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 | |
45 | static guint |
46 | count_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 | */ |
60 | static void |
61 | test_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 | |
100 | static gboolean |
101 | on_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 | |
113 | static gboolean |
114 | on_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 | |
158 | static gboolean |
159 | on_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 | |
198 | static gboolean |
199 | on_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 | |
215 | static gboolean |
216 | on_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 | |
231 | static gboolean |
232 | on_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 | |
253 | static gboolean |
254 | on_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 | |
309 | static gboolean |
310 | my_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 | |
347 | static gboolean |
348 | my_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 | |
386 | static gboolean |
387 | on_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 | |
395 | static gboolean |
396 | on_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 | |
404 | static gboolean |
405 | on_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 | |
415 | static gboolean |
416 | on_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 | |
429 | static GThread *method_handler_thread = NULL; |
430 | |
431 | static FooiGenBar *exported_bar_object = NULL; |
432 | static FooiGenBat *exported_bat_object = NULL; |
433 | static FooiGenAuthorize *exported_authorize_object = NULL; |
434 | static GDBusObjectSkeleton *authorize_enclosing_object = NULL; |
435 | static FooiGenMethodThreads *exported_thread_object_1 = NULL; |
436 | static FooiGenMethodThreads *exported_thread_object_2 = NULL; |
437 | |
438 | static void |
439 | unexport_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 | |
448 | static void |
449 | on_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 | |
590 | static gpointer check_proxies_in_thread (gpointer user_data); |
591 | |
592 | static void |
593 | on_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 | |
602 | static void |
603 | on_name_lost (GDBusConnection *connection, |
604 | const gchar *name, |
605 | gpointer user_data) |
606 | { |
607 | g_assert_not_reached (); |
608 | } |
609 | |
610 | /* ---------------------------------------------------------------------------------------------------- */ |
611 | |
612 | typedef 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 | |
623 | static void |
624 | on_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 | |
633 | static void |
634 | on_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 | |
643 | static void |
644 | on_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 | |
673 | static void |
674 | on_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 | |
695 | static void |
696 | on_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 | |
712 | static void |
713 | check_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 | |
1130 | static void |
1131 | on_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 | |
1152 | static void |
1153 | check_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 | |
1224 | static void |
1225 | check_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 | |
1265 | static GThread * |
1266 | get_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 | |
1289 | static void |
1290 | check_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 | |
1303 | static gpointer |
1304 | check_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 | |
1396 | typedef struct |
1397 | { |
1398 | gchar *xml; |
1399 | GMainLoop *loop; |
1400 | } IntrospectData; |
1401 | |
1402 | static void |
1403 | introspect_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 | |
1423 | static GDBusNodeInfo * |
1424 | introspect (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 | |
1463 | static guint |
1464 | count_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 | |
1472 | static guint |
1473 | count_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 | |
1481 | static guint |
1482 | has_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 | |
1496 | typedef struct { |
1497 | GMainLoop *loop; |
1498 | GVariant *result; |
1499 | } OMGetManagedObjectsData; |
1500 | |
1501 | static void |
1502 | om_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 | |
1518 | static void |
1519 | om_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 | |
1550 | typedef 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 | |
1561 | static gint |
1562 | my_pstrcmp (const gchar **a, const gchar **b) |
1563 | { |
1564 | return g_strcmp0 (str1: *a, str2: *b); |
1565 | } |
1566 | |
1567 | static void |
1568 | om_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 | |
1616 | static void |
1617 | om_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 | |
1665 | static void |
1666 | om_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 | |
1775 | static GAsyncResult *om_res = NULL; |
1776 | |
1777 | static void |
1778 | om_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 | |
1787 | static void |
1788 | on_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 | |
1796 | static void |
1797 | on_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 | |
1805 | static void |
1806 | on_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 | |
1822 | static void |
1823 | on_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 | |
1837 | static void |
1838 | property_changed (GObject *object, |
1839 | GParamSpec *pspec, |
1840 | gpointer user_data) |
1841 | { |
1842 | gboolean *changed = user_data; |
1843 | |
1844 | *changed = TRUE; |
1845 | } |
1846 | |
1847 | static void |
1848 | om_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 | |
1910 | static void |
1911 | check_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 | |
2382 | static void |
2383 | test_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 | |
2415 | extern gpointer name_forcing_1; |
2416 | extern gpointer name_forcing_2; |
2417 | extern gpointer name_forcing_3; |
2418 | extern gpointer name_forcing_4; |
2419 | extern gpointer name_forcing_5; |
2420 | extern gpointer name_forcing_6; |
2421 | extern gpointer name_forcing_7; |
2422 | gpointer name_forcing_1 = foo_igen_rocket123_get_type; |
2423 | gpointer name_forcing_2 = foo_igen_rocket123_call_ignite_xyz; |
2424 | gpointer name_forcing_3 = foo_igen_rocket123_emit_exploded_xyz; |
2425 | gpointer name_forcing_4 = foo_igen_rocket123_get_speed_xyz; |
2426 | gpointer name_forcing_5 = foo_igen_test_ugly_case_interface_call_get_iscsi_servers; |
2427 | gpointer name_forcing_6 = foo_igen_test_ugly_case_interface_emit_servers_updated_now; |
2428 | gpointer 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 | |
2436 | static void |
2437 | test_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 | |
2463 | static void |
2464 | test_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 | |
2486 | static void |
2487 | test_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 | |
2525 | static void |
2526 | test_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 | |
2558 | static void |
2559 | assert_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 | |
2580 | static void |
2581 | assert_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 | */ |
2606 | static void |
2607 | test_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 | /* ---------------------------------------------------------------------------------------------------- */ |
2661 | static gboolean |
2662 | handle_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 |
2672 | static gboolean |
2673 | handle_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 | |
2683 | static gboolean |
2684 | handle_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 |
2693 | static gboolean |
2694 | handle_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 | |
2703 | static gboolean |
2704 | handle_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 | */ |
2718 | static void |
2719 | test_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 | |
2742 | int |
2743 | main (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 | |