1/* GLib testing framework examples and tests
2 *
3 * Copyright (C) 2008-2018 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: David Zeuthen <davidz@redhat.com>
19 */
20
21#include <gio/gio.h>
22#include <unistd.h>
23#include <string.h>
24#include <stdio.h>
25
26#include "glib/glib-private.h"
27
28#include "gdbus-tests.h"
29
30#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
31#include "gdbus-test-codegen-generated-min-required-2-64.h"
32#else
33#include "gdbus-test-codegen-generated.h"
34#endif
35
36#include "gdbus-test-codegen-generated-interface-info.h"
37
38#if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_68
39# undef G_DBUS_METHOD_INVOCATION_HANDLED
40# define G_DBUS_METHOD_INVOCATION_HANDLED TRUE
41#endif
42
43/* ---------------------------------------------------------------------------------------------------- */
44
45static guint
46count_annotations (GDBusAnnotationInfo **annotations)
47{
48 guint ret;
49 ret = 0;
50 while (annotations != NULL && annotations[ret] != NULL)
51 ret++;
52 return ret;
53}
54
55/* checks that
56 *
57 * - non-internal annotations are written out correctly; and
58 * - injection via --annotation --key --value works
59 */
60static void
61test_annotations (void)
62{
63 GDBusInterfaceInfo *iface;
64 GDBusMethodInfo *method;
65 GDBusSignalInfo *signal;
66 GDBusPropertyInfo *property;
67
68 iface = foo_igen_bar_interface_info ();
69 g_assert (iface != NULL);
70
71 /* see meson.build for where these annotations are injected */
72 g_assert_cmpint (count_annotations (iface->annotations), ==, 1);
73 g_assert_cmpstr (g_dbus_annotation_info_lookup (iface->annotations, "Key1"), ==, "Value1");
74
75 method = g_dbus_interface_info_lookup_method (info: iface, name: "HelloWorld");
76 g_assert (method != NULL);
77 g_assert_cmpint (count_annotations (method->annotations), ==, 2);
78 g_assert_cmpstr (g_dbus_annotation_info_lookup (method->annotations, "ExistingAnnotation"), ==, "blah");
79 g_assert_cmpstr (g_dbus_annotation_info_lookup (method->annotations, "Key3"), ==, "Value3");
80
81 signal = g_dbus_interface_info_lookup_signal (info: iface, name: "TestSignal");
82 g_assert (signal != NULL);
83 g_assert_cmpint (count_annotations (signal->annotations), ==, 1);
84 g_assert_cmpstr (g_dbus_annotation_info_lookup (signal->annotations, "Key4"), ==, "Value4");
85 g_assert_cmpstr (g_dbus_annotation_info_lookup (signal->args[1]->annotations, "Key8"), ==, "Value8");
86
87 property = g_dbus_interface_info_lookup_property (info: iface, name: "ay");
88 g_assert (property != NULL);
89 g_assert_cmpint (count_annotations (property->annotations), ==, 1);
90 g_assert_cmpstr (g_dbus_annotation_info_lookup (property->annotations, "Key5"), ==, "Value5");
91
92 method = g_dbus_interface_info_lookup_method (info: iface, name: "TestPrimitiveTypes");
93 g_assert (method != NULL);
94 g_assert_cmpstr (g_dbus_annotation_info_lookup (method->in_args[4]->annotations, "Key6"), ==, "Value6");
95 g_assert_cmpstr (g_dbus_annotation_info_lookup (method->out_args[5]->annotations, "Key7"), ==, "Value7");
96}
97
98/* ---------------------------------------------------------------------------------------------------- */
99
100static gboolean
101on_handle_hello_world (FooiGenBar *object,
102 GDBusMethodInvocation *invocation,
103 const gchar *greeting,
104 gpointer user_data)
105{
106 gchar *response;
107 response = g_strdup_printf (format: "Word! You said '%s'. I'm Skeleton, btw!", greeting);
108 foo_igen_bar_complete_hello_world (object, invocation, response);
109 g_free (mem: response);
110 return G_DBUS_METHOD_INVOCATION_HANDLED;
111}
112
113static gboolean
114on_handle_test_primitive_types (FooiGenBar *object,
115 GDBusMethodInvocation *invocation,
116 guchar val_byte,
117 gboolean val_boolean,
118 gint16 val_int16,
119 guint16 val_uint16,
120 gint val_int32,
121 guint val_uint32,
122 gint64 val_int64,
123 guint64 val_uint64,
124 gdouble val_double,
125 const gchar *val_string,
126 const gchar *val_objpath,
127 const gchar *val_signature,
128 const gchar *val_bytestring,
129 gpointer user_data)
130{
131 gchar *s1;
132 gchar *s2;
133 gchar *s3;
134 s1 = g_strdup_printf (format: "Word! You said '%s'. Rock'n'roll!", val_string);
135 s2 = g_strdup_printf (format: "/modified%s", val_objpath);
136 s3 = g_strdup_printf (format: "assgit%s", val_signature);
137 foo_igen_bar_complete_test_primitive_types (object,
138 invocation,
139 10 + val_byte,
140 !val_boolean,
141 100 + val_int16,
142 1000 + val_uint16,
143 10000 + val_int32,
144 100000 + val_uint32,
145 1000000 + val_int64,
146 10000000 + val_uint64,
147 val_double / G_PI,
148 s1,
149 s2,
150 s3,
151 "bytestring!\xff");
152 g_free (mem: s1);
153 g_free (mem: s2);
154 g_free (mem: s3);
155 return G_DBUS_METHOD_INVOCATION_HANDLED;
156}
157
158static gboolean
159on_handle_test_non_primitive_types (FooiGenBar *object,
160 GDBusMethodInvocation *invocation,
161 GVariant *dict_s_to_s,
162 GVariant *dict_s_to_pairs,
163 GVariant *a_struct,
164 const gchar* const *array_of_strings,
165 const gchar* const *array_of_objpaths,
166 GVariant *array_of_signatures,
167 const gchar* const *array_of_bytestrings,
168 gpointer user_data)
169{
170 gchar *s;
171 GString *str;
172 str = g_string_new (NULL);
173 s = g_variant_print (value: dict_s_to_s, TRUE); g_string_append (string: str, val: s); g_free (mem: s);
174 s = g_variant_print (value: dict_s_to_pairs, TRUE); g_string_append (string: str, val: s); g_free (mem: s);
175 s = g_variant_print (value: a_struct, TRUE); g_string_append (string: str, val: s); g_free (mem: s);
176 s = g_strjoinv (separator: ", ", str_array: (gchar **) array_of_strings);
177 g_string_append_printf (string: str, format: "array_of_strings: [%s] ", s);
178 g_free (mem: s);
179 s = g_strjoinv (separator: ", ", str_array: (gchar **) array_of_objpaths);
180 g_string_append_printf (string: str, format: "array_of_objpaths: [%s] ", s);
181 g_free (mem: s);
182 s = g_variant_print (value: array_of_signatures, TRUE);
183 g_string_append_printf (string: str, format: "array_of_signatures: %s ", s);
184 g_free (mem: s);
185 s = g_strjoinv (separator: ", ", str_array: (gchar **) array_of_bytestrings);
186 g_string_append_printf (string: str, format: "array_of_bytestrings: [%s] ", s);
187 g_free (mem: s);
188 foo_igen_bar_complete_test_non_primitive_types (object, invocation,
189 array_of_strings,
190 array_of_objpaths,
191 array_of_signatures,
192 array_of_bytestrings,
193 str->str);
194 g_string_free (string: str, TRUE);
195 return G_DBUS_METHOD_INVOCATION_HANDLED;
196}
197
198static gboolean
199on_handle_request_signal_emission (FooiGenBar *object,
200 GDBusMethodInvocation *invocation,
201 gint which_one,
202 gpointer user_data)
203{
204 if (which_one == 0)
205 {
206 const gchar *a_strv[] = {"foo", "bar", NULL};
207 const gchar *a_bytestring_array[] = {"foo\xff", "bar\xff", NULL};
208 GVariant *a_variant = g_variant_new_parsed (format: "{'first': (42, 42), 'second': (43, 43)}");
209 foo_igen_bar_emit_test_signal (object, 43, a_strv, a_bytestring_array, a_variant); /* consumes a_variant */
210 foo_igen_bar_complete_request_signal_emission (object, invocation);
211 }
212 return G_DBUS_METHOD_INVOCATION_HANDLED;
213}
214
215static gboolean
216on_handle_request_multi_property_mods (FooiGenBar *object,
217 GDBusMethodInvocation *invocation,
218 gpointer user_data)
219{
220 foo_igen_bar_set_y (object, foo_igen_bar_get_y (object) + 1);
221 foo_igen_bar_set_i (object, foo_igen_bar_get_i (object) + 1);
222 foo_igen_bar_set_y (object, foo_igen_bar_get_y (object) + 1);
223 foo_igen_bar_set_i (object, foo_igen_bar_get_i (object) + 1);
224 g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (object));
225 foo_igen_bar_set_y (object, foo_igen_bar_get_y (object) + 1);
226 foo_igen_bar_set_i (object, foo_igen_bar_get_i (object) + 1);
227 foo_igen_bar_complete_request_multi_property_mods (object, invocation);
228 return G_DBUS_METHOD_INVOCATION_HANDLED;
229}
230
231static gboolean
232on_handle_property_cancellation (FooiGenBar *object,
233 GDBusMethodInvocation *invocation,
234 gpointer user_data)
235{
236 guint n;
237 n = foo_igen_bar_get_n (object);
238 /* This queues up a PropertiesChange event */
239 foo_igen_bar_set_n (object, n + 1);
240 /* this modifies the queued up event */
241 foo_igen_bar_set_n (object, n);
242 /* this flushes all PropertiesChanges event (sends the D-Bus message right
243 * away, if any - there should not be any)
244 */
245 g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (object));
246 /* this makes us return the reply D-Bus method */
247 foo_igen_bar_complete_property_cancellation (object, invocation);
248 return G_DBUS_METHOD_INVOCATION_HANDLED;
249}
250
251/* ---------------------------------------------------------------------------------------------------- */
252
253static gboolean
254on_handle_force_method (FooiGenBat *object,
255 GDBusMethodInvocation *invocation,
256 GVariant *force_in_i,
257 GVariant *force_in_s,
258 GVariant *force_in_ay,
259 GVariant *force_in_struct,
260 gpointer user_data)
261{
262 GVariant *ret_i;
263 GVariant *ret_s;
264 GVariant *ret_ay;
265 GVariant *ret_struct;
266 gint32 val;
267 gchar *s;
268
269 ret_i = g_variant_new_int32 (value: g_variant_get_int32 (value: force_in_i) + 10);
270 s = g_strdup_printf (format: "%s_foo", g_variant_get_string (value: force_in_s, NULL));
271 ret_s = g_variant_new_string (string: s);
272 g_free (mem: s);
273 s = g_strdup_printf (format: "%s_foo\xff", g_variant_get_bytestring (value: force_in_ay));
274 ret_ay = g_variant_new_bytestring (string: s);
275 g_free (mem: s);
276
277 g_variant_get (value: force_in_struct, format_string: "(i)", &val);
278 ret_struct = g_variant_new (format_string: "(i)", val + 10);
279
280 g_variant_ref_sink (value: ret_i);
281 g_variant_ref_sink (value: ret_s);
282 g_variant_ref_sink (value: ret_ay);
283 g_variant_ref_sink (value: ret_struct);
284
285 foo_igen_bat_emit_force_signal (object,
286 ret_i,
287 ret_s,
288 ret_ay,
289 ret_struct);
290
291 foo_igen_bat_complete_force_method (object,
292 invocation,
293 ret_i,
294 ret_s,
295 ret_ay,
296 ret_struct);
297
298 g_variant_unref (value: ret_i);
299 g_variant_unref (value: ret_s);
300 g_variant_unref (value: ret_ay);
301 g_variant_unref (value: ret_struct);
302
303 return G_DBUS_METHOD_INVOCATION_HANDLED;
304}
305
306
307/* ---------------------------------------------------------------------------------------------------- */
308
309static gboolean
310my_g_authorize_method_handler (GDBusInterfaceSkeleton *interface,
311 GDBusMethodInvocation *invocation,
312 gpointer user_data)
313{
314 const gchar *method_name;
315 gboolean authorized;
316
317 authorized = FALSE;
318
319 method_name = g_dbus_method_invocation_get_method_name (invocation);
320 if (g_strcmp0 (str1: method_name, str2: "CheckNotAuthorized") == 0)
321 {
322 authorized = FALSE;
323 }
324 else if (g_strcmp0 (str1: method_name, str2: "CheckAuthorized") == 0)
325 {
326 authorized = TRUE;
327 }
328 else if (g_strcmp0 (str1: method_name, str2: "CheckNotAuthorizedFromObject") == 0)
329 {
330 authorized = TRUE;
331 }
332 else
333 {
334 g_assert_not_reached ();
335 }
336
337 if (!authorized)
338 {
339 g_dbus_method_invocation_return_error (invocation,
340 G_IO_ERROR,
341 code: G_IO_ERROR_PERMISSION_DENIED,
342 format: "not authorized...");
343 }
344 return authorized;
345}
346
347static gboolean
348my_object_authorize_method_handler (GDBusObjectSkeleton *object,
349 GDBusInterfaceSkeleton *interface,
350 GDBusMethodInvocation *invocation,
351 gpointer user_data)
352{
353 const gchar *method_name;
354 gboolean authorized;
355
356 authorized = FALSE;
357
358 method_name = g_dbus_method_invocation_get_method_name (invocation);
359 if (g_strcmp0 (str1: method_name, str2: "CheckNotAuthorized") == 0)
360 {
361 authorized = TRUE;
362 }
363 else if (g_strcmp0 (str1: method_name, str2: "CheckAuthorized") == 0)
364 {
365 authorized = TRUE;
366 }
367 else if (g_strcmp0 (str1: method_name, str2: "CheckNotAuthorizedFromObject") == 0)
368 {
369 authorized = FALSE;
370 }
371 else
372 {
373 g_assert_not_reached ();
374 }
375
376 if (!authorized)
377 {
378 g_dbus_method_invocation_return_error (invocation,
379 G_IO_ERROR,
380 code: G_IO_ERROR_PENDING,
381 format: "not authorized (from object)...");
382 }
383 return authorized;
384}
385
386static gboolean
387on_handle_check_not_authorized (FooiGenAuthorize *object,
388 GDBusMethodInvocation *invocation,
389 gpointer user_data)
390{
391 foo_igen_authorize_complete_check_not_authorized (object, invocation);
392 return G_DBUS_METHOD_INVOCATION_HANDLED;
393}
394
395static gboolean
396on_handle_check_authorized (FooiGenAuthorize *object,
397 GDBusMethodInvocation *invocation,
398 gpointer user_data)
399{
400 foo_igen_authorize_complete_check_authorized (object, invocation);
401 return G_DBUS_METHOD_INVOCATION_HANDLED;
402}
403
404static gboolean
405on_handle_check_not_authorized_from_object (FooiGenAuthorize *object,
406 GDBusMethodInvocation *invocation,
407 gpointer user_data)
408{
409 foo_igen_authorize_complete_check_not_authorized_from_object (object, invocation);
410 return G_DBUS_METHOD_INVOCATION_HANDLED;
411}
412
413/* ---------------------------------------------------------------------------------------------------- */
414
415static gboolean
416on_handle_get_self (FooiGenMethodThreads *object,
417 GDBusMethodInvocation *invocation,
418 gpointer user_data)
419{
420 gchar *s;
421 s = g_strdup_printf (format: "%p", (void *)g_thread_self ());
422 foo_igen_method_threads_complete_get_self (object, invocation, s);
423 g_free (mem: s);
424 return G_DBUS_METHOD_INVOCATION_HANDLED;
425}
426
427/* ---------------------------------------------------------------------------------------------------- */
428
429static GThread *method_handler_thread = NULL;
430
431static FooiGenBar *exported_bar_object = NULL;
432static FooiGenBat *exported_bat_object = NULL;
433static FooiGenAuthorize *exported_authorize_object = NULL;
434static GDBusObjectSkeleton *authorize_enclosing_object = NULL;
435static FooiGenMethodThreads *exported_thread_object_1 = NULL;
436static FooiGenMethodThreads *exported_thread_object_2 = NULL;
437
438static void
439unexport_objects (void)
440{
441 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_bar_object));
442 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_bat_object));
443 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_authorize_object));
444 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1));
445 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_thread_object_2));
446}
447
448static void
449on_bus_acquired (GDBusConnection *connection,
450 const gchar *name,
451 gpointer user_data)
452{
453 GError *error;
454
455 /* Test that we can export an object using the generated
456 * FooiGenBarSkeleton subclass. Notes:
457 *
458 * 1. We handle methods by simply connecting to the appropriate
459 * GObject signal.
460 *
461 * 2. Property storage is taken care of by the class; we can
462 * use g_object_get()/g_object_set() (and the generated
463 * C bindings at will)
464 */
465 error = NULL;
466 exported_bar_object = foo_igen_bar_skeleton_new ();
467 foo_igen_bar_set_ay (exported_bar_object, "ABCabc");
468 foo_igen_bar_set_y (exported_bar_object, 42);
469 foo_igen_bar_set_d (exported_bar_object, 43.0);
470 foo_igen_bar_set_finally_normal_name (exported_bar_object, "There aint no place like home");
471 foo_igen_bar_set_writeonly_property (exported_bar_object, "Mr. Burns");
472
473 /* The following works because it's on the Skeleton object - it will
474 * fail (at run-time) on a Proxy (see on_proxy_appeared() below)
475 */
476 foo_igen_bar_set_readonly_property (exported_bar_object, "blah");
477 g_assert_cmpstr (foo_igen_bar_get_writeonly_property (exported_bar_object), ==, "Mr. Burns");
478
479 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_bar_object),
480 connection,
481 object_path: "/bar",
482 error: &error);
483 g_assert_no_error (error);
484 g_signal_connect (exported_bar_object,
485 "handle-hello-world",
486 G_CALLBACK (on_handle_hello_world),
487 NULL);
488 g_signal_connect (exported_bar_object,
489 "handle-test-primitive-types",
490 G_CALLBACK (on_handle_test_primitive_types),
491 NULL);
492 g_signal_connect (exported_bar_object,
493 "handle-test-non-primitive-types",
494 G_CALLBACK (on_handle_test_non_primitive_types),
495 NULL);
496 g_signal_connect (exported_bar_object,
497 "handle-request-signal-emission",
498 G_CALLBACK (on_handle_request_signal_emission),
499 NULL);
500 g_signal_connect (exported_bar_object,
501 "handle-request-multi-property-mods",
502 G_CALLBACK (on_handle_request_multi_property_mods),
503 NULL);
504 g_signal_connect (exported_bar_object,
505 "handle-property-cancellation",
506 G_CALLBACK (on_handle_property_cancellation),
507 NULL);
508
509 exported_bat_object = foo_igen_bat_skeleton_new ();
510 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_bat_object),
511 connection,
512 object_path: "/bat",
513 error: &error);
514 g_assert_no_error (error);
515 g_signal_connect (exported_bat_object,
516 "handle-force-method",
517 G_CALLBACK (on_handle_force_method),
518 NULL);
519 g_object_set (object: exported_bat_object,
520 first_property_name: "force-i", g_variant_new_int32 (value: 43),
521 "force-s", g_variant_new_string (string: "prop string"),
522 "force-ay", g_variant_new_bytestring (string: "prop bytestring\xff"),
523 "force-struct", g_variant_new (format_string: "(i)", 4300),
524 NULL);
525
526 authorize_enclosing_object = g_dbus_object_skeleton_new (object_path: "/authorize");
527 g_signal_connect (authorize_enclosing_object,
528 "authorize-method",
529 G_CALLBACK (my_object_authorize_method_handler),
530 NULL);
531 exported_authorize_object = foo_igen_authorize_skeleton_new ();
532 g_dbus_object_skeleton_add_interface (object: authorize_enclosing_object,
533 G_DBUS_INTERFACE_SKELETON (exported_authorize_object));
534 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_authorize_object),
535 connection,
536 object_path: "/authorize",
537 error: &error);
538 g_assert_no_error (error);
539 g_signal_connect (exported_authorize_object,
540 "g-authorize-method",
541 G_CALLBACK (my_g_authorize_method_handler),
542 NULL);
543 g_signal_connect (exported_authorize_object,
544 "handle-check-not-authorized",
545 G_CALLBACK (on_handle_check_not_authorized),
546 NULL);
547 g_signal_connect (exported_authorize_object,
548 "handle-check-authorized",
549 G_CALLBACK (on_handle_check_authorized),
550 NULL);
551 g_signal_connect (exported_authorize_object,
552 "handle-check-not-authorized-from-object",
553 G_CALLBACK (on_handle_check_not_authorized_from_object),
554 NULL);
555
556
557 /* only object 1 has the G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD flag set */
558 exported_thread_object_1 = foo_igen_method_threads_skeleton_new ();
559 g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1),
560 flags: G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
561
562 g_assert (!g_dbus_interface_skeleton_has_connection (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1), connection));
563 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1),
564 connection,
565 object_path: "/method_threads_1",
566 error: &error);
567 g_assert_no_error (error);
568 g_signal_connect (exported_thread_object_1,
569 "handle-get-self",
570 G_CALLBACK (on_handle_get_self),
571 NULL);
572 g_assert_cmpint (g_dbus_interface_skeleton_get_flags (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1)), ==, G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
573
574 exported_thread_object_2 = foo_igen_method_threads_skeleton_new ();
575 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_thread_object_2),
576 connection,
577 object_path: "/method_threads_2",
578 error: &error);
579 g_assert_no_error (error);
580 g_signal_connect (exported_thread_object_2,
581 "handle-get-self",
582 G_CALLBACK (on_handle_get_self),
583 NULL);
584
585 g_assert_cmpint (g_dbus_interface_skeleton_get_flags (G_DBUS_INTERFACE_SKELETON (exported_thread_object_2)), ==, G_DBUS_INTERFACE_SKELETON_FLAGS_NONE);
586
587 method_handler_thread = g_thread_self ();
588}
589
590static gpointer check_proxies_in_thread (gpointer user_data);
591
592static void
593on_name_acquired (GDBusConnection *connection,
594 const gchar *name,
595 gpointer user_data)
596{
597 GMainLoop *loop = user_data;
598 GThread *thread = g_thread_new (name: "check-proxies", func: check_proxies_in_thread, data: loop);
599 g_thread_unref (thread);
600}
601
602static void
603on_name_lost (GDBusConnection *connection,
604 const gchar *name,
605 gpointer user_data)
606{
607 g_assert_not_reached ();
608}
609
610/* ---------------------------------------------------------------------------------------------------- */
611
612typedef struct
613{
614 GMainLoop *thread_loop;
615 gint initial_y;
616 gint initial_i;
617 guint num_g_properties_changed;
618 gboolean received_test_signal;
619 guint num_notify_u;
620 guint num_notify_n;
621} ClientData;
622
623static void
624on_notify_u (GObject *object,
625 GParamSpec *pspec,
626 gpointer user_data)
627{
628 ClientData *data = user_data;
629 g_assert_cmpstr (pspec->name, ==, "u");
630 data->num_notify_u += 1;
631}
632
633static void
634on_notify_n (GObject *object,
635 GParamSpec *pspec,
636 gpointer user_data)
637{
638 ClientData *data = user_data;
639 g_assert_cmpstr (pspec->name, ==, "n");
640 data->num_notify_n += 1;
641}
642
643static void
644on_g_properties_changed (GDBusProxy *_proxy,
645 GVariant *changed_properties,
646 const gchar* const *invalidated_properties,
647 gpointer user_data)
648{
649 ClientData *data = user_data;
650 FooiGenBar *proxy = FOO_IGEN_BAR (_proxy);
651
652 g_assert_cmpint (g_variant_n_children (changed_properties), ==, 2);
653
654 if (data->num_g_properties_changed == 0)
655 {
656 g_assert_cmpint (data->initial_y, ==, foo_igen_bar_get_y (proxy) - 2);
657 g_assert_cmpint (data->initial_i, ==, foo_igen_bar_get_i (proxy) - 2);
658 }
659 else if (data->num_g_properties_changed == 1)
660 {
661 g_assert_cmpint (data->initial_y, ==, foo_igen_bar_get_y (proxy) - 3);
662 g_assert_cmpint (data->initial_i, ==, foo_igen_bar_get_i (proxy) - 3);
663 }
664 else
665 g_assert_not_reached ();
666
667 data->num_g_properties_changed++;
668
669 if (data->num_g_properties_changed == 2)
670 g_main_loop_quit (loop: data->thread_loop);
671}
672
673static void
674on_test_signal (FooiGenBar *proxy,
675 gint val_int32,
676 const gchar* const *array_of_strings,
677 const gchar* const *array_of_bytestrings,
678 GVariant *dict_s_to_pairs,
679 gpointer user_data)
680{
681 ClientData *data = user_data;
682
683 g_assert_cmpint (val_int32, ==, 43);
684 g_assert_cmpstr (array_of_strings[0], ==, "foo");
685 g_assert_cmpstr (array_of_strings[1], ==, "bar");
686 g_assert (array_of_strings[2] == NULL);
687 g_assert_cmpstr (array_of_bytestrings[0], ==, "foo\xff");
688 g_assert_cmpstr (array_of_bytestrings[1], ==, "bar\xff");
689 g_assert (array_of_bytestrings[2] == NULL);
690
691 data->received_test_signal = TRUE;
692 g_main_loop_quit (loop: data->thread_loop);
693}
694
695static void
696on_property_cancellation_cb (FooiGenBar *proxy,
697 GAsyncResult *res,
698 gpointer user_data)
699{
700 ClientData *data = user_data;
701 gboolean ret;
702 GError *error = NULL;
703
704 error = NULL;
705 ret = foo_igen_bar_call_property_cancellation_finish (proxy, res, &error);
706 g_assert_no_error (error);
707 g_assert (ret);
708
709 g_main_loop_quit (loop: data->thread_loop);
710}
711
712static void
713check_bar_proxy (FooiGenBar *proxy,
714 GMainLoop *thread_loop)
715{
716 const gchar *array_of_strings[3] = {"one", "two", NULL};
717 const gchar *array_of_strings_2[3] = {"one2", "two2", NULL};
718 const gchar *array_of_objpaths[3] = {"/one", "/one/two", NULL};
719 GVariant *array_of_signatures = NULL;
720 const gchar *array_of_bytestrings[3] = {"one\xff", "two\xff", NULL};
721 gchar **ret_array_of_strings = NULL;
722 gchar **ret_array_of_objpaths = NULL;
723 GVariant *ret_array_of_signatures = NULL;
724 gchar **ret_array_of_bytestrings = NULL;
725 guchar ret_val_byte;
726 gboolean ret_val_boolean;
727 gint16 ret_val_int16;
728 guint16 ret_val_uint16;
729 gint ret_val_int32;
730 guint ret_val_uint32;
731 gint64 ret_val_int64;
732 guint64 ret_val_uint64;
733 gdouble ret_val_double;
734 gchar *ret_val_string;
735 gchar *ret_val_objpath;
736 gchar *ret_val_signature;
737 gchar *ret_val_bytestring;
738 gboolean ret;
739 GError *error;
740 ClientData *data;
741 guchar val_y;
742 gboolean val_b;
743 gint val_n;
744 guint val_q;
745 gint val_i;
746 guint val_u;
747 gint64 val_x;
748 guint64 val_t;
749 gdouble val_d;
750 gchar *val_s;
751 gchar *val_o;
752 gchar *val_g;
753 gchar *val_ay;
754 gchar **val_as;
755 gchar **val_ao;
756 GVariant *val_ag;
757 gint32 val_unset_i;
758 gdouble val_unset_d;
759 gchar *val_unset_s;
760 gchar *val_unset_o;
761 gchar *val_unset_g;
762 gchar *val_unset_ay;
763 gchar **val_unset_as;
764 gchar **val_unset_ao;
765 GVariant *val_unset_ag;
766 GVariant *val_unset_struct;
767 gchar *val_finally_normal_name;
768 GVariant *v;
769 gchar *s;
770 const gchar *const *read_as;
771 const gchar *const *read_as2;
772 const gchar *const *read_as3;
773
774 data = g_new0 (ClientData, 1);
775 data->thread_loop = thread_loop;
776
777 v = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), property_name: "y");
778 g_assert (v != NULL);
779 g_variant_unref (value: v);
780
781 /* set empty values to non-empty */
782 val_unset_i = 42;
783 val_unset_d = 42.0;
784 val_unset_s = "42";
785 val_unset_o = "42";
786 val_unset_g = "42";
787 val_unset_ay = NULL;
788 val_unset_as = NULL;
789 val_unset_ao = NULL;
790 val_unset_ag = NULL;
791 val_unset_struct = NULL;
792 /* check properties */
793 g_object_get (object: proxy,
794 first_property_name: "y", &val_y,
795 "b", &val_b,
796 "n", &val_n,
797 "q", &val_q,
798 "i", &val_i,
799 "u", &val_u,
800 "x", &val_x,
801 "t", &val_t,
802 "d", &val_d,
803 "s", &val_s,
804 "o", &val_o,
805 "g", &val_g,
806 "ay", &val_ay,
807 "as", &val_as,
808 "ao", &val_ao,
809 "ag", &val_ag,
810 "unset_i", &val_unset_i,
811 "unset_d", &val_unset_d,
812 "unset_s", &val_unset_s,
813 "unset_o", &val_unset_o,
814 "unset_g", &val_unset_g,
815 "unset_ay", &val_unset_ay,
816 "unset_as", &val_unset_as,
817 "unset_ao", &val_unset_ao,
818 "unset_ag", &val_unset_ag,
819 "unset_struct", &val_unset_struct,
820 "finally-normal-name", &val_finally_normal_name,
821 NULL);
822 g_assert_cmpint (val_y, ==, 42);
823 g_assert_cmpstr (val_finally_normal_name, ==, "There aint no place like home");
824 g_free (mem: val_s);
825 g_free (mem: val_o);
826 g_free (mem: val_g);
827 g_assert_cmpstr (val_ay, ==, "ABCabc");
828 g_free (mem: val_ay);
829 g_strfreev (str_array: val_as);
830 g_strfreev (str_array: val_ao);
831 g_variant_unref (value: val_ag);
832 g_free (mem: val_finally_normal_name);
833 /* check empty values */
834 g_assert_cmpint (val_unset_i, ==, 0);
835 g_assert_cmpfloat (val_unset_d, ==, 0.0);
836 g_assert_cmpstr (val_unset_s, ==, "");
837 g_assert_cmpstr (val_unset_o, ==, "/");
838 g_assert_cmpstr (val_unset_g, ==, "");
839 g_free (mem: val_unset_s);
840 g_free (mem: val_unset_o);
841 g_free (mem: val_unset_g);
842 g_assert_cmpstr (val_unset_ay, ==, "");
843 g_assert (val_unset_as[0] == NULL);
844 g_assert (val_unset_ao[0] == NULL);
845 g_assert (g_variant_is_of_type (val_unset_ag, G_VARIANT_TYPE ("ag")));
846 g_assert (g_variant_is_of_type (val_unset_struct, G_VARIANT_TYPE ("(idsogayasaoag)")));
847 s = g_variant_print (value: val_unset_struct, TRUE);
848 g_assert_cmpstr (s, ==, "(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])");
849 g_free (mem: s);
850 g_free (mem: val_unset_ay);
851 g_strfreev (str_array: val_unset_as);
852 g_strfreev (str_array: val_unset_ao);
853 g_variant_unref (value: val_unset_ag);
854 g_variant_unref (value: val_unset_struct);
855
856 /* Try setting a property. This causes the generated glue to invoke
857 * the org.fd.DBus.Properties.Set() method asynchronously. So we
858 * have to wait for properties-changed...
859 */
860 foo_igen_bar_set_finally_normal_name (proxy, "foo!");
861 _g_assert_property_notify (proxy, "finally-normal-name");
862 g_assert_cmpstr (foo_igen_bar_get_finally_normal_name (proxy), ==, "foo!");
863
864 /* Try setting properties that requires memory management. This
865 * is to exercise the paths that frees the references.
866 */
867
868 g_object_set (object: proxy,
869 first_property_name: "s", "a string",
870 "o", "/a/path",
871 "g", "asig",
872 "ay", g_variant_new_parsed (format: "[byte 0x65, 0x67]"),
873 "as", array_of_strings,
874 "ao", array_of_objpaths,
875 "ag", g_variant_new_parsed (format: "[@g 'ass', 'git']"),
876 NULL);
877
878 error = NULL;
879 ret = foo_igen_bar_call_test_primitive_types_sync (proxy,
880 10,
881 TRUE,
882 11,
883 12,
884 13,
885 14,
886 15,
887 16,
888 17,
889 "a string",
890 "/a/path",
891 "asig",
892 "bytestring\xff",
893#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
894 G_DBUS_CALL_FLAGS_NONE,
895 -1,
896#endif
897 &ret_val_byte,
898 &ret_val_boolean,
899 &ret_val_int16,
900 &ret_val_uint16,
901 &ret_val_int32,
902 &ret_val_uint32,
903 &ret_val_int64,
904 &ret_val_uint64,
905 &ret_val_double,
906 &ret_val_string,
907 &ret_val_objpath,
908 &ret_val_signature,
909 &ret_val_bytestring,
910 NULL, /* GCancellable */
911 &error);
912 g_assert_no_error (error);
913 g_assert (ret);
914
915 g_clear_pointer (&ret_val_string, g_free);
916 g_clear_pointer (&ret_val_objpath, g_free);
917 g_clear_pointer (&ret_val_signature, g_free);
918 g_clear_pointer (&ret_val_bytestring, g_free);
919
920 error = NULL;
921 array_of_signatures = g_variant_ref_sink (value: g_variant_new_parsed (format: "[@g 'ass', 'git']"));
922 ret = foo_igen_bar_call_test_non_primitive_types_sync (proxy,
923 g_variant_new_parsed (format: "{'one': 'red',"
924 " 'two': 'blue'}"),
925 g_variant_new_parsed (format: "{'first': (42, 42), "
926 "'second': (43, 43)}"),
927 g_variant_new_parsed (format: "(42, 'foo', 'bar')"),
928 array_of_strings,
929 array_of_objpaths,
930 array_of_signatures,
931 array_of_bytestrings,
932#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
933 G_DBUS_CALL_FLAGS_NONE,
934 -1,
935#endif
936 &ret_array_of_strings,
937 &ret_array_of_objpaths,
938 &ret_array_of_signatures,
939 &ret_array_of_bytestrings,
940 &s,
941 NULL, /* GCancellable */
942 &error);
943
944 g_assert_no_error (error);
945 g_assert (ret);
946
947 g_assert_nonnull (ret_array_of_strings);
948 g_assert_cmpuint (g_strv_length ((gchar **) ret_array_of_strings), ==,
949 g_strv_length ((gchar **) array_of_strings));
950 g_assert_nonnull (ret_array_of_objpaths);
951 g_assert_cmpuint (g_strv_length ((gchar **) ret_array_of_objpaths), ==,
952 g_strv_length ((gchar **) array_of_objpaths));
953 g_assert_nonnull (ret_array_of_signatures);
954 g_assert_cmpvariant (ret_array_of_signatures, array_of_signatures);
955 g_assert_nonnull (ret_array_of_bytestrings);
956 g_assert_cmpuint (g_strv_length ((gchar **) ret_array_of_bytestrings), ==,
957 g_strv_length ((gchar **) array_of_bytestrings));
958
959 g_clear_pointer (&ret_array_of_strings, g_strfreev);
960 g_clear_pointer (&ret_array_of_objpaths, g_strfreev);
961 g_clear_pointer (&ret_array_of_signatures, g_variant_unref);
962 g_clear_pointer (&ret_array_of_bytestrings, g_strfreev);
963 g_clear_pointer (&s, g_free);
964
965 /* Check that org.freedesktop.DBus.Error.UnknownMethod is returned on
966 * unimplemented methods.
967 */
968 error = NULL;
969#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
970 ret = foo_igen_bar_call_unimplemented_method_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL /* GCancellable */, &error);
971#else
972 ret = foo_igen_bar_call_unimplemented_method_sync (proxy, NULL /* GCancellable */, &error);
973#endif
974 g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
975 g_error_free (error);
976 error = NULL;
977 g_assert (!ret);
978
979 g_signal_connect (proxy,
980 "test-signal",
981 G_CALLBACK (on_test_signal),
982 data);
983 error = NULL;
984#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
985 ret = foo_igen_bar_call_request_signal_emission_sync (proxy, 0, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
986#else
987 ret = foo_igen_bar_call_request_signal_emission_sync (proxy, 0, NULL, &error);
988#endif
989 g_assert_no_error (error);
990 g_assert (ret);
991
992 g_assert (!data->received_test_signal);
993 g_main_loop_run (loop: thread_loop);
994 g_assert (data->received_test_signal);
995
996 /* Try setting a property. This causes the generated glue to invoke
997 * the org.fd.DBus.Properties.Set() method asynchronously. So we
998 * have to wait for properties-changed...
999 */
1000 foo_igen_bar_set_finally_normal_name (proxy, "hey back!");
1001 _g_assert_property_notify (proxy, "finally-normal-name");
1002 g_assert_cmpstr (foo_igen_bar_get_finally_normal_name (proxy), ==, "hey back!");
1003
1004 /* Check that multiple calls to a strv getter works... and that
1005 * updates on them works as well (See comment for "property vfuncs"
1006 * in gio/gdbus-codegen/codegen.py for details)
1007 */
1008 read_as = foo_igen_bar_get_as (proxy);
1009 read_as2 = foo_igen_bar_get_as (proxy);
1010 g_assert_cmpint (g_strv_length ((gchar **) read_as), ==, 2);
1011 g_assert_cmpstr (read_as[0], ==, "one");
1012 g_assert_cmpstr (read_as[1], ==, "two");
1013 g_assert (read_as == read_as2); /* this is more testing an implementation detail */
1014 g_object_set (object: proxy,
1015 first_property_name: "as", array_of_strings_2,
1016 NULL);
1017 _g_assert_property_notify (proxy, "as");
1018 read_as3 = foo_igen_bar_get_as (proxy);
1019 g_assert_cmpint (g_strv_length ((gchar **) read_as3), ==, 2);
1020 g_assert_cmpstr (read_as3[0], ==, "one2");
1021 g_assert_cmpstr (read_as3[1], ==, "two2");
1022
1023 /* Check that grouping changes in idle works.
1024 *
1025 * See on_handle_request_multi_property_mods(). The server should
1026 * emit exactly two PropertiesChanged signals each containing two
1027 * properties.
1028 *
1029 * On the first reception, y and i should both be increased by
1030 * two. On the second reception, only by one. The signal handler
1031 * checks this.
1032 *
1033 * This also checks that _drain_notify() works.
1034 */
1035 data->initial_y = foo_igen_bar_get_y (proxy);
1036 data->initial_i = foo_igen_bar_get_i (proxy);
1037 g_signal_connect (proxy,
1038 "g-properties-changed",
1039 G_CALLBACK (on_g_properties_changed),
1040 data);
1041 error = NULL;
1042#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
1043 ret = foo_igen_bar_call_request_multi_property_mods_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1044#else
1045 ret = foo_igen_bar_call_request_multi_property_mods_sync (proxy, NULL, &error);
1046#endif
1047 g_assert_no_error (error);
1048 g_assert (ret);
1049 g_main_loop_run (loop: thread_loop);
1050 g_assert_cmpint (data->num_g_properties_changed, ==, 2);
1051 g_signal_handlers_disconnect_by_func (proxy,
1052 G_CALLBACK (on_g_properties_changed),
1053 data);
1054
1055 /* Check that we don't emit PropertiesChanged() if the property
1056 * didn't change... we actually get two notifies.. one for the
1057 * local set (without a value change) and one when receiving
1058 * the PropertiesChanged() signal generated from the remote end.
1059 */
1060 g_assert_cmpint (data->num_notify_u, ==, 0);
1061 g_signal_connect (proxy,
1062 "notify::u",
1063 G_CALLBACK (on_notify_u),
1064 data);
1065 foo_igen_bar_set_u (proxy, 1042);
1066 g_assert_cmpint (data->num_notify_u, ==, 1);
1067 g_assert_cmpint (foo_igen_bar_get_u (proxy), ==, 0);
1068 _g_assert_property_notify (proxy, "u");
1069 g_assert_cmpint (foo_igen_bar_get_u (proxy), ==, 1042);
1070 g_assert_cmpint (data->num_notify_u, ==, 2);
1071
1072 /* Now change u again to the same value.. this will cause a
1073 * local notify:: notify and the usual Properties.Set() call
1074 *
1075 * (Btw, why also the Set() call if the value in the cache is
1076 * the same? Because someone else might have changed it
1077 * in the mean time and we're just waiting to receive the
1078 * PropertiesChanged() signal...)
1079 *
1080 * More tricky - how do we check for the *absence* of the
1081 * notification that u changed? Simple: we change another
1082 * property and wait for that PropertiesChanged() message
1083 * to arrive.
1084 */
1085 foo_igen_bar_set_u (proxy, 1042);
1086 g_assert_cmpint (data->num_notify_u, ==, 3);
1087
1088 g_assert_cmpint (data->num_notify_n, ==, 0);
1089 g_signal_connect (proxy,
1090 "notify::n",
1091 G_CALLBACK (on_notify_n),
1092 data);
1093 foo_igen_bar_set_n (proxy, 10042);
1094 g_assert_cmpint (data->num_notify_n, ==, 1);
1095 g_assert_cmpint (foo_igen_bar_get_n (proxy), ==, 0);
1096 _g_assert_property_notify (proxy, "n");
1097 g_assert_cmpint (foo_igen_bar_get_n (proxy), ==, 10042);
1098 g_assert_cmpint (data->num_notify_n, ==, 2);
1099 /* Checks that u didn't change at all */
1100 g_assert_cmpint (data->num_notify_u, ==, 3);
1101
1102 /* Now we check that if the service does
1103 *
1104 * guint n = foo_igen_bar_get_n (foo);
1105 * foo_igen_bar_set_n (foo, n + 1);
1106 * foo_igen_bar_set_n (foo, n);
1107 *
1108 * then no PropertiesChanged() signal is emitted!
1109 */
1110 error = NULL;
1111 foo_igen_bar_call_property_cancellation (proxy,
1112#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
1113 G_DBUS_CALL_FLAGS_NONE,
1114 -1,
1115#endif
1116 NULL, /* GCancellable */
1117 (GAsyncReadyCallback) on_property_cancellation_cb,
1118 data);
1119 g_main_loop_run (loop: thread_loop);
1120 /* Checks that n didn't change at all */
1121 g_assert_cmpint (data->num_notify_n, ==, 2);
1122
1123 /* cleanup */
1124 g_free (mem: data);
1125 g_variant_unref (value: array_of_signatures);
1126}
1127
1128/* ---------------------------------------------------------------------------------------------------- */
1129
1130static void
1131on_force_signal (FooiGenBat *proxy,
1132 GVariant *force_i,
1133 GVariant *force_s,
1134 GVariant *force_ay,
1135 GVariant *force_struct,
1136 gpointer user_data)
1137{
1138 gboolean *signal_received = user_data;
1139 gint val;
1140
1141 g_assert (!(*signal_received));
1142
1143 g_assert_cmpint (g_variant_get_int32 (force_i), ==, 42 + 10);
1144 g_assert_cmpstr (g_variant_get_string (force_s, NULL), ==, "a string_foo");
1145 g_assert_cmpstr (g_variant_get_bytestring (force_ay), ==, "a bytestring\xff_foo\xff");
1146 g_variant_get (value: force_struct, format_string: "(i)", &val);
1147 g_assert_cmpint (val, ==, 4200 + 10);
1148
1149 *signal_received = TRUE;
1150}
1151
1152static void
1153check_bat_proxy (FooiGenBat *proxy,
1154 GMainLoop *thread_loop)
1155{
1156 GError *error;
1157 GVariant *ret_i;
1158 GVariant *ret_s;
1159 GVariant *ret_ay;
1160 GVariant *ret_struct;
1161 gint val;
1162 gboolean force_signal_received;
1163
1164 /* --------------------------------------------------- */
1165 /* Check type-mapping where we force use of a GVariant */
1166 /* --------------------------------------------------- */
1167
1168 /* check properties */
1169 g_object_get (object: proxy,
1170 first_property_name: "force-i", &ret_i,
1171 "force-s", &ret_s,
1172 "force-ay", &ret_ay,
1173 "force-struct", &ret_struct,
1174 NULL);
1175 g_assert_cmpint (g_variant_get_int32 (ret_i), ==, 43);
1176 g_assert_cmpstr (g_variant_get_string (ret_s, NULL), ==, "prop string");
1177 g_assert_cmpstr (g_variant_get_bytestring (ret_ay), ==, "prop bytestring\xff");
1178 g_variant_get (value: ret_struct, format_string: "(i)", &val);
1179 g_assert_cmpint (val, ==, 4300);
1180 g_variant_unref (value: ret_i);
1181 g_variant_unref (value: ret_s);
1182 g_variant_unref (value: ret_ay);
1183 g_variant_unref (value: ret_struct);
1184
1185 /* check method and signal */
1186 force_signal_received = FALSE;
1187 g_signal_connect (proxy,
1188 "force-signal",
1189 G_CALLBACK (on_force_signal),
1190 &force_signal_received);
1191
1192 error = NULL;
1193 foo_igen_bat_call_force_method_sync (proxy,
1194 g_variant_new_int32 (value: 42),
1195 g_variant_new_string (string: "a string"),
1196 g_variant_new_bytestring (string: "a bytestring\xff"),
1197 g_variant_new (format_string: "(i)", 4200),
1198#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
1199 G_DBUS_CALL_FLAGS_NONE,
1200 -1,
1201#endif
1202 &ret_i,
1203 &ret_s,
1204 &ret_ay,
1205 &ret_struct,
1206 NULL, /* GCancellable* */
1207 &error);
1208 g_assert_no_error (error);
1209 g_assert_cmpint (g_variant_get_int32 (ret_i), ==, 42 + 10);
1210 g_assert_cmpstr (g_variant_get_string (ret_s, NULL), ==, "a string_foo");
1211 g_assert_cmpstr (g_variant_get_bytestring (ret_ay), ==, "a bytestring\xff_foo\xff");
1212 g_variant_get (value: ret_struct, format_string: "(i)", &val);
1213 g_assert_cmpint (val, ==, 4200 + 10);
1214 g_variant_unref (value: ret_i);
1215 g_variant_unref (value: ret_s);
1216 g_variant_unref (value: ret_ay);
1217 g_variant_unref (value: ret_struct);
1218 _g_assert_signal_received (proxy, "force-signal");
1219 g_assert (force_signal_received);
1220}
1221
1222/* ---------------------------------------------------------------------------------------------------- */
1223
1224static void
1225check_authorize_proxy (FooiGenAuthorize *proxy,
1226 GMainLoop *thread_loop)
1227{
1228 GError *error;
1229 gboolean ret;
1230
1231 /* Check that g-authorize-method works as intended */
1232
1233 error = NULL;
1234#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
1235 ret = foo_igen_authorize_call_check_not_authorized_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1236#else
1237 ret = foo_igen_authorize_call_check_not_authorized_sync (proxy, NULL, &error);
1238#endif
1239 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
1240 g_error_free (error);
1241 g_assert (!ret);
1242
1243 error = NULL;
1244#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
1245 ret = foo_igen_authorize_call_check_authorized_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1246#else
1247 ret = foo_igen_authorize_call_check_authorized_sync (proxy, NULL, &error);
1248#endif
1249 g_assert_no_error (error);
1250 g_assert (ret);
1251
1252 error = NULL;
1253#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
1254 ret = foo_igen_authorize_call_check_not_authorized_from_object_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1255#else
1256 ret = foo_igen_authorize_call_check_not_authorized_from_object_sync (proxy, NULL, &error);
1257#endif
1258 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
1259 g_error_free (error);
1260 g_assert (!ret);
1261}
1262
1263/* ---------------------------------------------------------------------------------------------------- */
1264
1265static GThread *
1266get_self_via_proxy (FooiGenMethodThreads *proxy_1)
1267{
1268 GError *error;
1269 gchar *self_str;
1270 gboolean ret;
1271 gpointer self;
1272
1273 error = NULL;
1274#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
1275 ret = foo_igen_method_threads_call_get_self_sync (proxy_1, G_DBUS_CALL_FLAGS_NONE, -1, &self_str, NULL, &error);
1276#else
1277 ret = foo_igen_method_threads_call_get_self_sync (proxy_1, &self_str, NULL, &error);
1278#endif
1279 g_assert_no_error (error);
1280 g_assert (ret);
1281
1282 g_assert_cmpint (sscanf (self_str, "%p", &self), ==, 1);
1283
1284 g_free (mem: self_str);
1285
1286 return self;
1287}
1288
1289static void
1290check_thread_proxies (FooiGenMethodThreads *proxy_1,
1291 FooiGenMethodThreads *proxy_2,
1292 GMainLoop *thread_loop)
1293{
1294 /* proxy_1 is indeed using threads so should never get the handler thread */
1295 g_assert (get_self_via_proxy (proxy_1) != method_handler_thread);
1296
1297 /* proxy_2 is not using threads so should get the handler thread */
1298 g_assert (get_self_via_proxy (proxy_2) == method_handler_thread);
1299}
1300
1301/* ---------------------------------------------------------------------------------------------------- */
1302
1303static gpointer
1304check_proxies_in_thread (gpointer user_data)
1305{
1306 GMainLoop *loop = user_data;
1307#ifdef _GLIB_ADDRESS_SANITIZER
1308
1309 /* Silence "Not available before 2.38" when using old API */
1310 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1311 g_test_incomplete ("FIXME: Leaks a GWeakRef, see glib#2312");
1312 G_GNUC_END_IGNORE_DEPRECATIONS
1313
1314 (void) check_thread_proxies;
1315 (void) check_authorize_proxy;
1316 (void) check_bat_proxy;
1317 (void) check_bar_proxy;
1318#else
1319 GMainContext *thread_context;
1320 GMainLoop *thread_loop;
1321 GError *error;
1322 FooiGenBar *bar_proxy;
1323 FooiGenBat *bat_proxy;
1324 FooiGenAuthorize *authorize_proxy;
1325 FooiGenMethodThreads *thread_proxy_1;
1326 FooiGenMethodThreads *thread_proxy_2;
1327
1328 thread_context = g_main_context_new ();
1329 thread_loop = g_main_loop_new (context: thread_context, FALSE);
1330 g_main_context_push_thread_default (context: thread_context);
1331
1332 /* Check the object */
1333 error = NULL;
1334 bar_proxy = foo_igen_bar_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1335 G_DBUS_PROXY_FLAGS_NONE,
1336 "org.gtk.GDBus.BindingsTool.Test",
1337 "/bar",
1338 NULL, /* GCancellable* */
1339 &error);
1340 check_bar_proxy (bar_proxy, thread_loop);
1341 g_assert_no_error (error);
1342 g_object_unref (bar_proxy);
1343
1344 error = NULL;
1345 bat_proxy = foo_igen_bat_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1346 G_DBUS_PROXY_FLAGS_NONE,
1347 "org.gtk.GDBus.BindingsTool.Test",
1348 "/bat",
1349 NULL, /* GCancellable* */
1350 &error);
1351 check_bat_proxy (bat_proxy, thread_loop);
1352 g_assert_no_error (error);
1353 g_object_unref (bat_proxy);
1354
1355 error = NULL;
1356 authorize_proxy = foo_igen_authorize_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1357 G_DBUS_PROXY_FLAGS_NONE,
1358 "org.gtk.GDBus.BindingsTool.Test",
1359 "/authorize",
1360 NULL, /* GCancellable* */
1361 &error);
1362 check_authorize_proxy (authorize_proxy, thread_loop);
1363 g_assert_no_error (error);
1364 g_object_unref (authorize_proxy);
1365
1366 error = NULL;
1367 thread_proxy_1 = foo_igen_method_threads_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1368 G_DBUS_PROXY_FLAGS_NONE,
1369 "org.gtk.GDBus.BindingsTool.Test",
1370 "/method_threads_1",
1371 NULL, /* GCancellable* */
1372 &error);
1373 g_assert_no_error (error);
1374 thread_proxy_2 = foo_igen_method_threads_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1375 G_DBUS_PROXY_FLAGS_NONE,
1376 "org.gtk.GDBus.BindingsTool.Test",
1377 "/method_threads_2",
1378 NULL, /* GCancellable* */
1379 &error);
1380 g_assert_no_error (error);
1381 check_thread_proxies (thread_proxy_1, thread_proxy_2, thread_loop);
1382 g_object_unref (thread_proxy_1);
1383 g_object_unref (thread_proxy_2);
1384
1385 g_main_loop_unref (loop: thread_loop);
1386 g_main_context_unref (context: thread_context);
1387#endif
1388
1389 /* this breaks out of the loop in main() (below) */
1390 g_main_loop_quit (loop);
1391 return NULL;
1392}
1393
1394/* ---------------------------------------------------------------------------------------------------- */
1395
1396typedef struct
1397{
1398 gchar *xml;
1399 GMainLoop *loop;
1400} IntrospectData;
1401
1402static void
1403introspect_cb (GDBusConnection *connection,
1404 GAsyncResult *res,
1405 gpointer user_data)
1406{
1407 IntrospectData *data = user_data;
1408 GVariant *result;
1409 GError *error;
1410
1411 error = NULL;
1412 result = g_dbus_connection_call_finish (connection,
1413 res,
1414 error: &error);
1415 g_assert_no_error (error);
1416 g_assert (result != NULL);
1417 g_variant_get (value: result, format_string: "(s)", &data->xml);
1418 g_variant_unref (value: result);
1419
1420 g_main_loop_quit (loop: data->loop);
1421}
1422
1423static GDBusNodeInfo *
1424introspect (GDBusConnection *connection,
1425 const gchar *name,
1426 const gchar *object_path,
1427 GMainLoop *loop)
1428{
1429 GError *error;
1430 GDBusNodeInfo *node_info;
1431 IntrospectData *data;
1432
1433 data = g_new0 (IntrospectData, 1);
1434 data->xml = NULL;
1435 data->loop = loop;
1436
1437 /* do this async to avoid deadlocks */
1438 g_dbus_connection_call (connection,
1439 bus_name: name,
1440 object_path,
1441 interface_name: "org.freedesktop.DBus.Introspectable",
1442 method_name: "Introspect",
1443 NULL, /* params */
1444 G_VARIANT_TYPE ("(s)"),
1445 flags: G_DBUS_CALL_FLAGS_NONE,
1446 timeout_msec: -1,
1447 NULL,
1448 callback: (GAsyncReadyCallback) introspect_cb,
1449 user_data: data);
1450 g_main_loop_run (loop);
1451 g_assert (data->xml != NULL);
1452
1453 error = NULL;
1454 node_info = g_dbus_node_info_new_for_xml (xml_data: data->xml, error: &error);
1455 g_assert_no_error (error);
1456 g_assert (node_info != NULL);
1457 g_free (mem: data->xml);
1458 g_free (mem: data);
1459
1460 return node_info;
1461}
1462
1463static guint
1464count_interfaces (GDBusNodeInfo *info)
1465{
1466 guint n;
1467 for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
1468 ;
1469 return n;
1470}
1471
1472static guint
1473count_nodes (GDBusNodeInfo *info)
1474{
1475 guint n;
1476 for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
1477 ;
1478 return n;
1479}
1480
1481static guint
1482has_interface (GDBusNodeInfo *info,
1483 const gchar *name)
1484{
1485 guint n;
1486 for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
1487 {
1488 if (g_strcmp0 (str1: info->interfaces[n]->name, str2: name) == 0)
1489 return TRUE;
1490 }
1491 return FALSE;
1492}
1493
1494/* ---------------------------------------------------------------------------------------------------- */
1495
1496typedef struct {
1497 GMainLoop *loop;
1498 GVariant *result;
1499} OMGetManagedObjectsData;
1500
1501static void
1502om_get_all_cb (GDBusConnection *connection,
1503 GAsyncResult *res,
1504 gpointer user_data)
1505{
1506 OMGetManagedObjectsData *data = user_data;
1507 GError *error;
1508
1509 error = NULL;
1510 data->result = g_dbus_connection_call_finish (connection,
1511 res,
1512 error: &error);
1513 g_assert_no_error (error);
1514 g_assert (data->result != NULL);
1515 g_main_loop_quit (loop: data->loop);
1516}
1517
1518static void
1519om_check_get_all (GDBusConnection *c,
1520 GMainLoop *loop,
1521 const gchar *str)
1522{
1523 OMGetManagedObjectsData data;
1524 gchar *s;
1525
1526 data.loop = loop;
1527 data.result = NULL;
1528
1529 /* do this async to avoid deadlocks */
1530 g_dbus_connection_call (connection: c,
1531 bus_name: g_dbus_connection_get_unique_name (connection: c),
1532 object_path: "/managed",
1533 interface_name: "org.freedesktop.DBus.ObjectManager",
1534 method_name: "GetManagedObjects",
1535 NULL, /* params */
1536 G_VARIANT_TYPE ("(a{oa{sa{sv}}})"),
1537 flags: G_DBUS_CALL_FLAGS_NONE,
1538 timeout_msec: -1,
1539 NULL,
1540 callback: (GAsyncReadyCallback) om_get_all_cb,
1541 user_data: &data);
1542 g_main_loop_run (loop);
1543 g_assert (data.result != NULL);
1544 s = g_variant_print (value: data.result, TRUE);
1545 g_assert_cmpstr (s, ==, str);
1546 g_free (mem: s);
1547 g_variant_unref (value: data.result);
1548}
1549
1550typedef struct
1551{
1552 GMainLoop *loop;
1553 guint state;
1554
1555 guint num_object_proxy_added_signals;
1556 guint num_object_proxy_removed_signals;
1557 guint num_interface_added_signals;
1558 guint num_interface_removed_signals;
1559} OMData;
1560
1561static gint
1562my_pstrcmp (const gchar **a, const gchar **b)
1563{
1564 return g_strcmp0 (str1: *a, str2: *b);
1565}
1566
1567static void
1568om_check_interfaces_added (const gchar *signal_name,
1569 GVariant *parameters,
1570 const gchar *object_path,
1571 const gchar *first_interface_name,
1572 ...)
1573{
1574 const gchar *path;
1575 GVariant *array;
1576 guint n;
1577 GPtrArray *interfaces;
1578 GPtrArray *interfaces_in_message;
1579 va_list var_args;
1580 const gchar *str;
1581
1582 interfaces = g_ptr_array_new ();
1583 g_ptr_array_add (array: interfaces, data: (gpointer) first_interface_name);
1584 va_start (var_args, first_interface_name);
1585 do
1586 {
1587 str = va_arg (var_args, const gchar *);
1588 if (str == NULL)
1589 break;
1590 g_ptr_array_add (array: interfaces, data: (gpointer) str);
1591 }
1592 while (TRUE);
1593 va_end (var_args);
1594
1595 g_variant_get (value: parameters, format_string: "(&o*)", &path, &array);
1596 g_assert_cmpstr (signal_name, ==, "InterfacesAdded");
1597 g_assert_cmpstr (path, ==, object_path);
1598 g_assert_cmpint (g_variant_n_children (array), ==, interfaces->len);
1599 interfaces_in_message = g_ptr_array_new ();
1600 for (n = 0; n < interfaces->len; n++)
1601 {
1602 const gchar *iface_name;
1603 g_variant_get_child (value: array, index_: n, format_string: "{&sa{sv}}", &iface_name, NULL);
1604 g_ptr_array_add (array: interfaces_in_message, data: (gpointer) iface_name);
1605 }
1606 g_assert_cmpint (interfaces_in_message->len, ==, interfaces->len);
1607 g_ptr_array_sort (array: interfaces, compare_func: (GCompareFunc) my_pstrcmp);
1608 g_ptr_array_sort (array: interfaces_in_message, compare_func: (GCompareFunc) my_pstrcmp);
1609 for (n = 0; n < interfaces->len; n++)
1610 g_assert_cmpstr (interfaces->pdata[n], ==, interfaces_in_message->pdata[n]);
1611 g_ptr_array_unref (array: interfaces_in_message);
1612 g_ptr_array_unref (array: interfaces);
1613 g_variant_unref (value: array);
1614}
1615
1616static void
1617om_check_interfaces_removed (const gchar *signal_name,
1618 GVariant *parameters,
1619 const gchar *object_path,
1620 const gchar *first_interface_name,
1621 ...)
1622{
1623 const gchar *path;
1624 GVariant *array;
1625 guint n;
1626 GPtrArray *interfaces;
1627 GPtrArray *interfaces_in_message;
1628 va_list var_args;
1629 const gchar *str;
1630
1631 interfaces = g_ptr_array_new ();
1632 g_ptr_array_add (array: interfaces, data: (gpointer) first_interface_name);
1633 va_start (var_args, first_interface_name);
1634 do
1635 {
1636 str = va_arg (var_args, const gchar *);
1637 if (str == NULL)
1638 break;
1639 g_ptr_array_add (array: interfaces, data: (gpointer) str);
1640 }
1641 while (TRUE);
1642 va_end (var_args);
1643
1644 g_variant_get (value: parameters, format_string: "(&o*)", &path, &array);
1645 g_assert_cmpstr (signal_name, ==, "InterfacesRemoved");
1646 g_assert_cmpstr (path, ==, object_path);
1647 g_assert_cmpint (g_variant_n_children (array), ==, interfaces->len);
1648 interfaces_in_message = g_ptr_array_new ();
1649 for (n = 0; n < interfaces->len; n++)
1650 {
1651 const gchar *iface_name;
1652 g_variant_get_child (value: array, index_: n, format_string: "&s", &iface_name, NULL);
1653 g_ptr_array_add (array: interfaces_in_message, data: (gpointer) iface_name);
1654 }
1655 g_assert_cmpint (interfaces_in_message->len, ==, interfaces->len);
1656 g_ptr_array_sort (array: interfaces, compare_func: (GCompareFunc) my_pstrcmp);
1657 g_ptr_array_sort (array: interfaces_in_message, compare_func: (GCompareFunc) my_pstrcmp);
1658 for (n = 0; n < interfaces->len; n++)
1659 g_assert_cmpstr (interfaces->pdata[n], ==, interfaces_in_message->pdata[n]);
1660 g_ptr_array_unref (array: interfaces_in_message);
1661 g_ptr_array_unref (array: interfaces);
1662 g_variant_unref (value: array);
1663}
1664
1665static void
1666om_on_signal (GDBusConnection *connection,
1667 const gchar *sender_name,
1668 const gchar *object_path,
1669 const gchar *interface_name,
1670 const gchar *signal_name,
1671 GVariant *parameters,
1672 gpointer user_data)
1673{
1674 OMData *om_data = user_data;
1675
1676 //g_debug ("foo: %s", g_variant_print (parameters, TRUE));
1677
1678 switch (om_data->state)
1679 {
1680 default:
1681 case 0:
1682 g_printerr (format: "failing and om_data->state=%d on signal %s, params=%s\n",
1683 om_data->state,
1684 signal_name,
1685 g_variant_print (value: parameters, TRUE));
1686 g_assert_not_reached ();
1687 break;
1688
1689 case 1:
1690 om_check_interfaces_added (signal_name, parameters, object_path: "/managed/first",
1691 first_interface_name: "org.project.Bar", NULL);
1692 om_data->state = 2;
1693 g_main_loop_quit (loop: om_data->loop);
1694 break;
1695
1696 case 3:
1697 om_check_interfaces_removed (signal_name, parameters, object_path: "/managed/first",
1698 first_interface_name: "org.project.Bar", NULL);
1699 om_data->state = 5;
1700 /* keep running the loop */
1701 break;
1702
1703 case 5:
1704 om_check_interfaces_added (signal_name, parameters, object_path: "/managed/first",
1705 first_interface_name: "org.project.Bar", NULL);
1706 om_data->state = 6;
1707 g_main_loop_quit (loop: om_data->loop);
1708 break;
1709
1710 case 7:
1711 om_check_interfaces_removed (signal_name, parameters, object_path: "/managed/first",
1712 first_interface_name: "org.project.Bar", NULL);
1713 om_data->state = 9;
1714 /* keep running the loop */
1715 break;
1716
1717 case 9:
1718 om_check_interfaces_added (signal_name, parameters, object_path: "/managed/first",
1719 first_interface_name: "org.project.Bar", NULL);
1720 om_data->state = 10;
1721 g_main_loop_quit (loop: om_data->loop);
1722 break;
1723
1724 case 11:
1725 om_check_interfaces_added (signal_name, parameters, object_path: "/managed/first",
1726 first_interface_name: "org.project.Bat", NULL);
1727 om_data->state = 12;
1728 g_main_loop_quit (loop: om_data->loop);
1729 break;
1730
1731 case 13:
1732 om_check_interfaces_removed (signal_name, parameters, object_path: "/managed/first",
1733 first_interface_name: "org.project.Bar", NULL);
1734 om_data->state = 14;
1735 g_main_loop_quit (loop: om_data->loop);
1736 break;
1737
1738 case 15:
1739 om_check_interfaces_removed (signal_name, parameters, object_path: "/managed/first",
1740 first_interface_name: "org.project.Bat", NULL);
1741 om_data->state = 16;
1742 g_main_loop_quit (loop: om_data->loop);
1743 break;
1744
1745 case 17:
1746 om_check_interfaces_added (signal_name, parameters, object_path: "/managed/first",
1747 first_interface_name: "com.acme.Coyote", NULL);
1748 om_data->state = 18;
1749 g_main_loop_quit (loop: om_data->loop);
1750 break;
1751
1752 case 101:
1753 om_check_interfaces_added (signal_name, parameters, object_path: "/managed/second",
1754 first_interface_name: "org.project.Bat", "org.project.Bar", NULL);
1755 om_data->state = 102;
1756 g_main_loop_quit (loop: om_data->loop);
1757 break;
1758
1759 case 103:
1760 om_check_interfaces_removed (signal_name, parameters, object_path: "/managed/second",
1761 first_interface_name: "org.project.Bat", "org.project.Bar", NULL);
1762 om_data->state = 104;
1763 g_main_loop_quit (loop: om_data->loop);
1764 break;
1765
1766 case 200:
1767 om_check_interfaces_added (signal_name, parameters, object_path: "/managed/first_1",
1768 first_interface_name: "com.acme.Coyote", NULL);
1769 om_data->state = 201;
1770 g_main_loop_quit (loop: om_data->loop);
1771 break;
1772 }
1773}
1774
1775static GAsyncResult *om_res = NULL;
1776
1777static void
1778om_pm_start_cb (FooiGenObjectManagerClient *manager,
1779 GAsyncResult *res,
1780 gpointer user_data)
1781{
1782 GMainLoop *loop = user_data;
1783 om_res = g_object_ref (res);
1784 g_main_loop_quit (loop);
1785}
1786
1787static void
1788on_interface_added (GDBusObject *object,
1789 GDBusInterface *interface,
1790 gpointer user_data)
1791{
1792 OMData *om_data = user_data;
1793 om_data->num_interface_added_signals += 1;
1794}
1795
1796static void
1797on_interface_removed (GDBusObject *object,
1798 GDBusInterface *interface,
1799 gpointer user_data)
1800{
1801 OMData *om_data = user_data;
1802 om_data->num_interface_removed_signals += 1;
1803}
1804
1805static void
1806on_object_proxy_added (GDBusObjectManagerClient *manager,
1807 GDBusObjectProxy *object_proxy,
1808 gpointer user_data)
1809{
1810 OMData *om_data = user_data;
1811 om_data->num_object_proxy_added_signals += 1;
1812 g_signal_connect (object_proxy,
1813 "interface-added",
1814 G_CALLBACK (on_interface_added),
1815 om_data);
1816 g_signal_connect (object_proxy,
1817 "interface-removed",
1818 G_CALLBACK (on_interface_removed),
1819 om_data);
1820}
1821
1822static void
1823on_object_proxy_removed (GDBusObjectManagerClient *manager,
1824 GDBusObjectProxy *object_proxy,
1825 gpointer user_data)
1826{
1827 OMData *om_data = user_data;
1828 om_data->num_object_proxy_removed_signals += 1;
1829 g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
1830 G_CALLBACK (on_interface_added),
1831 om_data), ==, 1);
1832 g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
1833 G_CALLBACK (on_interface_removed),
1834 om_data), ==, 1);
1835}
1836
1837static void
1838property_changed (GObject *object,
1839 GParamSpec *pspec,
1840 gpointer user_data)
1841{
1842 gboolean *changed = user_data;
1843
1844 *changed = TRUE;
1845}
1846
1847static void
1848om_check_property_and_signal_emission (GMainLoop *loop,
1849 FooiGenBar *skeleton,
1850 FooiGenBar *proxy)
1851{
1852 gboolean d_changed = FALSE;
1853 gboolean quiet_changed = FALSE;
1854 gboolean quiet_too_changed = FALSE;
1855 guint handler;
1856
1857 /* First PropertiesChanged */
1858 g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 0);
1859 g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 0);
1860 foo_igen_bar_set_i (skeleton, 1);
1861 _g_assert_property_notify (proxy, "i");
1862 g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 1);
1863 g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 1);
1864
1865 /* Double-check the gdouble case */
1866 g_assert_cmpfloat (foo_igen_bar_get_d (skeleton), ==, 0.0);
1867 g_assert_cmpfloat (foo_igen_bar_get_d (proxy), ==, 0.0);
1868 foo_igen_bar_set_d (skeleton, 1.0);
1869 _g_assert_property_notify (proxy, "d");
1870
1871 /* Verify that re-setting it to the same value doesn't cause a
1872 * notify on the proxy, by taking advantage of the fact that
1873 * notifications are serialized.
1874 */
1875 handler = g_signal_connect (proxy, "notify::d",
1876 G_CALLBACK (property_changed), &d_changed);
1877 foo_igen_bar_set_d (skeleton, 1.0);
1878 foo_igen_bar_set_i (skeleton, 2);
1879 _g_assert_property_notify (proxy, "i");
1880 g_assert (d_changed == FALSE);
1881 g_signal_handler_disconnect (instance: proxy, handler_id: handler);
1882
1883 /* Verify that re-setting a property with the "EmitsChangedSignal"
1884 * set to false doesn't emit a signal. */
1885 handler = g_signal_connect (proxy, "notify::quiet",
1886 G_CALLBACK (property_changed), &quiet_changed);
1887 foo_igen_bar_set_quiet (skeleton, "hush!");
1888 foo_igen_bar_set_i (skeleton, 3);
1889 _g_assert_property_notify (proxy, "i");
1890 g_assert (quiet_changed == FALSE);
1891 g_assert_cmpstr (foo_igen_bar_get_quiet (skeleton), ==, "hush!");
1892 g_signal_handler_disconnect (instance: proxy, handler_id: handler);
1893
1894 /* Also verify that re-setting a property with the "EmitsChangedSignal"
1895 * set to 'const' doesn't emit a signal. */
1896 handler = g_signal_connect (proxy, "notify::quiet-too",
1897 G_CALLBACK (property_changed), &quiet_changed);
1898 foo_igen_bar_set_quiet_too (skeleton, "hush too!");
1899 foo_igen_bar_set_i (skeleton, 4);
1900 _g_assert_property_notify (proxy, "i");
1901 g_assert (quiet_too_changed == FALSE);
1902 g_assert_cmpstr (foo_igen_bar_get_quiet_too (skeleton), ==, "hush too!");
1903 g_signal_handler_disconnect (instance: proxy, handler_id: handler);
1904
1905 /* Then just a regular signal */
1906 foo_igen_bar_emit_another_signal (skeleton, "word");
1907 _g_assert_signal_received (proxy, "another-signal");
1908}
1909
1910static void
1911check_object_manager (void)
1912{
1913 FooiGenObjectSkeleton *o = NULL;
1914 FooiGenObjectSkeleton *o2 = NULL;
1915 FooiGenObjectSkeleton *o3 = NULL;
1916 GDBusInterfaceSkeleton *i;
1917 GDBusConnection *c;
1918 GDBusObjectManagerServer *manager = NULL;
1919 GDBusNodeInfo *info;
1920 GError *error;
1921 GMainLoop *loop;
1922 OMData *om_data = NULL;
1923 guint om_signal_id = -1;
1924 GDBusObjectManager *pm = NULL;
1925 GList *object_proxies;
1926 GList *proxies;
1927 GDBusObject *op;
1928 GDBusProxy *p;
1929 FooiGenBar *bar_skeleton;
1930 GDBusInterface *iface;
1931 gchar *path, *name, *name_owner;
1932 GDBusConnection *c2;
1933 GDBusObjectManagerClientFlags flags;
1934
1935 loop = g_main_loop_new (NULL, FALSE);
1936
1937 om_data = g_new0 (OMData, 1);
1938 om_data->loop = loop;
1939 om_data->state = 0;
1940
1941 error = NULL;
1942 c = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, error: &error);
1943 g_assert_no_error (error);
1944 g_assert (c != NULL);
1945
1946 om_signal_id = g_dbus_connection_signal_subscribe (connection: c,
1947 NULL, /* sender */
1948 interface_name: "org.freedesktop.DBus.ObjectManager",
1949 NULL, /* member */
1950 NULL, /* object_path */
1951 NULL, /* arg0 */
1952 flags: G_DBUS_SIGNAL_FLAGS_NONE,
1953 callback: om_on_signal,
1954 user_data: om_data,
1955 NULL); /* user_data_free_func */
1956
1957 /* Our GDBusObjectManagerClient tests are simple - we basically just count the
1958 * number of times the various signals have been emitted (we don't check
1959 * that the right objects/interfaces are passed though - that's checked
1960 * in the lower-level tests in om_on_signal()...)
1961 *
1962 * Note that these tests rely on the D-Bus signal handlers used by
1963 * GDBusObjectManagerClient firing before om_on_signal().
1964 */
1965 error = NULL;
1966 pm = foo_igen_object_manager_client_new_sync (c,
1967 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
1968 g_dbus_connection_get_unique_name (connection: c),
1969 "/managed",
1970 NULL, /* GCancellable */
1971 &error);
1972 g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
1973 g_error_free (error);
1974 g_assert (pm == NULL);
1975
1976 manager = g_dbus_object_manager_server_new (object_path: "/managed");
1977
1978 g_assert (g_dbus_object_manager_server_get_connection (manager) == NULL);
1979
1980 g_dbus_object_manager_server_set_connection (manager, connection: c);
1981
1982 g_assert_cmpstr (g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)), ==, "/managed");
1983 g_object_get (object: manager, first_property_name: "object-path", &path, "connection", &c2, NULL);
1984 g_assert_cmpstr (path, ==, "/managed");
1985 g_assert (c2 == c);
1986 g_free (mem: path);
1987 g_clear_object (&c2);
1988
1989 /* Check that the manager object is visible */
1990 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed", loop);
1991 g_assert_cmpint (count_interfaces (info), ==, 4); /* ObjectManager + Properties,Introspectable,Peer */
1992 g_assert (has_interface (info, "org.freedesktop.DBus.ObjectManager"));
1993 g_assert_cmpint (count_nodes (info), ==, 0);
1994 g_dbus_node_info_unref (info);
1995
1996 /* Check GetManagedObjects() - should be empty since we have no objects */
1997 om_check_get_all (c, loop,
1998 str: "(@a{oa{sa{sv}}} {},)");
1999
2000 /* Now try to create the proxy manager again - this time it should work */
2001 error = NULL;
2002 foo_igen_object_manager_client_new (c,
2003 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
2004 g_dbus_connection_get_unique_name (connection: c),
2005 "/managed",
2006 NULL, /* GCancellable */
2007 (GAsyncReadyCallback) om_pm_start_cb,
2008 loop);
2009 g_main_loop_run (loop);
2010 error = NULL;
2011 pm = foo_igen_object_manager_client_new_finish (om_res, &error);
2012 g_clear_object (&om_res);
2013 g_assert_no_error (error);
2014 g_assert (pm != NULL);
2015 g_signal_connect (pm,
2016 "object-added",
2017 G_CALLBACK (on_object_proxy_added),
2018 om_data);
2019 g_signal_connect (pm,
2020 "object-removed",
2021 G_CALLBACK (on_object_proxy_removed),
2022 om_data);
2023
2024 g_assert_cmpstr (g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (pm)), ==, "/managed");
2025 g_object_get (object: pm,
2026 first_property_name: "object-path", &path,
2027 "connection", &c2,
2028 "name", &name,
2029 "name-owner", &name_owner,
2030 "flags", &flags,
2031 NULL);
2032 g_assert_cmpstr (path, ==, "/managed");
2033 g_assert_cmpstr (name, ==, g_dbus_connection_get_unique_name (c));
2034 g_assert_cmpstr (name_owner, ==, g_dbus_connection_get_unique_name (c));
2035 g_assert_cmpint (flags, ==, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
2036 g_assert (c2 == c);
2037 g_free (mem: path);
2038 g_clear_object (&c2);
2039 g_free (mem: name);
2040 g_free (mem: name_owner);
2041
2042 /* ... check there are no object proxies yet */
2043 object_proxies = g_dbus_object_manager_get_objects (manager: pm);
2044 g_assert (object_proxies == NULL);
2045
2046 /* First, export an object with a single interface (also check that
2047 * g_dbus_interface_get_object() works and that the object isn't reffed)
2048 */
2049 o = foo_igen_object_skeleton_new ("/managed/first");
2050 i = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ());
2051 g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
2052 g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
2053 foo_igen_object_skeleton_set_bar (o, FOO_IGEN_BAR (i));
2054 g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
2055 g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
2056 g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
2057 foo_igen_object_skeleton_set_bar (o, NULL);
2058 g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
2059 g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
2060 foo_igen_object_skeleton_set_bar (o, FOO_IGEN_BAR (i));
2061 g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
2062 g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
2063
2064 o2 = FOO_IGEN_OBJECT_SKELETON (g_dbus_interface_dup_object (G_DBUS_INTERFACE (i)));
2065 g_assert (G_DBUS_OBJECT (o2) == G_DBUS_OBJECT (o));
2066 g_assert_cmpint (G_OBJECT (o2)->ref_count, ==, 2);
2067 g_clear_object (&o2);
2068
2069 g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (o));
2070
2071 /* ... check we get the InterfacesAdded signal */
2072 om_data->state = 1;
2073
2074 g_main_loop_run (loop: om_data->loop);
2075
2076 g_assert_cmpint (om_data->state, ==, 2);
2077 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 1);
2078 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 0);
2079 g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
2080 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
2081 /* ... check there's one non-standard interfaces */
2082 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/first", loop);
2083 g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
2084 g_assert (has_interface (info, "org.project.Bar"));
2085 g_dbus_node_info_unref (info);
2086
2087 /* Also check g_dbus_object_manager_get_interface */
2088 iface = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (manager), object_path: "/managed/first", interface_name: "org.project.Bar");
2089 g_assert (iface != NULL);
2090 g_clear_object (&iface);
2091 iface = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (manager), object_path: "/managed/first", interface_name: "org.project.Bat");
2092 g_assert (iface == NULL);
2093 iface = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (pm), object_path: "/managed/first", interface_name: "org.project.Bar");
2094 g_assert (iface != NULL);
2095 g_clear_object (&iface);
2096 iface = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (pm), object_path: "/managed/first", interface_name: "org.project.Bat");
2097 g_assert (iface == NULL);
2098
2099 /* Now, check adding the same interface replaces the existing one */
2100 foo_igen_object_skeleton_set_bar (o, FOO_IGEN_BAR (i));
2101 /* ... check we get the InterfacesRemoved */
2102 om_data->state = 3;
2103 g_main_loop_run (loop: om_data->loop);
2104 /* ... and then check we get the InterfacesAdded */
2105 g_assert_cmpint (om_data->state, ==, 6);
2106 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 2);
2107 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 1);
2108 g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
2109 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
2110 /* ... check introspection data */
2111 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/first", loop);
2112 g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
2113 g_assert (has_interface (info, "org.project.Bar"));
2114 g_dbus_node_info_unref (info);
2115 g_clear_object (&i);
2116
2117 /* check adding an interface of same type (but not same object) replaces the existing one */
2118 i = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ());
2119 foo_igen_object_skeleton_set_bar (o, FOO_IGEN_BAR (i));
2120 /* ... check we get the InterfacesRemoved and then InterfacesAdded */
2121 om_data->state = 7;
2122 g_main_loop_run (loop: om_data->loop);
2123 g_assert_cmpint (om_data->state, ==, 10);
2124 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
2125 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
2126 g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
2127 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
2128 /* ... check introspection data */
2129 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/first", loop);
2130 g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
2131 g_assert (has_interface (info, "org.project.Bar"));
2132 g_dbus_node_info_unref (info);
2133 g_clear_object (&i);
2134
2135 /* check adding an interface of another type doesn't replace the existing one */
2136 i = G_DBUS_INTERFACE_SKELETON (foo_igen_bat_skeleton_new ());
2137 foo_igen_object_skeleton_set_bat (o, FOO_IGEN_BAT (i));
2138 g_clear_object (&i);
2139 /* ... check we get the InterfacesAdded */
2140 om_data->state = 11;
2141 g_main_loop_run (loop: om_data->loop);
2142 g_assert_cmpint (om_data->state, ==, 12);
2143 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
2144 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
2145 g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
2146 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
2147 /* ... check introspection data */
2148 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/first", loop);
2149 g_assert_cmpint (count_interfaces (info), ==, 5); /* Bar,Bat + Properties,Introspectable,Peer */
2150 g_assert (has_interface (info, "org.project.Bar"));
2151 g_assert (has_interface (info, "org.project.Bat"));
2152 g_dbus_node_info_unref (info);
2153
2154 /* check we can remove an interface */
2155 foo_igen_object_skeleton_set_bar (o, NULL);
2156 /* ... check we get the InterfacesRemoved */
2157 om_data->state = 13;
2158 g_main_loop_run (loop: om_data->loop);
2159 g_assert_cmpint (om_data->state, ==, 14);
2160 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
2161 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
2162 g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
2163 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
2164 /* ... check introspection data */
2165 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/first", loop);
2166 g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
2167 g_assert (has_interface (info, "org.project.Bat"));
2168 g_dbus_node_info_unref (info);
2169 /* also and that the call only has effect if the interface actually exists
2170 *
2171 * (Note: if a signal was emitted we'd assert in the signal handler
2172 * because we're in state 14)
2173 */
2174 foo_igen_object_skeleton_set_bar (o, NULL);
2175 /* ... check introspection data */
2176 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/first", loop);
2177 g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
2178 g_assert (has_interface (info, "org.project.Bat"));
2179 g_dbus_node_info_unref (info);
2180
2181 /* remove the last interface */
2182 foo_igen_object_skeleton_set_bat (o, NULL);
2183 /* ... check we get the InterfacesRemoved */
2184 om_data->state = 15;
2185 g_main_loop_run (loop: om_data->loop);
2186 g_assert_cmpint (om_data->state, ==, 16);
2187 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
2188 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
2189 g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
2190 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
2191 /* ... check introspection data */
2192 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/first", loop);
2193 g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
2194 g_dbus_node_info_unref (info);
2195
2196 /* and add an interface again */
2197 i = G_DBUS_INTERFACE_SKELETON (foo_igen_com_acme_coyote_skeleton_new ());
2198 foo_igen_object_skeleton_set_com_acme_coyote (o, FOO_IGEN_COM_ACME_COYOTE (i));
2199 g_clear_object (&i);
2200 /* ... check we get the InterfacesAdded */
2201 om_data->state = 17;
2202 g_main_loop_run (loop: om_data->loop);
2203 g_assert_cmpint (om_data->state, ==, 18);
2204 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 4);
2205 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
2206 g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
2207 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
2208 /* ... check introspection data */
2209 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/first", loop);
2210 g_assert_cmpint (count_interfaces (info), ==, 4); /* com.acme.Coyote + Properties,Introspectable,Peer */
2211 g_assert (has_interface (info, "com.acme.Coyote"));
2212 g_dbus_node_info_unref (info);
2213
2214 /* Check GetManagedObjects() - should be just the Coyote */
2215 om_check_get_all (c, loop,
2216 str: "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
2217
2218 /* -------------------------------------------------- */
2219
2220 /* create a new object with two interfaces */
2221 o2 = foo_igen_object_skeleton_new ("/managed/second");
2222 i = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ());
2223 bar_skeleton = FOO_IGEN_BAR (i); /* save for later test */
2224 foo_igen_object_skeleton_set_bar (o2, FOO_IGEN_BAR (i));
2225 g_clear_object (&i);
2226 i = G_DBUS_INTERFACE_SKELETON (foo_igen_bat_skeleton_new ());
2227 foo_igen_object_skeleton_set_bat (o2, FOO_IGEN_BAT (i));
2228 g_clear_object (&i);
2229 /* ... add it */
2230 g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (o2));
2231 /* ... check we get the InterfacesAdded with _two_ interfaces */
2232 om_data->state = 101;
2233 g_main_loop_run (loop: om_data->loop);
2234 g_assert_cmpint (om_data->state, ==, 102);
2235 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
2236 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
2237 g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
2238 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
2239
2240 /* -------------------------------------------------- */
2241
2242 /* Now that we have a couple of objects with interfaces, check
2243 * that ObjectManager.GetManagedObjects() works
2244 */
2245 om_check_get_all (c, loop,
2246 str: "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'quiet': <''>, 'quiet_too': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
2247
2248 /* Set connection to NULL, causing everything to be unexported.. verify this.. and
2249 * then set the connection back.. and then check things still work
2250 */
2251 g_dbus_object_manager_server_set_connection (manager, NULL);
2252 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed", loop);
2253 g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
2254 g_dbus_node_info_unref (info);
2255
2256 g_dbus_object_manager_server_set_connection (manager, connection: c);
2257 om_check_get_all (c, loop,
2258 str: "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'quiet': <''>, 'quiet_too': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
2259
2260 /* Also check that the ObjectManagerClient returns these objects - and
2261 * that they are of the right GType cf. what was requested via
2262 * the generated ::get-proxy-type signal handler
2263 */
2264 object_proxies = g_dbus_object_manager_get_objects (manager: pm);
2265 g_assert (g_list_length (object_proxies) == 2);
2266 g_list_free_full (list: object_proxies, free_func: g_object_unref);
2267 op = g_dbus_object_manager_get_object (manager: pm, object_path: "/managed/first");
2268 g_assert (op != NULL);
2269 g_assert (FOO_IGEN_IS_OBJECT_PROXY (op));
2270 g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/first");
2271 proxies = g_dbus_object_get_interfaces (object: op);
2272 g_assert (g_list_length (proxies) == 1);
2273 g_list_free_full (list: proxies, free_func: g_object_unref);
2274 p = G_DBUS_PROXY (foo_igen_object_get_com_acme_coyote (FOO_IGEN_OBJECT (op)));
2275 g_assert (p != NULL);
2276 g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_COM_ACME_COYOTE_PROXY);
2277 g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_TYPE_COM_ACME_COYOTE));
2278 g_clear_object (&p);
2279 p = (GDBusProxy *) g_dbus_object_get_interface (object: op, interface_name: "org.project.NonExisting");
2280 g_assert (p == NULL);
2281 g_clear_object (&op);
2282
2283 /* -- */
2284 op = g_dbus_object_manager_get_object (manager: pm, object_path: "/managed/second");
2285 g_assert (op != NULL);
2286 g_assert (FOO_IGEN_IS_OBJECT_PROXY (op));
2287 g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/second");
2288 proxies = g_dbus_object_get_interfaces (object: op);
2289 g_assert (g_list_length (proxies) == 2);
2290 g_list_free_full (list: proxies, free_func: g_object_unref);
2291 p = G_DBUS_PROXY (foo_igen_object_get_bat (FOO_IGEN_OBJECT (op)));
2292 g_assert (p != NULL);
2293 g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_BAT_PROXY);
2294 g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_TYPE_BAT));
2295 g_clear_object (&p);
2296 p = G_DBUS_PROXY (foo_igen_object_get_bar (FOO_IGEN_OBJECT (op)));
2297 g_assert (p != NULL);
2298 g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_BAR_PROXY);
2299 g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_TYPE_BAR));
2300 /* ... now that we have a Bar instance around, also check that we get signals
2301 * and property changes...
2302 */
2303 om_check_property_and_signal_emission (loop, bar_skeleton, FOO_IGEN_BAR (p));
2304 g_clear_object (&p);
2305 p = (GDBusProxy *) g_dbus_object_get_interface (object: op, interface_name: "org.project.NonExisting");
2306 g_assert (p == NULL);
2307 g_clear_object (&op);
2308
2309 /* -------------------------------------------------- */
2310
2311 /* Now remove the second object added above */
2312 g_dbus_object_manager_server_unexport (manager, object_path: "/managed/second");
2313 /* ... check we get InterfacesRemoved with both interfaces */
2314 om_data->state = 103;
2315 g_main_loop_run (loop: om_data->loop);
2316 g_assert_cmpint (om_data->state, ==, 104);
2317 g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
2318 g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 4);
2319 g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
2320 g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
2321 /* ... check introspection data (there should be nothing) */
2322 info = introspect (connection: c, name: g_dbus_connection_get_unique_name (connection: c), object_path: "/managed/second", loop);
2323 g_assert_cmpint (count_nodes (info), ==, 0);
2324 g_assert_cmpint (count_interfaces (info), ==, 0);
2325 g_dbus_node_info_unref (info);
2326
2327 /* Check GetManagedObjects() again */
2328 om_check_get_all (c, loop,
2329 str: "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
2330 /* -------------------------------------------------- */
2331
2332 /* Check that export_uniquely() works */
2333
2334 o3 = foo_igen_object_skeleton_new ("/managed/first");
2335 i = G_DBUS_INTERFACE_SKELETON (foo_igen_com_acme_coyote_skeleton_new ());
2336 foo_igen_com_acme_coyote_set_mood (FOO_IGEN_COM_ACME_COYOTE (i), "indifferent");
2337 foo_igen_object_skeleton_set_com_acme_coyote (o3, FOO_IGEN_COM_ACME_COYOTE (i));
2338 g_clear_object (&i);
2339 g_dbus_object_manager_server_export_uniquely (manager, G_DBUS_OBJECT_SKELETON (o3));
2340 /* ... check we get the InterfacesAdded signal */
2341 om_data->state = 200;
2342 g_main_loop_run (loop: om_data->loop);
2343 g_assert_cmpint (om_data->state, ==, 201);
2344
2345 om_check_get_all (c, loop,
2346 str: "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/first_1': {'com.acme.Coyote': {'Mood': <'indifferent'>}}},)");
2347
2348 //g_main_loop_run (loop); /* TODO: tmp */
2349
2350 /* Clean up objects */
2351 g_assert (g_dbus_object_manager_server_unexport (manager, "/managed/first_1"));
2352 //g_assert (g_dbus_object_manager_server_unexport (manager, "/managed/second"));
2353 g_assert (g_dbus_object_manager_server_unexport (manager, "/managed/first"));
2354 g_assert_cmpint (g_list_length (g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager))), ==, 0);
2355
2356 if (loop != NULL)
2357 g_main_loop_unref (loop);
2358
2359 if (om_signal_id != -1)
2360 g_dbus_connection_signal_unsubscribe (connection: c, subscription_id: om_signal_id);
2361 g_clear_object (&o3);
2362 g_clear_object (&o2);
2363 g_clear_object (&o);
2364 g_clear_object (&manager);
2365 if (pm != NULL)
2366 {
2367 g_assert_cmpint (g_signal_handlers_disconnect_by_func (pm,
2368 G_CALLBACK (on_object_proxy_added),
2369 om_data), ==, 1);
2370 g_assert_cmpint (g_signal_handlers_disconnect_by_func (pm,
2371 G_CALLBACK (on_object_proxy_removed),
2372 om_data), ==, 1);
2373 g_clear_object (&pm);
2374 }
2375 g_clear_object (&c);
2376
2377 g_free (mem: om_data);
2378}
2379
2380/* ---------------------------------------------------------------------------------------------------- */
2381
2382static void
2383test_object_manager (void)
2384{
2385 GMainLoop *loop;
2386 guint id;
2387
2388 loop = g_main_loop_new (NULL, FALSE);
2389
2390 id = g_bus_own_name (bus_type: G_BUS_TYPE_SESSION,
2391 name: "org.gtk.GDBus.BindingsTool.Test",
2392 flags: G_BUS_NAME_OWNER_FLAGS_NONE,
2393 bus_acquired_handler: on_bus_acquired,
2394 name_acquired_handler: on_name_acquired,
2395 name_lost_handler: on_name_lost,
2396 user_data: loop,
2397 NULL);
2398
2399 g_main_loop_run (loop);
2400
2401 check_object_manager ();
2402
2403 /* uncomment to keep the service around (to e.g. introspect it) */
2404 /* g_main_loop_run (loop); */
2405
2406 unexport_objects ();
2407
2408 g_bus_unown_name (owner_id: id);
2409 g_main_loop_unref (loop);
2410}
2411
2412/* ---------------------------------------------------------------------------------------------------- */
2413/* This checks that forcing names via org.gtk.GDBus.Name works (see test-codegen.xml) */
2414
2415extern gpointer name_forcing_1;
2416extern gpointer name_forcing_2;
2417extern gpointer name_forcing_3;
2418extern gpointer name_forcing_4;
2419extern gpointer name_forcing_5;
2420extern gpointer name_forcing_6;
2421extern gpointer name_forcing_7;
2422gpointer name_forcing_1 = foo_igen_rocket123_get_type;
2423gpointer name_forcing_2 = foo_igen_rocket123_call_ignite_xyz;
2424gpointer name_forcing_3 = foo_igen_rocket123_emit_exploded_xyz;
2425gpointer name_forcing_4 = foo_igen_rocket123_get_speed_xyz;
2426gpointer name_forcing_5 = foo_igen_test_ugly_case_interface_call_get_iscsi_servers;
2427gpointer name_forcing_6 = foo_igen_test_ugly_case_interface_emit_servers_updated_now;
2428gpointer name_forcing_7 = foo_igen_test_ugly_case_interface_get_ugly_name;
2429
2430/* ---------------------------------------------------------------------------------------------------- */
2431
2432/* See https://bugzilla.gnome.org/show_bug.cgi?id=647577#c5 for details */
2433
2434#define CHECK_FIELD(name, v1, v2) g_assert_cmpint (G_STRUCT_OFFSET (FooiGenChangingInterface##v1##Iface, name), ==, G_STRUCT_OFFSET (FooiGenChangingInterface##v2##Iface, name));
2435
2436static void
2437test_interface_stability (void)
2438{
2439 CHECK_FIELD(handle_foo_method, V1, V2);
2440 CHECK_FIELD(handle_bar_method, V1, V2);
2441 CHECK_FIELD(handle_baz_method, V1, V2);
2442 CHECK_FIELD(foo_signal, V1, V2);
2443 CHECK_FIELD(bar_signal, V1, V2);
2444 CHECK_FIELD(baz_signal, V1, V2);
2445 CHECK_FIELD(handle_new_method_in2, V2, V10);
2446 CHECK_FIELD(new_signal_in2, V2, V10);
2447}
2448
2449#undef CHECK_FIELD
2450
2451/* ---------------------------------------------------------------------------------------------------- */
2452
2453/* property naming
2454 *
2455 * - check that a property with name "Type" is mapped into g-name "type"
2456 * with C accessors get_type_ (to avoid clashing with the GType accessor)
2457 * and set_type_ (for symmetry)
2458 * (see https://bugzilla.gnome.org/show_bug.cgi?id=679473 for details)
2459 *
2460 * - (could add more tests here)
2461 */
2462
2463static void
2464test_property_naming (void)
2465{
2466 gpointer c_getter_name = foo_igen_naming_get_type_;
2467 gpointer c_setter_name = foo_igen_naming_set_type_;
2468 FooiGenNaming *skel;
2469
2470 (void) c_getter_name;
2471 (void) c_setter_name;
2472
2473 skel = foo_igen_naming_skeleton_new ();
2474 g_assert (g_object_class_find_property (G_OBJECT_GET_CLASS (skel), "type") != NULL);
2475 g_object_unref (skel);
2476}
2477
2478/* ---------------------------------------------------------------------------------------------------- */
2479
2480/* autocleanups
2481 *
2482 * - check that g_autoptr() works for all generated types, if supported by the
2483 * current compiler
2484 */
2485
2486static void
2487test_autocleanups (void)
2488{
2489#ifdef g_autoptr
2490 g_autoptr(FooiGenBar) bar = NULL;
2491 g_autoptr(FooiGenBarProxy) bar_proxy = NULL;
2492 g_autoptr(FooiGenBarSkeleton) bar_skeleton = NULL;
2493 g_autoptr(FooiGenObject) object = NULL;
2494 g_autoptr(FooiGenObjectProxy) object_proxy = NULL;
2495 g_autoptr(FooiGenObjectSkeleton) object_skeleton = NULL;
2496 g_autoptr(FooiGenObjectManagerClient) object_manager_client = NULL;
2497
2498 (void) bar;
2499 (void) bar_proxy;
2500 (void) bar_skeleton;
2501 (void) object;
2502 (void) object_proxy;
2503 (void) object_skeleton;
2504 (void) object_manager_client;
2505#elif GLIB_CHECK_VERSION(2, 38, 0)
2506 /* This file is compiled twice, once without GLib version guards and once
2507 * with
2508 *
2509 * -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_36
2510 * -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_36
2511 *
2512 * g_test_skip() was added in 2.38.
2513 */
2514 g_test_skip ("g_autoptr() not supported on this compiler");
2515#else
2516 /* Let's just say it passed. */
2517#endif
2518}
2519
2520/* ---------------------------------------------------------------------------------------------------- */
2521
2522/* deprecations
2523 */
2524
2525static void
2526test_deprecations (void)
2527{
2528 {
2529 FooiGenOldieInterface *iskel;
2530 GParamSpec *pspec;
2531
2532 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2533 iskel = foo_igen_oldie_interface_skeleton_new ();
2534 G_GNUC_END_IGNORE_DEPRECATIONS;
2535
2536 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (iskel), "bat");
2537 g_assert_nonnull (pspec);
2538 g_assert_cmpint (pspec->flags & G_PARAM_DEPRECATED, ==, G_PARAM_DEPRECATED);
2539
2540 g_object_unref (iskel);
2541 }
2542
2543 {
2544 FooiGenObjectSkeleton *oskel;
2545 GParamSpec *pspec;
2546
2547 oskel = foo_igen_object_skeleton_new ("/objects/first");
2548 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (oskel), "oldie-interface");
2549 g_assert_nonnull (pspec);
2550 g_assert_cmpint (pspec->flags & G_PARAM_DEPRECATED, ==, G_PARAM_DEPRECATED);
2551
2552 g_object_unref (oskel);
2553 }
2554}
2555
2556/* ---------------------------------------------------------------------------------------------------- */
2557
2558static void
2559assert_arg_infos_equal (GDBusArgInfo **a,
2560 GDBusArgInfo **b)
2561{
2562 if (a == NULL)
2563 {
2564 g_assert_null (b);
2565 return;
2566 }
2567
2568 g_assert_nonnull (b);
2569
2570 for (; *a != NULL && *b != NULL; a++, b++)
2571 {
2572 g_assert_cmpstr ((*a)->name, ==, (*b)->name);
2573 g_assert_cmpstr ((*a)->signature, ==, (*b)->signature);
2574 }
2575
2576 g_assert_null (*a);
2577 g_assert_null (*b);
2578}
2579
2580static void
2581assert_annotations_equal (GDBusAnnotationInfo **a,
2582 GDBusAnnotationInfo **b)
2583{
2584 guint a_len = count_annotations (annotations: a);
2585 guint b_len = count_annotations (annotations: b);
2586
2587 g_assert_cmpuint (a_len, ==, b_len);
2588
2589 if (a == NULL || b == NULL)
2590 return;
2591
2592 for (; *a != NULL && *b != NULL; a++, b++)
2593 {
2594 g_assert_cmpstr ((*a)->key, ==, (*b)->key);
2595 g_assert_cmpstr ((*a)->value, ==, (*b)->value);
2596 assert_annotations_equal (a: (*a)->annotations, b: (*b)->annotations);
2597 }
2598
2599 g_assert_null (*a);
2600 g_assert_null (*b);
2601}
2602
2603/* Test that the GDBusInterfaceInfo structure generated by gdbus-codegen
2604 * --interface-info-body matches that generated by the other mode.
2605 */
2606static void
2607test_standalone_interface_info (void)
2608{
2609 GDBusInterfaceSkeleton *skel = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ());
2610 GDBusInterfaceInfo *skel_info = g_dbus_interface_skeleton_get_info (interface_: skel);
2611 const GDBusInterfaceInfo *slim_info = &org_project_bar_interface;
2612 gsize i;
2613
2614 g_assert_cmpstr (skel_info->name, ==, slim_info->name);
2615
2616 for (i = 0; skel_info->methods[i] != NULL; i++)
2617 {
2618 GDBusMethodInfo *skel_method = skel_info->methods[i];
2619 GDBusMethodInfo *slim_method = slim_info->methods[i];
2620
2621 g_assert_nonnull (slim_method);
2622 g_assert_cmpstr (skel_method->name, ==, slim_method->name);
2623 assert_arg_infos_equal (a: skel_method->in_args, b: slim_method->in_args);
2624 assert_arg_infos_equal (a: skel_method->out_args, b: slim_method->out_args);
2625 assert_annotations_equal (a: skel_method->annotations, b: slim_method->annotations);
2626 }
2627 g_assert_null (slim_info->methods[i]);
2628
2629 for (i = 0; skel_info->signals[i] != NULL; i++)
2630 {
2631 GDBusSignalInfo *skel_signal = skel_info->signals[i];
2632 GDBusSignalInfo *slim_signal = slim_info->signals[i];
2633
2634 g_assert_nonnull (slim_signal);
2635 g_assert_cmpstr (skel_signal->name, ==, slim_signal->name);
2636 assert_arg_infos_equal (a: skel_signal->args, b: slim_signal->args);
2637 assert_annotations_equal (a: skel_signal->annotations, b: slim_signal->annotations);
2638 }
2639 g_assert_null (slim_info->signals[i]);
2640
2641 for (i = 0; skel_info->properties[i] != NULL; i++)
2642 {
2643 GDBusPropertyInfo *skel_prop = skel_info->properties[i];
2644 GDBusPropertyInfo *slim_prop = slim_info->properties[i];
2645
2646 g_assert_nonnull (slim_prop);
2647
2648 g_assert_cmpstr (skel_prop->name, ==, slim_prop->name);
2649 g_assert_cmpstr (skel_prop->signature, ==, slim_prop->signature);
2650 g_assert_cmpuint (skel_prop->flags, ==, slim_prop->flags);
2651 assert_annotations_equal (a: skel_prop->annotations, b: slim_prop->annotations);
2652 }
2653 g_assert_null (slim_info->properties[i]);
2654
2655 assert_annotations_equal (a: skel_info->annotations, b: slim_info->annotations);
2656
2657 g_clear_object (&skel);
2658}
2659
2660/* ---------------------------------------------------------------------------------------------------- */
2661static gboolean
2662handle_hello_fd (FooiGenFDPassing *object,
2663 GDBusMethodInvocation *invocation,
2664 GUnixFDList *fd_list,
2665 const gchar *arg_greeting)
2666{
2667 foo_igen_fdpassing_complete_hello_fd (object, invocation, fd_list, arg_greeting);
2668 return G_DBUS_METHOD_INVOCATION_HANDLED;
2669}
2670
2671#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64
2672static gboolean
2673handle_no_annotation (FooiGenFDPassing *object,
2674 GDBusMethodInvocation *invocation,
2675 GUnixFDList *fd_list,
2676 GVariant *arg_greeting,
2677 const gchar *arg_greeting_locale)
2678{
2679 foo_igen_fdpassing_complete_no_annotation (object, invocation, fd_list, arg_greeting, arg_greeting_locale);
2680 return G_DBUS_METHOD_INVOCATION_HANDLED;
2681}
2682
2683static gboolean
2684handle_no_annotation_nested (FooiGenFDPassing *object,
2685 GDBusMethodInvocation *invocation,
2686 GUnixFDList *fd_list,
2687 GVariant *arg_files)
2688{
2689 foo_igen_fdpassing_complete_no_annotation_nested (object, invocation, fd_list);
2690 return G_DBUS_METHOD_INVOCATION_HANDLED;
2691}
2692#else
2693static gboolean
2694handle_no_annotation (FooiGenFDPassing *object,
2695 GDBusMethodInvocation *invocation,
2696 GVariant *arg_greeting,
2697 const gchar *arg_greeting_locale)
2698{
2699 foo_igen_fdpassing_complete_no_annotation (object, invocation, arg_greeting, arg_greeting_locale);
2700 return G_DBUS_METHOD_INVOCATION_HANDLED;
2701}
2702
2703static gboolean
2704handle_no_annotation_nested (FooiGenFDPassing *object,
2705 GDBusMethodInvocation *invocation,
2706 GVariant *arg_files)
2707{
2708 foo_igen_fdpassing_complete_no_annotation_nested (object, invocation);
2709 return G_DBUS_METHOD_INVOCATION_HANDLED;
2710}
2711#endif
2712
2713/* Test that generated code for methods includes GUnixFDList arguments
2714 * unconditionally if the method is explicitly annotated as C.UnixFD, and only
2715 * emits GUnixFDList arguments when there's merely an 'h' parameter if
2716 * --glib-min-required=2.64 or greater.
2717 */
2718static void
2719test_unix_fd_list (void)
2720{
2721 FooiGenFDPassingIface iface;
2722
2723 g_test_bug (bug_uri_snippet: "https://gitlab.gnome.org/GNOME/glib/issues/1726");
2724
2725 /* This method is explicitly annotated. */
2726 iface.handle_hello_fd = handle_hello_fd;
2727
2728 /* This one is not annotated; even though it's got an in and out 'h'
2729 * parameter, for backwards compatibility we cannot emit GUnixFDList
2730 * arguments unless --glib-min-required >= 2.64 was used.
2731 */
2732 iface.handle_no_annotation = handle_no_annotation;
2733
2734 /* This method has an 'h' inside a complex type. */
2735 iface.handle_no_annotation_nested = handle_no_annotation_nested;
2736
2737 (void) iface;
2738}
2739
2740/* ---------------------------------------------------------------------------------------------------- */
2741
2742int
2743main (int argc,
2744 char *argv[])
2745{
2746 g_test_init (argc: &argc, argv: &argv, NULL);
2747
2748 g_test_add_func (testpath: "/gdbus/codegen/annotations", test_func: test_annotations);
2749 g_test_add_func (testpath: "/gdbus/codegen/interface_stability", test_func: test_interface_stability);
2750 g_test_add_func (testpath: "/gdbus/codegen/object-manager", test_func: test_object_manager);
2751 g_test_add_func (testpath: "/gdbus/codegen/property-naming", test_func: test_property_naming);
2752 g_test_add_func (testpath: "/gdbus/codegen/autocleanups", test_func: test_autocleanups);
2753 g_test_add_func (testpath: "/gdbus/codegen/deprecations", test_func: test_deprecations);
2754 g_test_add_func (testpath: "/gdbus/codegen/standalone-interface-info", test_func: test_standalone_interface_info);
2755 g_test_add_func (testpath: "/gdbus/codegen/unix-fd-list", test_func: test_unix_fd_list);
2756
2757 return session_bus_run ();
2758}
2759

source code of gtk/subprojects/glib/gio/tests/gdbus-test-codegen.c