GDBus: Support Ugly_Case and use org.gtk.GDBus.C.Name since it's C-only
[platform/upstream/glib.git] / gio / tests / gdbus-test-codegen.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2008-2011 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 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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include <gio/gio.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include "gdbus-tests.h"
29
30 #include "gdbus-test-codegen-generated.h"
31
32 /* ---------------------------------------------------------------------------------------------------- */
33
34 static guint
35 count_annotations (GDBusAnnotationInfo **annotations)
36 {
37   guint ret;
38   ret = 0;
39   while (annotations != NULL && annotations[ret] != NULL)
40     ret++;
41   return ret;
42 }
43
44 /* checks that
45  *
46  *  - non-internal annotations are written out correctly; and
47  *  - injection via --annotation --key --value works
48  */
49 static void
50 test_annotations (void)
51 {
52   GDBusInterfaceInfo *iface;
53   GDBusMethodInfo *method;
54   GDBusSignalInfo *signal;
55   GDBusPropertyInfo *property;
56
57   iface = foo_bar_interface_info ();
58   g_assert (iface != NULL);
59
60   /* see Makefile.am for where these annotations are injected */
61   g_assert_cmpint (count_annotations (iface->annotations), ==, 1);
62   g_assert_cmpstr (g_dbus_annotation_info_lookup (iface->annotations, "Key1"), ==, "Value1");
63
64   method = g_dbus_interface_info_lookup_method (iface, "HelloWorld");
65   g_assert (method != NULL);
66   g_assert_cmpint (count_annotations (method->annotations), ==, 2);
67   g_assert_cmpstr (g_dbus_annotation_info_lookup (method->annotations, "ExistingAnnotation"), ==, "blah");
68   g_assert_cmpstr (g_dbus_annotation_info_lookup (method->annotations, "Key3"), ==, "Value3");
69
70   signal = g_dbus_interface_info_lookup_signal (iface, "TestSignal");
71   g_assert (signal != NULL);
72   g_assert_cmpint (count_annotations (signal->annotations), ==, 1);
73   g_assert_cmpstr (g_dbus_annotation_info_lookup (signal->annotations, "Key4"), ==, "Value4");
74   g_assert_cmpstr (g_dbus_annotation_info_lookup (signal->args[1]->annotations, "Key8"), ==, "Value8");
75
76   property = g_dbus_interface_info_lookup_property (iface, "ay");
77   g_assert (property != NULL);
78   g_assert_cmpint (count_annotations (property->annotations), ==, 1);
79   g_assert_cmpstr (g_dbus_annotation_info_lookup (property->annotations, "Key5"), ==, "Value5");
80
81   method = g_dbus_interface_info_lookup_method (iface, "TestPrimitiveTypes");
82   g_assert (method != NULL);
83   g_assert_cmpstr (g_dbus_annotation_info_lookup (method->in_args[4]->annotations, "Key6"), ==, "Value6");
84   g_assert_cmpstr (g_dbus_annotation_info_lookup (method->out_args[5]->annotations, "Key7"), ==, "Value7");
85 }
86
87 /* ---------------------------------------------------------------------------------------------------- */
88
89 static gboolean
90 on_handle_hello_world (FooBar                 *object,
91                        GDBusMethodInvocation  *invocation,
92                        const gchar            *greeting,
93                        gpointer                user_data)
94 {
95   gchar *response;
96   response = g_strdup_printf ("Word! You said `%s'. I'm Skeleton, btw!", greeting);
97   foo_bar_complete_hello_world (object, invocation, response);
98   g_free (response);
99   return TRUE;
100 }
101
102 static gboolean
103 on_handle_test_primitive_types (FooBar                *object,
104                                 GDBusMethodInvocation *invocation,
105                                 guchar                 val_byte,
106                                 gboolean               val_boolean,
107                                 gint16                 val_int16,
108                                 guint16                val_uint16,
109                                 gint                   val_int32,
110                                 guint                  val_uint32,
111                                 gint64                 val_int64,
112                                 guint64                val_uint64,
113                                 gdouble                val_double,
114                                 const gchar           *val_string,
115                                 const gchar           *val_objpath,
116                                 const gchar           *val_signature,
117                                 const gchar           *val_bytestring,
118                                 gpointer               user_data)
119 {
120   gchar *s1;
121   gchar *s2;
122   gchar *s3;
123   s1 = g_strdup_printf ("Word! You said `%s'. Rock'n'roll!", val_string);
124   s2 = g_strdup_printf ("/modified%s", val_objpath);
125   s3 = g_strdup_printf ("assgit%s", val_signature);
126   foo_bar_complete_test_primitive_types (object,
127                                          invocation,
128                                          10 + val_byte,
129                                          !val_boolean,
130                                          100 + val_int16,
131                                          1000 + val_uint16,
132                                          10000 + val_int32,
133                                          100000 + val_uint32,
134                                          1000000 + val_int64,
135                                          10000000 + val_uint64,
136                                          val_double / G_PI,
137                                          s1,
138                                          s2,
139                                          s3,
140                                          "bytestring!\xff");
141   g_free (s1);
142   g_free (s2);
143   g_free (s3);
144   return TRUE;
145 }
146
147 static gboolean
148 on_handle_test_non_primitive_types (FooBar                *object,
149                                     GDBusMethodInvocation *invocation,
150                                     GVariant              *dict_s_to_s,
151                                     GVariant              *dict_s_to_pairs,
152                                     GVariant              *a_struct,
153                                     const gchar* const    *array_of_strings,
154                                     GVariant              *array_of_objpaths,
155                                     GVariant              *array_of_signatures,
156                                     const gchar* const    *array_of_bytestrings,
157                                     gpointer               user_data)
158 {
159   gchar *s;
160   GString *str;
161   str = g_string_new (NULL);
162   s = g_variant_print (dict_s_to_s, TRUE); g_string_append (str, s); g_free (s);
163   s = g_variant_print (dict_s_to_pairs, TRUE); g_string_append (str, s); g_free (s);
164   s = g_variant_print (a_struct, TRUE); g_string_append (str, s); g_free (s);
165   s = g_strjoinv (", ", (gchar **) array_of_strings);
166   g_string_append_printf (str, "array_of_strings: [%s] ", s);
167   g_free (s);
168   s = g_variant_print (array_of_objpaths, TRUE);
169   g_string_append_printf (str, "array_of_objpaths: %s ", s);
170   g_free (s);
171   s = g_variant_print (array_of_objpaths, TRUE);
172   g_string_append_printf (str, "array_of_signatures: %s ", s);
173   g_free (s);
174   s = g_strjoinv (", ", (gchar **) array_of_bytestrings);
175   g_string_append_printf (str, "array_of_bytestrings: [%s] ", s);
176   g_free (s);
177   foo_bar_complete_test_non_primitive_types (object, invocation, str->str);
178   g_string_free (str, TRUE);
179   return TRUE;
180 }
181
182 static gboolean
183 on_handle_request_signal_emission (FooBar                 *object,
184                                    GDBusMethodInvocation  *invocation,
185                                    gint                    which_one,
186                                    gpointer                user_data)
187 {
188   if (which_one == 0)
189     {
190       const gchar *a_strv[] = {"foo", "bar", NULL};
191       const gchar *a_bytestring_array[] = {"foo\xff", "bar\xff", NULL};
192       GVariant *a_variant = g_variant_new_parsed ("{'first': (42, 42), 'second': (43, 43)}");
193       foo_bar_emit_test_signal (object, 43, a_strv, a_bytestring_array, a_variant); /* consumes a_variant */
194       foo_bar_complete_request_signal_emission (object, invocation);
195     }
196   return TRUE;
197 }
198
199 static gboolean
200 on_handle_request_multi_property_mods (FooBar                 *object,
201                                        GDBusMethodInvocation  *invocation,
202                                        gpointer                user_data)
203 {
204   foo_bar_set_y (object, foo_bar_get_y (object) + 1);
205   foo_bar_set_i (object, foo_bar_get_i (object) + 1);
206   foo_bar_set_y (object, foo_bar_get_y (object) + 1);
207   foo_bar_set_i (object, foo_bar_get_i (object) + 1);
208   g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (object));
209   foo_bar_set_y (object, foo_bar_get_y (object) + 1);
210   foo_bar_set_i (object, foo_bar_get_i (object) + 1);
211   foo_bar_complete_request_multi_property_mods (object, invocation);
212   return TRUE;
213 }
214
215 /* ---------------------------------------------------------------------------------------------------- */
216
217 static gboolean
218 on_handle_force_method (FooBat                 *object,
219                         GDBusMethodInvocation  *invocation,
220                         GVariant               *force_in_i,
221                         GVariant               *force_in_s,
222                         GVariant               *force_in_ay,
223                         GVariant               *force_in_struct,
224                         gpointer                user_data)
225 {
226   GVariant *ret_i;
227   GVariant *ret_s;
228   GVariant *ret_ay;
229   GVariant *ret_struct;
230   gint32 val;
231   gchar *s;
232
233   ret_i = g_variant_new_int32 (g_variant_get_int32 (force_in_i) + 10);
234   s = g_strdup_printf ("%s_foo", g_variant_get_string (force_in_s, NULL));
235   ret_s = g_variant_new_string (s);
236   g_free (s);
237   s = g_strdup_printf ("%s_foo\xff", g_variant_get_bytestring (force_in_ay));
238   ret_ay = g_variant_new_bytestring (s);
239   g_free (s);
240
241   g_variant_get (force_in_struct, "(i)", &val);
242   ret_struct = g_variant_new ("(i)", val + 10);
243
244   g_variant_ref_sink (ret_i);
245   g_variant_ref_sink (ret_s);
246   g_variant_ref_sink (ret_ay);
247   g_variant_ref_sink (ret_struct);
248
249   foo_bat_emit_force_signal (object,
250                              ret_i,
251                              ret_s,
252                              ret_ay,
253                              ret_struct);
254
255   foo_bat_complete_force_method (object,
256                                  invocation,
257                                  ret_i,
258                                  ret_s,
259                                  ret_ay,
260                                  ret_struct);
261
262   g_variant_unref (ret_i);
263   g_variant_unref (ret_s);
264   g_variant_unref (ret_ay);
265   g_variant_unref (ret_struct);
266
267   return TRUE;
268 }
269
270
271 /* ---------------------------------------------------------------------------------------------------- */
272
273 static gboolean
274 my_g_authorize_method_handler (GDBusInterfaceSkeleton *interface,
275                                GDBusMethodInvocation  *invocation,
276                                gpointer                user_data)
277 {
278   const gchar *method_name;
279   gboolean authorized;
280
281   authorized = FALSE;
282
283   method_name = g_dbus_method_invocation_get_method_name (invocation);
284   if (g_strcmp0 (method_name, "CheckNotAuthorized") == 0)
285     {
286       authorized = FALSE;
287     }
288   else if (g_strcmp0 (method_name, "CheckAuthorized") == 0)
289     {
290       authorized = TRUE;
291     }
292   else if (g_strcmp0 (method_name, "CheckNotAuthorizedFromObject") == 0)
293     {
294       authorized = TRUE;
295     }
296   else
297     {
298       g_assert_not_reached ();
299     }
300
301   if (!authorized)
302     {
303       g_dbus_method_invocation_return_error (invocation,
304                                              G_IO_ERROR,
305                                              G_IO_ERROR_PERMISSION_DENIED,
306                                              "not authorized...");
307     }
308   return authorized;
309 }
310
311 static gboolean
312 my_object_authorize_method_handler (GDBusObjectSkeleton     *object,
313                                     GDBusInterfaceSkeleton  *interface,
314                                     GDBusMethodInvocation   *invocation,
315                                     gpointer                 user_data)
316 {
317   const gchar *method_name;
318   gboolean authorized;
319
320   authorized = FALSE;
321
322   method_name = g_dbus_method_invocation_get_method_name (invocation);
323   if (g_strcmp0 (method_name, "CheckNotAuthorized") == 0)
324     {
325       authorized = TRUE;
326     }
327   else if (g_strcmp0 (method_name, "CheckAuthorized") == 0)
328     {
329       authorized = TRUE;
330     }
331   else if (g_strcmp0 (method_name, "CheckNotAuthorizedFromObject") == 0)
332     {
333       authorized = FALSE;
334     }
335   else
336     {
337       g_assert_not_reached ();
338     }
339
340   if (!authorized)
341     {
342       g_dbus_method_invocation_return_error (invocation,
343                                              G_IO_ERROR,
344                                              G_IO_ERROR_PENDING,
345                                              "not authorized (from object)...");
346     }
347   return authorized;
348 }
349
350 static gboolean
351 on_handle_check_not_authorized (FooAuthorize           *object,
352                                 GDBusMethodInvocation  *invocation,
353                                 gpointer                user_data)
354 {
355   foo_authorize_complete_check_not_authorized (object, invocation);
356   return TRUE;
357 }
358
359 static gboolean
360 on_handle_check_authorized (FooAuthorize           *object,
361                             GDBusMethodInvocation  *invocation,
362                             gpointer                user_data)
363 {
364   foo_authorize_complete_check_authorized (object, invocation);
365   return TRUE;
366 }
367
368 static gboolean
369 on_handle_check_not_authorized_from_object (FooAuthorize           *object,
370                                             GDBusMethodInvocation  *invocation,
371                                             gpointer                user_data)
372 {
373   foo_authorize_complete_check_not_authorized_from_object (object, invocation);
374   return TRUE;
375 }
376
377 /* ---------------------------------------------------------------------------------------------------- */
378
379 static gboolean
380 on_handle_get_self (FooMethodThreads       *object,
381                     GDBusMethodInvocation  *invocation,
382                     gpointer                user_data)
383 {
384   gchar *s;
385   s = g_strdup_printf ("%p", g_thread_self ());
386   foo_method_threads_complete_get_self (object, invocation, s);
387   g_free (s);
388   return TRUE;
389 }
390
391 /* ---------------------------------------------------------------------------------------------------- */
392
393 static GThread *method_handler_thread = NULL;
394
395 static FooBar *exported_bar_object = NULL;
396 static FooBat *exported_bat_object = NULL;
397 static FooAuthorize *exported_authorize_object = NULL;
398 static GDBusObjectSkeleton *authorize_enclosing_object = NULL;
399 static FooMethodThreads *exported_thread_object_1 = NULL;
400 static FooMethodThreads *exported_thread_object_2 = NULL;
401
402 static void
403 on_bus_acquired (GDBusConnection *connection,
404                  const gchar     *name,
405                  gpointer         user_data)
406 {
407   GError *error;
408
409   /* Test that we can export an object using the generated
410    * FooBarSkeleton subclass. Notes:
411    *
412    * 1. We handle methods by simply connecting to the appropriate
413    * GObject signal.
414    *
415    * 2. Property storage is taken care of by the class; we can
416    *    use g_object_get()/g_object_set() (and the generated
417    *    C bindings at will)
418    */
419   error = NULL;
420   exported_bar_object = foo_bar_skeleton_new ();
421   foo_bar_set_ay (exported_bar_object, "ABCabc");
422   foo_bar_set_y (exported_bar_object, 42);
423   foo_bar_set_d (exported_bar_object, 43.0);
424   foo_bar_set_finally_normal_name (exported_bar_object, "There aint no place like home");
425   foo_bar_set_writeonly_property (exported_bar_object, "Mr. Burns");
426
427   /* The following works because it's on the Skeleton object - it will
428    * fail (at run-time) on a Proxy (see on_proxy_appeared() below)
429    */
430   foo_bar_set_readonly_property (exported_bar_object, "blah");
431   g_assert_cmpstr (foo_bar_get_writeonly_property (exported_bar_object), ==, "Mr. Burns");
432
433   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_bar_object),
434                                     connection,
435                                     "/bar",
436                                     &error);
437   g_assert_no_error (error);
438   g_signal_connect (exported_bar_object,
439                     "handle-hello-world",
440                     G_CALLBACK (on_handle_hello_world),
441                     NULL);
442   g_signal_connect (exported_bar_object,
443                     "handle-test-primitive-types",
444                     G_CALLBACK (on_handle_test_primitive_types),
445                     NULL);
446   g_signal_connect (exported_bar_object,
447                     "handle-test-non-primitive-types",
448                     G_CALLBACK (on_handle_test_non_primitive_types),
449                     NULL);
450   g_signal_connect (exported_bar_object,
451                     "handle-request-signal-emission",
452                     G_CALLBACK (on_handle_request_signal_emission),
453                     NULL);
454   g_signal_connect (exported_bar_object,
455                     "handle-request-multi-property-mods",
456                     G_CALLBACK (on_handle_request_multi_property_mods),
457                     NULL);
458
459   exported_bat_object = foo_bat_skeleton_new ();
460   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_bat_object),
461                                     connection,
462                                     "/bat",
463                                     &error);
464   g_assert_no_error (error);
465   g_signal_connect (exported_bat_object,
466                     "handle-force-method",
467                     G_CALLBACK (on_handle_force_method),
468                     NULL);
469   g_object_set (exported_bat_object,
470                 "force-i", g_variant_new_int32 (43),
471                 "force-s", g_variant_new_string ("prop string"),
472                 "force-ay", g_variant_new_bytestring ("prop bytestring\xff"),
473                 "force-struct", g_variant_new ("(i)", 4300),
474                 NULL);
475
476   authorize_enclosing_object = g_dbus_object_skeleton_new ("/authorize");
477   g_signal_connect (authorize_enclosing_object,
478                     "authorize-method",
479                     G_CALLBACK (my_object_authorize_method_handler),
480                     NULL);
481   exported_authorize_object = foo_authorize_skeleton_new ();
482   g_dbus_object_skeleton_add_interface (authorize_enclosing_object,
483                                         G_DBUS_INTERFACE_SKELETON (exported_authorize_object));
484   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_authorize_object),
485                                     connection,
486                                     "/authorize",
487                                     &error);
488   g_assert_no_error (error);
489   g_signal_connect (exported_authorize_object,
490                     "g-authorize-method",
491                     G_CALLBACK (my_g_authorize_method_handler),
492                     NULL);
493   g_signal_connect (exported_authorize_object,
494                     "handle-check-not-authorized",
495                     G_CALLBACK (on_handle_check_not_authorized),
496                     NULL);
497   g_signal_connect (exported_authorize_object,
498                     "handle-check-authorized",
499                     G_CALLBACK (on_handle_check_authorized),
500                     NULL);
501   g_signal_connect (exported_authorize_object,
502                     "handle-check-not-authorized-from-object",
503                     G_CALLBACK (on_handle_check_not_authorized_from_object),
504                     NULL);
505
506
507   /* only object 1 has the G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD flag set */
508   exported_thread_object_1 = foo_method_threads_skeleton_new ();
509   g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1),
510                                        G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
511   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1),
512                                     connection,
513                                     "/method_threads_1",
514                                     &error);
515   g_assert_no_error (error);
516   g_signal_connect (exported_thread_object_1,
517                     "handle-get-self",
518                     G_CALLBACK (on_handle_get_self),
519                     NULL);
520
521   exported_thread_object_2 = foo_method_threads_skeleton_new ();
522   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_thread_object_2),
523                                     connection,
524                                     "/method_threads_2",
525                                     &error);
526   g_assert_no_error (error);
527   g_signal_connect (exported_thread_object_2,
528                     "handle-get-self",
529                     G_CALLBACK (on_handle_get_self),
530                     NULL);
531
532   method_handler_thread = g_thread_self ();
533 }
534
535 static gpointer check_proxies_in_thread (gpointer user_data);
536
537 static void
538 on_name_acquired (GDBusConnection *connection,
539                   const gchar     *name,
540                   gpointer         user_data)
541 {
542   GMainLoop *loop = user_data;
543
544   g_thread_create (check_proxies_in_thread,
545                    loop,
546                    TRUE,
547                    NULL);
548 }
549
550 static void
551 on_name_lost (GDBusConnection *connection,
552               const gchar     *name,
553               gpointer         user_data)
554 {
555   g_assert_not_reached ();
556 }
557
558 /* ---------------------------------------------------------------------------------------------------- */
559
560 typedef struct
561 {
562   GMainLoop *thread_loop;
563   gint initial_y;
564   gint initial_i;
565   guint num_g_properties_changed;
566   gboolean received_test_signal;
567   guint num_notify_u;
568   guint num_notify_n;
569 } ClientData;
570
571 static void
572 on_notify_u (GObject    *object,
573            GParamSpec *pspec,
574            gpointer    user_data)
575 {
576   ClientData *data = user_data;
577   g_assert_cmpstr (pspec->name, ==, "u");
578   data->num_notify_u += 1;
579 }
580
581 static void
582 on_notify_n (GObject    *object,
583              GParamSpec *pspec,
584              gpointer    user_data)
585 {
586   ClientData *data = user_data;
587   g_assert_cmpstr (pspec->name, ==, "n");
588   data->num_notify_n += 1;
589 }
590
591 static void
592 on_g_properties_changed (GDBusProxy          *_proxy,
593                          GVariant            *changed_properties,
594                          const gchar* const  *invalidated_properties,
595                          gpointer             user_data)
596 {
597   ClientData *data = user_data;
598   FooBar *proxy = FOO_BAR (_proxy);
599
600   g_assert_cmpint (g_variant_n_children (changed_properties), ==, 2);
601
602   if (data->num_g_properties_changed == 0)
603     {
604       g_assert_cmpint (data->initial_y, ==, foo_bar_get_y (proxy) - 2);
605       g_assert_cmpint (data->initial_i, ==, foo_bar_get_i (proxy) - 2);
606     }
607   else if (data->num_g_properties_changed == 1)
608     {
609       g_assert_cmpint (data->initial_y, ==, foo_bar_get_y (proxy) - 3);
610       g_assert_cmpint (data->initial_i, ==, foo_bar_get_i (proxy) - 3);
611     }
612   else
613     g_assert_not_reached ();
614
615   data->num_g_properties_changed++;
616
617   if (data->num_g_properties_changed == 2)
618     g_main_loop_quit (data->thread_loop);
619 }
620
621 static void
622 on_test_signal (FooBar              *proxy,
623                 gint                 val_int32,
624                 const gchar* const  *array_of_strings,
625                 const gchar* const  *array_of_bytestrings,
626                 GVariant            *dict_s_to_pairs,
627                 gpointer             user_data)
628 {
629   ClientData *data = user_data;
630
631   g_assert_cmpint (val_int32, ==, 43);
632   g_assert_cmpstr (array_of_strings[0], ==, "foo");
633   g_assert_cmpstr (array_of_strings[1], ==, "bar");
634   g_assert (array_of_strings[2] == NULL);
635   g_assert_cmpstr (array_of_bytestrings[0], ==, "foo\xff");
636   g_assert_cmpstr (array_of_bytestrings[1], ==, "bar\xff");
637   g_assert (array_of_bytestrings[2] == NULL);
638
639   data->received_test_signal = TRUE;
640   g_main_loop_quit (data->thread_loop);
641 }
642
643 static void
644 check_bar_proxy (FooBar    *proxy,
645                  GMainLoop *thread_loop)
646 {
647   guchar ret_val_byte;
648   gboolean ret_val_boolean;
649   gint16 ret_val_int16;
650   guint16 ret_val_uint16;
651   gint ret_val_int32;
652   guint ret_val_uint32;
653   gint64 ret_val_int64;
654   guint64 ret_val_uint64;
655   gdouble ret_val_double;
656   gchar *ret_val_string;
657   gchar *ret_val_objpath;
658   gchar *ret_val_signature;
659   gchar *ret_val_bytestring;
660   gboolean ret;
661   GError *error;
662   ClientData *data;
663   guchar val_y;
664   gboolean val_b;
665   gint16 val_n;
666   guint16 val_q;
667   gint val_i;
668   guint val_u;
669   gint64 val_x;
670   guint64 val_t;
671   gdouble val_d;
672   gchar *val_s;
673   gchar *val_o;
674   gchar *val_g;
675   gchar *val_ay;
676   gchar **val_as;
677   GVariant *val_ao;
678   GVariant *val_ag;
679   gint32 val_unset_i;
680   gdouble val_unset_d;
681   gchar *val_unset_s;
682   gchar *val_unset_o;
683   gchar *val_unset_g;
684   gchar *val_unset_ay;
685   gchar **val_unset_as;
686   GVariant *val_unset_ao;
687   GVariant *val_unset_ag;
688   GVariant *val_unset_struct;
689   gchar *val_finally_normal_name;
690   GVariant *v;
691   gchar *s;
692
693   data = g_new0 (ClientData, 1);
694   data->thread_loop = thread_loop;
695
696   v = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), "y");
697   g_assert (v != NULL);
698   g_variant_unref (v);
699
700   /* set empty values to non-empty */
701   val_unset_i = 42;
702   val_unset_d = 42.0;
703   val_unset_s = "42";
704   val_unset_o = "42";
705   val_unset_g = "42";
706   val_unset_ay = NULL;
707   val_unset_as = NULL;
708   val_unset_ao = NULL;
709   val_unset_ag = NULL;
710   val_unset_struct = NULL;
711   /* check properties */
712   g_object_get (proxy,
713                 "y", &val_y,
714                 "b", &val_b,
715                 "n", &val_n,
716                 "q", &val_q,
717                 "i", &val_i,
718                 "u", &val_u,
719                 "x", &val_x,
720                 "t", &val_t,
721                 "d", &val_d,
722                 "s", &val_s,
723                 "o", &val_o,
724                 "g", &val_g,
725                 "ay", &val_ay,
726                 "as", &val_as,
727                 "ao", &val_ao,
728                 "ag", &val_ag,
729                 "unset_i", &val_unset_i,
730                 "unset_d", &val_unset_d,
731                 "unset_s", &val_unset_s,
732                 "unset_o", &val_unset_o,
733                 "unset_g", &val_unset_g,
734                 "unset_ay", &val_unset_ay,
735                 "unset_as", &val_unset_as,
736                 "unset_ao", &val_unset_ao,
737                 "unset_ag", &val_unset_ag,
738                 "unset_struct", &val_unset_struct,
739                 "finally-normal-name", &val_finally_normal_name,
740                 NULL);
741   g_assert_cmpint (val_y, ==, 42);
742   g_assert_cmpstr (val_finally_normal_name, ==, "There aint no place like home");
743   g_free (val_s);
744   g_free (val_o);
745   g_free (val_g);
746   g_assert_cmpstr (val_ay, ==, "ABCabc");
747   g_free (val_ay);
748   g_strfreev (val_as);
749   g_variant_unref (val_ao);
750   g_variant_unref (val_ag);
751   g_free (val_finally_normal_name);
752   /* check empty values */
753   g_assert_cmpint (val_unset_i, ==, 0);
754   g_assert_cmpfloat (val_unset_d, ==, 0.0);
755   g_assert_cmpstr (val_unset_s, ==, "");
756   g_assert_cmpstr (val_unset_o, ==, "/");
757   g_assert_cmpstr (val_unset_g, ==, "");
758   g_free (val_unset_s);
759   g_free (val_unset_o);
760   g_free (val_unset_g);
761   g_assert_cmpstr (val_unset_ay, ==, "");
762   g_assert (val_unset_as[0] == NULL);
763   g_assert (g_variant_is_of_type (val_unset_ao, G_VARIANT_TYPE ("ao")));
764   g_assert (g_variant_is_of_type (val_unset_ag, G_VARIANT_TYPE ("ag")));
765   g_assert (g_variant_is_of_type (val_unset_struct, G_VARIANT_TYPE ("(idsogayasaoag)")));
766   s = g_variant_print (val_unset_struct, TRUE);
767   g_assert_cmpstr (s, ==, "(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])");
768   g_free (s);
769   g_free (val_unset_ay);
770   g_strfreev (val_unset_as);
771   g_variant_unref (val_unset_ao);
772   g_variant_unref (val_unset_ag);
773   g_variant_unref (val_unset_struct);
774
775   /* Try setting a property. This causes the generated glue to invoke
776    * the org.fd.DBus.Properties.Set() method asynchronously. So we
777    * have to wait for properties-changed...
778    */
779   foo_bar_set_finally_normal_name (proxy, "foo!");
780   _g_assert_property_notify (proxy, "finally-normal-name");
781   g_assert_cmpstr (foo_bar_get_finally_normal_name (proxy), ==, "foo!");
782
783   /* Try setting properties that requires memory management. This
784    * is to exercise the paths that frees the references.
785    */
786   const gchar *array_of_strings[3] = {"one", "two", NULL};
787   const gchar *array_of_bytestrings[3] = {"one\xff", "two\xff", NULL};
788   g_object_set (proxy,
789                 "s", "a string",
790                 "o", "/a/path",
791                 "g", "asig",
792                 "ay", g_variant_new_parsed ("[byte 0x65, 0x67]"),
793                 "as", array_of_strings,
794                 "ao", g_variant_new_parsed ("[@o '/one', '/one/two']"),
795                 "ag", g_variant_new_parsed ("[@g 'ass', 'git']"),
796                 NULL);
797
798   error = NULL;
799   ret = foo_bar_call_test_primitive_types_sync (proxy,
800                                                 10,
801                                                 TRUE,
802                                                 11,
803                                                 12,
804                                                 13,
805                                                 14,
806                                                 15,
807                                                 16,
808                                                 17,
809                                                 "a string",
810                                                 "/a/path",
811                                                 "asig",
812                                                 "bytestring\xff",
813                                                 &ret_val_byte,
814                                                 &ret_val_boolean,
815                                                 &ret_val_int16,
816                                                 &ret_val_uint16,
817                                                 &ret_val_int32,
818                                                 &ret_val_uint32,
819                                                 &ret_val_int64,
820                                                 &ret_val_uint64,
821                                                 &ret_val_double,
822                                                 &ret_val_string,
823                                                 &ret_val_objpath,
824                                                 &ret_val_signature,
825                                                 &ret_val_bytestring,
826                                                 NULL, /* GCancellable */
827                                                 &error);
828   g_assert_no_error (error);
829   g_assert (ret);
830
831   error = NULL;
832   ret = foo_bar_call_test_non_primitive_types_sync (proxy,
833                                                     g_variant_new_parsed ("{'one': 'red',"
834                                                                           " 'two': 'blue'}"),
835                                                     g_variant_new_parsed ("{'first': (42, 42), "
836                                                                           "'second': (43, 43)}"),
837                                                     g_variant_new_parsed ("(42, 'foo', 'bar')"),
838                                                     array_of_strings,
839                                                     g_variant_new_parsed ("[@o '/one', '/one/two']"),
840                                                     g_variant_new_parsed ("[@g 'ass', 'git']"),
841                                                     array_of_bytestrings,
842                                                     &s,
843                                                     NULL, /* GCancellable */
844                                                     &error);
845
846   g_assert_no_error (error);
847   g_assert (ret);
848
849   /* Check that org.freedesktop.DBus.Error.UnknownMethod is returned on
850    * unimplemented methods.
851    */
852   error = NULL;
853   ret = foo_bar_call_unimplemented_method_sync (proxy, NULL /* GCancellable */, &error);
854   g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
855   g_error_free (error);
856   error = NULL;
857   g_assert (!ret);
858
859   g_signal_connect (proxy,
860                     "test-signal",
861                     G_CALLBACK (on_test_signal),
862                     data);
863   error = NULL;
864   ret = foo_bar_call_request_signal_emission_sync (proxy, 0, NULL, &error);
865   g_assert_no_error (error);
866   g_assert (ret);
867
868   g_assert (!data->received_test_signal);
869   g_main_loop_run (thread_loop);
870   g_assert (data->received_test_signal);
871
872   /* Try setting a property. This causes the generated glue to invoke
873    * the org.fd.DBus.Properties.Set() method asynchronously. So we
874    * have to wait for properties-changed...
875    */
876   foo_bar_set_finally_normal_name (proxy, "hey back!");
877   _g_assert_property_notify (proxy, "finally-normal-name");
878   g_assert_cmpstr (foo_bar_get_finally_normal_name (proxy), ==, "hey back!");
879
880   /* Check that grouping changes in idle works.
881    *
882    * See on_handle_request_multi_property_mods(). The server should
883    * emit exactly two PropertiesChanged signals each containing two
884    * properties.
885    *
886    * On the first reception, y and i should both be increased by
887    * two. On the the second reception, only by one. The signal handler
888    * checks this.
889    *
890    * This also checks that _drain_notify() works.
891    */
892   data->initial_y = foo_bar_get_y (proxy);
893   data->initial_i = foo_bar_get_i (proxy);
894   g_signal_connect (proxy,
895                     "g-properties-changed",
896                     G_CALLBACK (on_g_properties_changed),
897                     data);
898   error = NULL;
899   ret = foo_bar_call_request_multi_property_mods_sync (proxy, NULL, &error);
900   g_assert_no_error (error);
901   g_assert (ret);
902   g_main_loop_run (thread_loop);
903   g_assert_cmpint (data->num_g_properties_changed, ==, 2);
904   g_signal_handlers_disconnect_by_func (proxy,
905                                         G_CALLBACK (on_g_properties_changed),
906                                         data);
907
908   /* Check that we don't emit PropertiesChanged() if the property
909    * didn't change... we actually get two notifies.. one for the
910    * local set (without a value change) and one when receiving
911    * the PropertiesChanged() signal generated from the remote end.
912    */
913   g_assert_cmpint (data->num_notify_u, ==, 0);
914   g_signal_connect (proxy,
915                     "notify::u",
916                     G_CALLBACK (on_notify_u),
917                     data);
918   foo_bar_set_u (proxy, 1042);
919   g_assert_cmpint (data->num_notify_u, ==, 1);
920   g_assert_cmpint (foo_bar_get_u (proxy), ==, 0);
921   _g_assert_property_notify (proxy, "u");
922   g_assert_cmpint (foo_bar_get_u (proxy), ==, 1042);
923   g_assert_cmpint (data->num_notify_u, ==, 2);
924
925   /* Now change u again to the same value.. this will cause a
926    * local notify:: notify and the usual Properties.Set() call
927    *
928    * (Btw, why also the Set() call if the value in the cache is
929    * the same? Because someone else might have changed it
930    * in the mean time and we're just waiting to receive the
931    * PropertiesChanged() signal...)
932    *
933    * More tricky - how do we check for the *absence* of the
934    * notification that u changed? Simple: we change another
935    * property and wait for that PropertiesChanged() message
936    * to arrive.
937    */
938   foo_bar_set_u (proxy, 1042);
939   g_assert_cmpint (data->num_notify_u, ==, 3);
940
941   g_assert_cmpint (data->num_notify_n, ==, 0);
942   g_signal_connect (proxy,
943                     "notify::n",
944                     G_CALLBACK (on_notify_n),
945                     data);
946   foo_bar_set_n (proxy, 10042);
947   g_assert_cmpint (data->num_notify_n, ==, 1);
948   g_assert_cmpint (foo_bar_get_n (proxy), ==, 0);
949   _g_assert_property_notify (proxy, "n");
950   g_assert_cmpint (foo_bar_get_n (proxy), ==, 10042);
951   g_assert_cmpint (data->num_notify_n, ==, 2);
952
953   /* Checks that u didn't change at all */
954   g_assert_cmpint (data->num_notify_u, ==, 3);
955
956   /* cleanup */
957   g_free (data);
958 }
959
960 /* ---------------------------------------------------------------------------------------------------- */
961
962 static void
963 on_force_signal (FooBat    *proxy,
964                  GVariant  *force_i,
965                  GVariant  *force_s,
966                  GVariant  *force_ay,
967                  GVariant  *force_struct,
968                  gpointer   user_data)
969 {
970   gboolean *signal_received = user_data;
971   gint val;
972
973   g_assert (!(*signal_received));
974
975   g_assert_cmpint (g_variant_get_int32 (force_i), ==, 42 + 10);
976   g_assert_cmpstr (g_variant_get_string (force_s, NULL), ==, "a string_foo");
977   g_assert_cmpstr (g_variant_get_bytestring (force_ay), ==, "a bytestring\xff_foo\xff");
978   g_variant_get (force_struct, "(i)", &val);
979   g_assert_cmpint (val, ==, 4200 + 10);
980
981   *signal_received = TRUE;
982 }
983
984 static void
985 check_bat_proxy (FooBat *proxy,
986                  GMainLoop *thread_loop)
987 {
988   GError *error;
989   GVariant *ret_i;
990   GVariant *ret_s;
991   GVariant *ret_ay;
992   GVariant *ret_struct;
993   gint val;
994   gboolean force_signal_received;
995
996   /* --------------------------------------------------- */
997   /* Check type-mapping where we force use of a GVariant */
998   /* --------------------------------------------------- */
999
1000   /* check properties */
1001   g_object_get (proxy,
1002                 "force-i", &ret_i,
1003                 "force-s", &ret_s,
1004                 "force-ay", &ret_ay,
1005                 "force-struct", &ret_struct,
1006                 NULL);
1007   g_assert_cmpint (g_variant_get_int32 (ret_i), ==, 43);
1008   g_assert_cmpstr (g_variant_get_string (ret_s, NULL), ==, "prop string");
1009   g_assert_cmpstr (g_variant_get_bytestring (ret_ay), ==, "prop bytestring\xff");
1010   g_variant_get (ret_struct, "(i)", &val);
1011   g_assert_cmpint (val, ==, 4300);
1012   g_variant_unref (ret_i);
1013   g_variant_unref (ret_s);
1014   g_variant_unref (ret_ay);
1015   g_variant_unref (ret_struct);
1016
1017   /* check method and signal */
1018   force_signal_received = FALSE;
1019   g_signal_connect (proxy,
1020                     "force-signal",
1021                     G_CALLBACK (on_force_signal),
1022                     &force_signal_received);
1023
1024   error = NULL;
1025   foo_bat_call_force_method_sync (proxy,
1026                                   g_variant_new_int32 (42),
1027                                   g_variant_new_string ("a string"),
1028                                   g_variant_new_bytestring ("a bytestring\xff"),
1029                                   g_variant_new ("(i)", 4200),
1030                                   &ret_i,
1031                                   &ret_s,
1032                                   &ret_ay,
1033                                   &ret_struct,
1034                                   NULL, /* GCancellable* */
1035                                   &error);
1036   g_assert_no_error (error);
1037   g_assert_cmpint (g_variant_get_int32 (ret_i), ==, 42 + 10);
1038   g_assert_cmpstr (g_variant_get_string (ret_s, NULL), ==, "a string_foo");
1039   g_assert_cmpstr (g_variant_get_bytestring (ret_ay), ==, "a bytestring\xff_foo\xff");
1040   g_variant_get (ret_struct, "(i)", &val);
1041   g_assert_cmpint (val, ==, 4200 + 10);
1042   g_variant_unref (ret_i);
1043   g_variant_unref (ret_s);
1044   g_variant_unref (ret_ay);
1045   g_variant_unref (ret_struct);
1046   _g_assert_signal_received (proxy, "force-signal");
1047   g_assert (force_signal_received);
1048 }
1049
1050 /* ---------------------------------------------------------------------------------------------------- */
1051
1052 static void
1053 check_authorize_proxy (FooAuthorize *proxy,
1054                        GMainLoop *thread_loop)
1055 {
1056   GError *error;
1057   gboolean ret;
1058
1059   /* Check that g-authorize-method works as intended */
1060
1061   error = NULL;
1062   ret = foo_authorize_call_check_not_authorized_sync (proxy, NULL, &error);
1063   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
1064   g_error_free (error);
1065   g_assert (!ret);
1066
1067   error = NULL;
1068   ret = foo_authorize_call_check_authorized_sync (proxy, NULL, &error);
1069   g_assert_no_error (error);
1070   g_assert (ret);
1071
1072   error = NULL;
1073   ret = foo_authorize_call_check_not_authorized_from_object_sync (proxy, NULL, &error);
1074   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
1075   g_error_free (error);
1076   g_assert (!ret);
1077 }
1078
1079 /* ---------------------------------------------------------------------------------------------------- */
1080
1081 static GThread *
1082 get_self_via_proxy (FooMethodThreads *proxy_1)
1083 {
1084   GError *error;
1085   gchar *self_str;
1086   gboolean ret;
1087   gpointer self;
1088
1089   error = NULL;
1090   ret = foo_method_threads_call_get_self_sync (proxy_1, &self_str, NULL, &error);
1091   g_assert_no_error (error);
1092   g_assert (ret);
1093
1094   g_assert_cmpint (sscanf (self_str, "%p", &self), ==, 1);
1095
1096   g_free (self_str);
1097
1098   return self;
1099 }
1100
1101 static void
1102 check_thread_proxies (FooMethodThreads *proxy_1,
1103                       FooMethodThreads *proxy_2,
1104                       GMainLoop *thread_loop)
1105 {
1106   /* proxy_1 is indeed using threads so should never get the handler thread */
1107   g_assert (get_self_via_proxy (proxy_1) != method_handler_thread);
1108
1109   /* proxy_2 is not using threads so should get the handler thread */
1110   g_assert (get_self_via_proxy (proxy_2) == method_handler_thread);
1111 }
1112
1113 /* ---------------------------------------------------------------------------------------------------- */
1114
1115 static gpointer
1116 check_proxies_in_thread (gpointer user_data)
1117 {
1118   GMainLoop *loop = user_data;
1119   GMainContext *thread_context;
1120   GMainLoop *thread_loop;
1121   GError *error;
1122   FooBar *bar_proxy;
1123   FooBat *bat_proxy;
1124   FooAuthorize *authorize_proxy;
1125   FooMethodThreads *thread_proxy_1;
1126   FooMethodThreads *thread_proxy_2;
1127
1128   thread_context = g_main_context_new ();
1129   thread_loop = g_main_loop_new (thread_context, FALSE);
1130   g_main_context_push_thread_default (thread_context);
1131
1132   /* Check the object */
1133   error = NULL;
1134   bar_proxy = foo_bar_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1135                                               G_DBUS_PROXY_FLAGS_NONE,
1136                                               "org.gtk.GDBus.BindingsTool.Test",
1137                                               "/bar",
1138                                               NULL, /* GCancellable* */
1139                                               &error);
1140   check_bar_proxy (bar_proxy, thread_loop);
1141   g_assert_no_error (error);
1142   g_object_unref (bar_proxy);
1143
1144   error = NULL;
1145   bat_proxy = foo_bat_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1146                                               G_DBUS_PROXY_FLAGS_NONE,
1147                                               "org.gtk.GDBus.BindingsTool.Test",
1148                                               "/bat",
1149                                               NULL, /* GCancellable* */
1150                                               &error);
1151   check_bat_proxy (bat_proxy, thread_loop);
1152   g_assert_no_error (error);
1153   g_object_unref (bat_proxy);
1154
1155   error = NULL;
1156   authorize_proxy = foo_authorize_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1157                                                           G_DBUS_PROXY_FLAGS_NONE,
1158                                                           "org.gtk.GDBus.BindingsTool.Test",
1159                                                           "/authorize",
1160                                                           NULL, /* GCancellable* */
1161                                                           &error);
1162   check_authorize_proxy (authorize_proxy, thread_loop);
1163   g_assert_no_error (error);
1164   g_object_unref (authorize_proxy);
1165
1166   error = NULL;
1167   thread_proxy_1 = foo_method_threads_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1168                                                               G_DBUS_PROXY_FLAGS_NONE,
1169                                                               "org.gtk.GDBus.BindingsTool.Test",
1170                                                               "/method_threads_1",
1171                                                               NULL, /* GCancellable* */
1172                                                               &error);
1173   g_assert_no_error (error);
1174   thread_proxy_2 = foo_method_threads_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1175                                                               G_DBUS_PROXY_FLAGS_NONE,
1176                                                               "org.gtk.GDBus.BindingsTool.Test",
1177                                                               "/method_threads_2",
1178                                                               NULL, /* GCancellable* */
1179                                                               &error);
1180   g_assert_no_error (error);
1181   check_thread_proxies (thread_proxy_1, thread_proxy_2, thread_loop);
1182   g_object_unref (thread_proxy_1);
1183   g_object_unref (thread_proxy_2);
1184
1185   g_main_loop_unref (thread_loop);
1186   g_main_context_unref (thread_context);
1187
1188   /* this breaks out of the loop in main() (below) */
1189   g_main_loop_quit (loop);
1190   return NULL;
1191 }
1192
1193 /* ---------------------------------------------------------------------------------------------------- */
1194
1195 typedef struct
1196 {
1197   gchar *xml;
1198   GMainLoop *loop;
1199 } IntrospectData;
1200
1201 static void
1202 introspect_cb (GDBusConnection   *connection,
1203                GAsyncResult      *res,
1204                gpointer           user_data)
1205 {
1206   IntrospectData *data = user_data;
1207   GVariant *result;
1208   GError *error;
1209
1210   error = NULL;
1211   result = g_dbus_connection_call_finish (connection,
1212                                           res,
1213                                           &error);
1214   g_assert_no_error (error);
1215   g_assert (result != NULL);
1216   g_variant_get (result, "(s)", &data->xml);
1217   g_variant_unref (result);
1218
1219   g_main_loop_quit (data->loop);
1220 }
1221
1222 static GDBusNodeInfo *
1223 introspect (GDBusConnection  *connection,
1224             const gchar      *name,
1225             const gchar      *object_path,
1226             GMainLoop        *loop)
1227 {
1228   GError *error;
1229   GDBusNodeInfo *node_info;
1230   IntrospectData *data;
1231
1232   data = g_new0 (IntrospectData, 1);
1233   data->xml = NULL;
1234   data->loop = loop;
1235
1236   /* do this async to avoid deadlocks */
1237   g_dbus_connection_call (connection,
1238                           name,
1239                           object_path,
1240                           "org.freedesktop.DBus.Introspectable",
1241                           "Introspect",
1242                           NULL, /* params */
1243                           G_VARIANT_TYPE ("(s)"),
1244                           G_DBUS_CALL_FLAGS_NONE,
1245                           -1,
1246                           NULL,
1247                           (GAsyncReadyCallback) introspect_cb,
1248                           data);
1249   g_main_loop_run (loop);
1250   g_assert (data->xml != NULL);
1251
1252   error = NULL;
1253   node_info = g_dbus_node_info_new_for_xml (data->xml, &error);
1254   g_assert_no_error (error);
1255   g_assert (node_info != NULL);
1256   g_free (data->xml);
1257   g_free (data);
1258
1259   return node_info;
1260 }
1261
1262 static guint
1263 count_interfaces (GDBusNodeInfo *info)
1264 {
1265   guint n;
1266   for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
1267     ;
1268   return n;
1269 }
1270
1271 static guint
1272 count_nodes (GDBusNodeInfo *info)
1273 {
1274   guint n;
1275   for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
1276     ;
1277   return n;
1278 }
1279
1280 static guint
1281 has_interface (GDBusNodeInfo *info,
1282                const gchar   *name)
1283 {
1284   guint n;
1285   for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
1286     {
1287       if (g_strcmp0 (info->interfaces[n]->name, name) == 0)
1288         return TRUE;
1289     }
1290   return FALSE;
1291 }
1292
1293 /* ---------------------------------------------------------------------------------------------------- */
1294
1295 typedef struct {
1296   GMainLoop *loop;
1297   GVariant *result;
1298 } OMGetManagedObjectsData;
1299
1300 static void
1301 om_get_all_cb (GDBusConnection *connection,
1302                GAsyncResult    *res,
1303                gpointer         user_data)
1304 {
1305   OMGetManagedObjectsData *data = user_data;
1306   GError *error;
1307
1308   error = NULL;
1309   data->result = g_dbus_connection_call_finish (connection,
1310                                                 res,
1311                                                 &error);
1312   g_assert_no_error (error);
1313   g_assert (data->result != NULL);
1314   g_main_loop_quit (data->loop);
1315 }
1316
1317 static void
1318 om_check_get_all (GDBusConnection *c,
1319                   GMainLoop       *loop,
1320                   const gchar     *str)
1321 {
1322   OMGetManagedObjectsData data;
1323   gchar *s;
1324
1325   data.loop = loop;
1326   data.result = NULL;
1327
1328   /* do this async to avoid deadlocks */
1329   g_dbus_connection_call (c,
1330                           g_dbus_connection_get_unique_name (c),
1331                           "/managed",
1332                           "org.freedesktop.DBus.ObjectManager",
1333                           "GetManagedObjects",
1334                           NULL, /* params */
1335                           G_VARIANT_TYPE ("(a{oa{sa{sv}}})"),
1336                           G_DBUS_CALL_FLAGS_NONE,
1337                           -1,
1338                           NULL,
1339                           (GAsyncReadyCallback) om_get_all_cb,
1340                           &data);
1341   g_main_loop_run (loop);
1342   g_assert (data.result != NULL);
1343   s = g_variant_print (data.result, TRUE);
1344   g_assert_cmpstr (s, ==, str);
1345   g_free (s);
1346   g_variant_unref (data.result);
1347 }
1348
1349 typedef struct
1350 {
1351   GMainLoop *loop;
1352   guint state;
1353
1354   guint num_object_proxy_added_signals;
1355   guint num_object_proxy_removed_signals;
1356   guint num_interface_added_signals;
1357   guint num_interface_removed_signals;
1358 } OMData;
1359
1360 static gint
1361 my_pstrcmp (const gchar **a, const gchar **b)
1362 {
1363   return g_strcmp0 (*a, *b);
1364 }
1365
1366 static void
1367 om_check_interfaces_added (const gchar *signal_name,
1368                            GVariant *parameters,
1369                            const gchar *object_path,
1370                            const gchar *first_interface_name,
1371                            ...)
1372 {
1373   const gchar *path;
1374   GVariant *array;
1375   guint n;
1376   GPtrArray *interfaces;
1377   GPtrArray *interfaces_in_message;
1378   va_list var_args;
1379   const gchar *str;
1380
1381   interfaces = g_ptr_array_new ();
1382   g_ptr_array_add (interfaces, (gpointer) first_interface_name);
1383   va_start (var_args, first_interface_name);
1384   do
1385     {
1386       str = va_arg (var_args, const gchar *);
1387       if (str == NULL)
1388         break;
1389       g_ptr_array_add (interfaces, (gpointer) str);
1390     }
1391   while (TRUE);
1392   va_end (var_args);
1393
1394   g_variant_get (parameters, "(&o*)", &path, &array);
1395   g_assert_cmpstr (signal_name, ==, "InterfacesAdded");
1396   g_assert_cmpstr (path, ==, object_path);
1397   g_assert_cmpint (g_variant_n_children (array), ==, interfaces->len);
1398   interfaces_in_message = g_ptr_array_new ();
1399   for (n = 0; n < interfaces->len; n++)
1400     {
1401       const gchar *iface_name;
1402       g_variant_get_child (array, n, "{&sa{sv}}", &iface_name, NULL);
1403       g_ptr_array_add (interfaces_in_message, (gpointer) iface_name);
1404     }
1405   g_assert_cmpint (interfaces_in_message->len, ==, interfaces->len);
1406   g_ptr_array_sort (interfaces, (GCompareFunc) my_pstrcmp);
1407   g_ptr_array_sort (interfaces_in_message, (GCompareFunc) my_pstrcmp);
1408   for (n = 0; n < interfaces->len; n++)
1409     g_assert_cmpstr (interfaces->pdata[n], ==, interfaces_in_message->pdata[n]);
1410   g_ptr_array_unref (interfaces_in_message);
1411   g_ptr_array_unref (interfaces);
1412   g_variant_unref (array);
1413 }
1414
1415 static void
1416 om_check_interfaces_removed (const gchar *signal_name,
1417                              GVariant *parameters,
1418                              const gchar *object_path,
1419                              const gchar *first_interface_name,
1420                              ...)
1421 {
1422   const gchar *path;
1423   GVariant *array;
1424   guint n;
1425   GPtrArray *interfaces;
1426   GPtrArray *interfaces_in_message;
1427   va_list var_args;
1428   const gchar *str;
1429
1430   interfaces = g_ptr_array_new ();
1431   g_ptr_array_add (interfaces, (gpointer) first_interface_name);
1432   va_start (var_args, first_interface_name);
1433   do
1434     {
1435       str = va_arg (var_args, const gchar *);
1436       if (str == NULL)
1437         break;
1438       g_ptr_array_add (interfaces, (gpointer) str);
1439     }
1440   while (TRUE);
1441   va_end (var_args);
1442
1443   g_variant_get (parameters, "(&o*)", &path, &array);
1444   g_assert_cmpstr (signal_name, ==, "InterfacesRemoved");
1445   g_assert_cmpstr (path, ==, object_path);
1446   g_assert_cmpint (g_variant_n_children (array), ==, interfaces->len);
1447   interfaces_in_message = g_ptr_array_new ();
1448   for (n = 0; n < interfaces->len; n++)
1449     {
1450       const gchar *iface_name;
1451       g_variant_get_child (array, n, "&s", &iface_name, NULL);
1452       g_ptr_array_add (interfaces_in_message, (gpointer) iface_name);
1453     }
1454   g_assert_cmpint (interfaces_in_message->len, ==, interfaces->len);
1455   g_ptr_array_sort (interfaces, (GCompareFunc) my_pstrcmp);
1456   g_ptr_array_sort (interfaces_in_message, (GCompareFunc) my_pstrcmp);
1457   for (n = 0; n < interfaces->len; n++)
1458     g_assert_cmpstr (interfaces->pdata[n], ==, interfaces_in_message->pdata[n]);
1459   g_ptr_array_unref (interfaces_in_message);
1460   g_ptr_array_unref (interfaces);
1461   g_variant_unref (array);
1462 }
1463
1464 static void
1465 om_on_signal (GDBusConnection *connection,
1466               const gchar     *sender_name,
1467               const gchar     *object_path,
1468               const gchar     *interface_name,
1469               const gchar     *signal_name,
1470               GVariant        *parameters,
1471               gpointer         user_data)
1472 {
1473   OMData *om_data = user_data;
1474
1475   //g_debug ("foo: %s", g_variant_print (parameters, TRUE));
1476
1477   switch (om_data->state)
1478     {
1479     default:
1480     case 0:
1481       g_print ("failing and om_data->state=%d on signal %s, params=%s\n",
1482                om_data->state,
1483                signal_name,
1484                g_variant_print (parameters, TRUE));
1485       g_assert_not_reached ();
1486       break;
1487
1488     case 1:
1489       om_check_interfaces_added (signal_name, parameters, "/managed/first",
1490                                  "org.project.Bar", NULL);
1491       om_data->state = 2;
1492       g_main_loop_quit (om_data->loop);
1493       break;
1494
1495     case 3:
1496       om_check_interfaces_removed (signal_name, parameters, "/managed/first",
1497                                    "org.project.Bar", NULL);
1498       om_data->state = 5;
1499       /* keep running the loop */
1500       break;
1501
1502     case 5:
1503       om_check_interfaces_added (signal_name, parameters, "/managed/first",
1504                                  "org.project.Bar", NULL);
1505       om_data->state = 6;
1506       g_main_loop_quit (om_data->loop);
1507       break;
1508
1509     case 7:
1510       om_check_interfaces_removed (signal_name, parameters, "/managed/first",
1511                                    "org.project.Bar", NULL);
1512       om_data->state = 9;
1513       /* keep running the loop */
1514       break;
1515
1516     case 9:
1517       om_check_interfaces_added (signal_name, parameters, "/managed/first",
1518                                  "org.project.Bar", NULL);
1519       om_data->state = 10;
1520       g_main_loop_quit (om_data->loop);
1521       break;
1522
1523     case 11:
1524       om_check_interfaces_added (signal_name, parameters, "/managed/first",
1525                                  "org.project.Bat", NULL);
1526       om_data->state = 12;
1527       g_main_loop_quit (om_data->loop);
1528       break;
1529
1530     case 13:
1531       om_check_interfaces_removed (signal_name, parameters, "/managed/first",
1532                                    "org.project.Bar", NULL);
1533       om_data->state = 14;
1534       g_main_loop_quit (om_data->loop);
1535       break;
1536
1537     case 15:
1538       om_check_interfaces_removed (signal_name, parameters, "/managed/first",
1539                                    "org.project.Bat", NULL);
1540       om_data->state = 16;
1541       g_main_loop_quit (om_data->loop);
1542       break;
1543
1544     case 17:
1545       om_check_interfaces_added (signal_name, parameters, "/managed/first",
1546                                  "com.acme.Coyote", NULL);
1547       om_data->state = 18;
1548       g_main_loop_quit (om_data->loop);
1549       break;
1550
1551     case 101:
1552       om_check_interfaces_added (signal_name, parameters, "/managed/second",
1553                                  "org.project.Bat", "org.project.Bar", NULL);
1554       om_data->state = 102;
1555       g_main_loop_quit (om_data->loop);
1556       break;
1557
1558     case 103:
1559       om_check_interfaces_removed (signal_name, parameters, "/managed/second",
1560                                    "org.project.Bat", "org.project.Bar", NULL);
1561       om_data->state = 104;
1562       g_main_loop_quit (om_data->loop);
1563       break;
1564     }
1565 }
1566
1567 static GAsyncResult *om_res = NULL;
1568
1569 static void
1570 om_pm_start_cb (GDBusObjectManagerClient *manager,
1571                 GAsyncResult      *res,
1572                 gpointer           user_data)
1573 {
1574   GMainLoop *loop = user_data;
1575   om_res = g_object_ref (res);
1576   g_main_loop_quit (loop);
1577 }
1578
1579 static GType
1580 get_proxy_type (GDBusObjectManagerClient *manager,
1581                 const gchar       *object_path,
1582                 const gchar       *interface_name,
1583                 gpointer           user_data)
1584 {
1585   GType type;
1586
1587   g_assert_cmpint (GPOINTER_TO_UINT (user_data), ==, 42);
1588
1589   type = G_TYPE_DBUS_PROXY;
1590   /* only map Bar and Bat, not other interface types */
1591   if (g_strcmp0 (interface_name, "org.project.Bar") == 0)
1592     type = FOO_TYPE_BAR_PROXY;
1593   else if (g_strcmp0 (interface_name, "org.project.Bat") == 0)
1594     type = FOO_TYPE_BAT_PROXY;
1595
1596   return type;
1597 }
1598
1599 static void
1600 on_interface_added (GDBusObject    *object,
1601                     GDBusInterface *interface,
1602                     gpointer        user_data)
1603 {
1604   OMData *om_data = user_data;
1605   om_data->num_interface_added_signals += 1;
1606 }
1607
1608 static void
1609 on_interface_removed (GDBusObject    *object,
1610                       GDBusInterface *interface,
1611                       gpointer        user_data)
1612 {
1613   OMData *om_data = user_data;
1614   om_data->num_interface_removed_signals += 1;
1615 }
1616
1617 static void
1618 on_object_proxy_added (GDBusObjectManagerClient  *manager,
1619                        GDBusObjectProxy   *object_proxy,
1620                        gpointer            user_data)
1621 {
1622   OMData *om_data = user_data;
1623   om_data->num_object_proxy_added_signals += 1;
1624   g_signal_connect (object_proxy,
1625                     "interface-added",
1626                     G_CALLBACK (on_interface_added),
1627                     om_data);
1628   g_signal_connect (object_proxy,
1629                     "interface-removed",
1630                     G_CALLBACK (on_interface_removed),
1631                     om_data);
1632 }
1633
1634 static void
1635 on_object_proxy_removed (GDBusObjectManagerClient  *manager,
1636                          GDBusObjectProxy   *object_proxy,
1637                          gpointer            user_data)
1638 {
1639   OMData *om_data = user_data;
1640   om_data->num_object_proxy_removed_signals += 1;
1641   g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
1642                                                          G_CALLBACK (on_interface_added),
1643                                                          om_data), ==, 1);
1644   g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
1645                                                          G_CALLBACK (on_interface_removed),
1646                                                          om_data), ==, 1);
1647 }
1648
1649 static void
1650 om_check_property_and_signal_emission (GMainLoop  *loop,
1651                                        FooBar     *skeleton,
1652                                        FooBar     *proxy)
1653 {
1654   /* First PropertiesChanged */
1655   g_assert_cmpint (foo_bar_get_i (skeleton), ==, 0);
1656   g_assert_cmpint (foo_bar_get_i (proxy), ==, 0);
1657   foo_bar_set_i (skeleton, 1);
1658   _g_assert_property_notify (proxy, "i");
1659   g_assert_cmpint (foo_bar_get_i (skeleton), ==, 1);
1660   g_assert_cmpint (foo_bar_get_i (proxy), ==, 1);
1661
1662   /* Then just a regular signal */
1663   foo_bar_emit_another_signal (skeleton, "word");
1664   _g_assert_signal_received (proxy, "another-signal");
1665 }
1666
1667 static void
1668 check_object_manager (void)
1669 {
1670   GDBusObjectSkeleton *o;
1671   GDBusObjectSkeleton *o2;
1672   GDBusInterfaceSkeleton *i;
1673   GDBusInterfaceSkeleton *i2;
1674   GDBusConnection *c;
1675   GDBusObjectManagerServer *manager;
1676   GDBusNodeInfo *info;
1677   GError *error;
1678   GMainLoop *loop;
1679   OMData *om_data;
1680   guint om_signal_id;
1681   GDBusObjectManager *pm;
1682   GList *object_proxies;
1683   GList *proxies;
1684   GDBusObject *op;
1685   GDBusProxy *p;
1686   FooBar *bar_skeleton;
1687   FooBar *bar_p;
1688   FooBar *bar_p2;
1689   FooComAcmeCoyote *coyote_p;
1690   guint old_ref_count;
1691
1692   loop = g_main_loop_new (NULL, FALSE);
1693
1694   om_data = g_new0 (OMData, 1);
1695   om_data->loop = loop;
1696   om_data->state = 0;
1697
1698   error = NULL;
1699   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1700   g_assert_no_error (error);
1701   g_assert (c != NULL);
1702
1703   om_signal_id = g_dbus_connection_signal_subscribe (c,
1704                                                      NULL, /* sender */
1705                                                      "org.freedesktop.DBus.ObjectManager",
1706                                                      NULL, /* member */
1707                                                      NULL, /* object_path */
1708                                                      NULL, /* arg0 */
1709                                                      G_DBUS_SIGNAL_FLAGS_NONE,
1710                                                      om_on_signal,
1711                                                      om_data,
1712                                                      NULL); /* user_data_free_func */
1713
1714   /* Our GDBusObjectManagerClient tests are simple - we basically just count the
1715    * number of times the various signals have been emitted (we don't check
1716    * that the right objects/interfaces are passed though - that's checked
1717    * in the lower-level tests in om_on_signal()...)
1718    *
1719    * Note that these tests rely on the D-Bus signal handlers used by
1720    * GDBusObjectManagerClient firing before om_on_signal().
1721    */
1722   error = NULL;
1723   pm = g_dbus_object_manager_client_new_sync (c,
1724                                               G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
1725                                               g_dbus_connection_get_unique_name (c),
1726                                               "/managed",
1727                                               get_proxy_type,
1728                                               GUINT_TO_POINTER (42),
1729                                               NULL, /* GCancellable */
1730                                               &error);
1731   g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
1732   g_error_free (error);
1733   g_assert (pm == NULL);
1734
1735   manager = g_dbus_object_manager_server_new (c, "/managed");
1736
1737   /* Check that the manager object is visible */
1738   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop);
1739   g_assert_cmpint (count_interfaces (info), ==, 4); /* ObjectManager + Properties,Introspectable,Peer */
1740   g_assert (has_interface (info, "org.freedesktop.DBus.ObjectManager"));
1741   g_assert_cmpint (count_nodes (info), ==, 0);
1742   g_dbus_node_info_unref (info);
1743
1744   /* Check GetManagedObjects() - should be empty since we have no objects */
1745   om_check_get_all (c, loop,
1746                     "(@a{oa{sa{sv}}} {},)");
1747
1748   /* Now try to create the the proxy manager again - this time it should work */
1749   error = NULL;
1750   g_dbus_object_manager_client_new (c,
1751                             G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
1752                             g_dbus_connection_get_unique_name (c),
1753                             "/managed",
1754                             get_proxy_type,
1755                             GUINT_TO_POINTER (42),
1756                             NULL, /* GCancellable */
1757                             (GAsyncReadyCallback) om_pm_start_cb,
1758                             loop);
1759   g_main_loop_run (loop);
1760   error = NULL;
1761   pm = g_dbus_object_manager_client_new_finish (om_res, &error);
1762   g_object_unref (om_res);
1763   g_assert_no_error (error);
1764   g_assert (pm != NULL);
1765   g_signal_connect (pm,
1766                     "object-added",
1767                     G_CALLBACK (on_object_proxy_added),
1768                     om_data);
1769   g_signal_connect (pm,
1770                     "object-removed",
1771                     G_CALLBACK (on_object_proxy_removed),
1772                     om_data);
1773   /* ... check there are no object proxies yet */
1774   object_proxies = g_dbus_object_manager_get_objects (pm);
1775   g_assert (object_proxies == NULL);
1776
1777   /* First, export an object with a single interface (also check that
1778    * g_dbus_interface_get_object() works and that the object isn't reffed)
1779    */
1780   o = g_dbus_object_skeleton_new ("/managed/first");
1781   i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
1782   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
1783   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
1784   g_dbus_object_skeleton_add_interface (o, i);
1785   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
1786   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
1787   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
1788   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
1789   g_dbus_object_skeleton_remove_interface (o, i);
1790   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
1791   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
1792   g_dbus_object_skeleton_add_interface (o, i);
1793   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
1794   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
1795   g_dbus_object_manager_server_export (manager, o);
1796
1797   /* ... check we get the InterfacesAdded signal */
1798   om_data->state = 1;
1799   g_main_loop_run (om_data->loop);
1800   g_assert_cmpint (om_data->state, ==, 2);
1801   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 1);
1802   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 0);
1803   g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
1804   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
1805   /* ... check there's one non-standard interfaces */
1806   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
1807   g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
1808   g_assert (has_interface (info, "org.project.Bar"));
1809   g_dbus_node_info_unref (info);
1810
1811   /* Now, check adding the same interface replaces the existing one */
1812   g_dbus_object_skeleton_add_interface (o, i);
1813   /* ... check we get the InterfacesRemoved */
1814   om_data->state = 3;
1815   g_main_loop_run (om_data->loop);
1816   /* ... and then check we get the InterfacesAdded */
1817   g_assert_cmpint (om_data->state, ==, 6);
1818   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 2);
1819   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 1);
1820   g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
1821   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
1822   /* ... check introspection data */
1823   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
1824   g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
1825   g_assert (has_interface (info, "org.project.Bar"));
1826   g_dbus_node_info_unref (info);
1827   g_object_unref (i);
1828
1829   /* check adding an interface of same type (but not same object) replaces the existing one */
1830   i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
1831   g_dbus_object_skeleton_add_interface (o, i);
1832   /* ... check we get the InterfacesRemoved and then InterfacesAdded */
1833   om_data->state = 7;
1834   g_main_loop_run (om_data->loop);
1835   g_assert_cmpint (om_data->state, ==, 10);
1836   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
1837   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
1838   g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
1839   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
1840   /* ... check introspection data */
1841   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
1842   g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
1843   g_assert (has_interface (info, "org.project.Bar"));
1844   g_dbus_node_info_unref (info);
1845   g_object_unref (i);
1846
1847   /* check adding an interface of another type doesn't replace the existing one */
1848   i = G_DBUS_INTERFACE_SKELETON (foo_bat_skeleton_new ());
1849   g_dbus_object_skeleton_add_interface (o, i);
1850   g_object_unref (i);
1851   /* ... check we get the InterfacesAdded */
1852   om_data->state = 11;
1853   g_main_loop_run (om_data->loop);
1854   g_assert_cmpint (om_data->state, ==, 12);
1855   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
1856   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
1857   g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
1858   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
1859   /* ... check introspection data */
1860   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
1861   g_assert_cmpint (count_interfaces (info), ==, 5); /* Bar,Bat + Properties,Introspectable,Peer */
1862   g_assert (has_interface (info, "org.project.Bar"));
1863   g_assert (has_interface (info, "org.project.Bat"));
1864   g_dbus_node_info_unref (info);
1865
1866   /* check we can remove an interface */
1867   g_dbus_object_skeleton_remove_interface_by_name (o, "org.project.Bar");
1868   /* ... check we get the InterfacesRemoved */
1869   om_data->state = 13;
1870   g_main_loop_run (om_data->loop);
1871   g_assert_cmpint (om_data->state, ==, 14);
1872   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
1873   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
1874   g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
1875   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
1876   /* ... check introspection data */
1877   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
1878   g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
1879   g_assert (has_interface (info, "org.project.Bat"));
1880   g_dbus_node_info_unref (info);
1881   /* also and that the call only has effect if the interface actually exists
1882    *
1883    * (Note: if a signal was emitted we'd assert in the signal handler
1884    * because we're in state 14)
1885    */
1886   g_dbus_object_skeleton_remove_interface_by_name (o, "org.project.Bar");
1887   /* ... check introspection data */
1888   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
1889   g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
1890   g_assert (has_interface (info, "org.project.Bat"));
1891   g_dbus_node_info_unref (info);
1892
1893   /* remove the last interface */
1894   g_dbus_object_skeleton_remove_interface_by_name (o, "org.project.Bat");
1895   /* ... check we get the InterfacesRemoved */
1896   om_data->state = 15;
1897   g_main_loop_run (om_data->loop);
1898   g_assert_cmpint (om_data->state, ==, 16);
1899   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
1900   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
1901   g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
1902   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
1903   /* ... check introspection data */
1904   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
1905   g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
1906   g_dbus_node_info_unref (info);
1907
1908   /* and add an interface again */
1909   i = G_DBUS_INTERFACE_SKELETON (foo_com_acme_coyote_skeleton_new ());
1910   g_dbus_object_skeleton_add_interface (o, i);
1911   g_object_unref (i);
1912   /* ... check we get the InterfacesAdded */
1913   om_data->state = 17;
1914   g_main_loop_run (om_data->loop);
1915   g_assert_cmpint (om_data->state, ==, 18);
1916   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 4);
1917   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
1918   g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
1919   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
1920   /* ... check introspection data */
1921   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
1922   g_assert_cmpint (count_interfaces (info), ==, 4); /* com.acme.Coyote + Properties,Introspectable,Peer */
1923   g_assert (has_interface (info, "com.acme.Coyote"));
1924   g_dbus_node_info_unref (info);
1925
1926   /* Check GetManagedObjects() - should be just the Coyote */
1927   om_check_get_all (c, loop,
1928                     "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
1929
1930   /* -------------------------------------------------- */
1931
1932   /* create a new object with two interfaces */
1933   o2 = g_dbus_object_skeleton_new ("/managed/second");
1934   i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
1935   bar_skeleton = FOO_BAR (i); /* save for later test */
1936   g_dbus_object_skeleton_add_interface (o2, i);
1937   g_object_unref (i);
1938   i = G_DBUS_INTERFACE_SKELETON (foo_bat_skeleton_new ());
1939   g_dbus_object_skeleton_add_interface (o2, i);
1940   g_object_unref (i);
1941   /* ... add it */
1942   g_dbus_object_manager_server_export (manager, o2);
1943   /* ... check we get the InterfacesAdded with _two_ interfaces */
1944   om_data->state = 101;
1945   g_main_loop_run (om_data->loop);
1946   g_assert_cmpint (om_data->state, ==, 102);
1947   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
1948   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
1949   g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
1950   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
1951
1952   /* -------------------------------------------------- */
1953
1954   /* Now that we have a couple of objects with interfaces, check
1955    * that ObjectManager.GetManagedObjects() works
1956    */
1957   om_check_get_all (c, loop,
1958                     "({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': <''>, '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,)>}}},)");
1959
1960   /* check that the _GET_ and _PEEK_ macros work on the server side */
1961   i = FOO_PEEK_BAR (o);
1962   g_assert (i == NULL);
1963   i = FOO_PEEK_COM_ACME_COYOTE (o);
1964   g_assert (i != NULL);
1965   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), G_TYPE_DBUS_INTERFACE_SKELETON));
1966   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), FOO_TYPE_COM_ACME_COYOTE));
1967   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), FOO_TYPE_COM_ACME_COYOTE_SKELETON));
1968   /* ... and that PEEK doesn't increase the ref_count but GET does */
1969   g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 2);
1970   i2 = FOO_PEEK_COM_ACME_COYOTE (o);
1971   g_assert (i == i2);
1972   g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 2);
1973   i2 = FOO_GET_COM_ACME_COYOTE (o);
1974   g_assert (i == i2);
1975   g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 3);
1976   g_object_unref (i);
1977
1978   /* Also check that the ObjectManagerClient returns these objects - and
1979    * that they are of the right GType cf. what we requested via
1980    * our ::get-proxy-type signal handler
1981    */
1982   object_proxies = g_dbus_object_manager_get_objects (pm);
1983   g_assert (g_list_length (object_proxies) == 2);
1984   g_list_foreach (object_proxies, (GFunc) g_object_unref, NULL);
1985   g_list_free (object_proxies);
1986   op = g_dbus_object_manager_get_object (pm, "/managed/first");
1987   g_assert (op != NULL);
1988   g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/first");
1989   proxies = g_dbus_object_get_interfaces (op);
1990   g_assert (g_list_length (proxies) == 1);
1991   g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
1992   g_list_free (proxies);
1993   p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "com.acme.Coyote"));
1994   g_assert (p != NULL);
1995   g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, G_TYPE_DBUS_PROXY);
1996   g_assert (!g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_COM_ACME_COYOTE));
1997   g_object_unref (p);
1998   p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
1999   g_assert (p == NULL);
2000   g_object_unref (op);
2001   /* -- */
2002   op = g_dbus_object_manager_get_object (pm, "/managed/second");
2003   g_assert (op != NULL);
2004   g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/second");
2005   proxies = g_dbus_object_get_interfaces (op);
2006   g_assert (g_list_length (proxies) == 2);
2007   g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
2008   g_list_free (proxies);
2009   p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "org.project.Bat"));
2010   g_assert (p != NULL);
2011   g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_BAT_PROXY);
2012   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_BAT));
2013   g_object_unref (p);
2014   p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "org.project.Bar"));
2015   g_assert (p != NULL);
2016   g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_BAR_PROXY);
2017   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_BAR));
2018   /* ... now that we have a Bar instance around, also check that we get signals
2019    *     and property changes...
2020    */
2021   om_check_property_and_signal_emission (loop, bar_skeleton, FOO_BAR (p));
2022   g_object_unref (p);
2023   p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
2024   g_assert (p == NULL);
2025   g_object_unref (op);
2026
2027   /* -------------------------------------------------- */
2028
2029   /* check that the _GET_ and _PEEK_ macros work on the proxy side */
2030   op = g_dbus_object_manager_get_object (pm, "/managed/second");
2031   bar_p = FOO_GET_BAR (op);
2032   old_ref_count = G_OBJECT (op)->ref_count;
2033   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (bar_p)) == op);
2034   g_assert_cmpint (old_ref_count, ==, G_OBJECT (op)->ref_count);
2035   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (bar_p), FOO_TYPE_BAR));
2036   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (bar_p), G_TYPE_DBUS_PROXY));
2037   g_assert_cmpint (G_OBJECT (bar_p)->ref_count, ==, 2);
2038   g_object_unref (bar_p);
2039   bar_p2 = FOO_PEEK_BAR (op);
2040   g_assert (bar_p2 == bar_p);
2041   g_assert_cmpint (G_OBJECT (bar_p)->ref_count, ==, 1);
2042   coyote_p = FOO_GET_COM_ACME_COYOTE (op);
2043   g_assert (coyote_p == NULL);
2044   coyote_p = FOO_PEEK_COM_ACME_COYOTE (op);
2045   g_assert (coyote_p == NULL);
2046   g_object_unref (op);
2047
2048   /* Also, check that we warn on stderr in case the get_proxy_type() function is
2049    * wrong etc.
2050    */
2051   op = g_dbus_object_manager_get_object (pm, "/managed/first");
2052   bar_p = FOO_GET_BAR (op);
2053   g_assert (bar_p == NULL);
2054   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
2055     {
2056       coyote_p = FOO_GET_COM_ACME_COYOTE (op);
2057     }
2058   g_test_trap_assert_stderr ("*runtime check failed: (G_TYPE_CHECK_INSTANCE_TYPE (ret, type))*");
2059   g_object_unref (op);
2060
2061   /* -------------------------------------------------- */
2062
2063   /* Now remove the second object added above */
2064   g_dbus_object_manager_server_unexport (manager, "/managed/second");
2065   /* ... check we get InterfacesRemoved with both interfaces */
2066   om_data->state = 103;
2067   g_main_loop_run (om_data->loop);
2068   g_assert_cmpint (om_data->state, ==, 104);
2069   g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
2070   g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 4);
2071   g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
2072   g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
2073   /* ... check introspection data (there should be nothing) */
2074   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/second", loop);
2075   g_assert_cmpint (count_nodes (info), ==, 0);
2076   g_assert_cmpint (count_interfaces (info), ==, 0);
2077   g_dbus_node_info_unref (info);
2078
2079   /* Check GetManagedObjects() again */
2080   om_check_get_all (c, loop,
2081                     "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
2082
2083   //g_main_loop_run (loop); /* TODO: tmp */
2084
2085   g_main_loop_unref (loop);
2086
2087   g_dbus_connection_signal_unsubscribe (c, om_signal_id);
2088   g_object_unref (o2);
2089   g_object_unref (o);
2090   g_object_unref (manager);
2091   g_assert_cmpint (g_signal_handlers_disconnect_by_func (pm,
2092                                                          G_CALLBACK (on_object_proxy_added),
2093                                                          om_data), ==, 1);
2094   g_assert_cmpint (g_signal_handlers_disconnect_by_func (pm,
2095                                                          G_CALLBACK (on_object_proxy_removed),
2096                                                          om_data), ==, 1);
2097   g_object_unref (pm);
2098   g_object_unref (c);
2099
2100   g_free (om_data);
2101 }
2102
2103 /* ---------------------------------------------------------------------------------------------------- */
2104
2105 static void
2106 test_object_manager (void)
2107 {
2108   GMainLoop *loop;
2109   guint id;
2110
2111   loop = g_main_loop_new (NULL, FALSE);
2112
2113   id = g_bus_own_name (G_BUS_TYPE_SESSION,
2114                        "org.gtk.GDBus.BindingsTool.Test",
2115                        G_BUS_NAME_OWNER_FLAGS_NONE,
2116                        on_bus_acquired,
2117                        on_name_acquired,
2118                        on_name_lost,
2119                        loop,
2120                        NULL);
2121
2122   g_main_loop_run (loop);
2123
2124   check_object_manager ();
2125
2126   /* uncomment to keep the service around (to e.g. introspect it) */
2127   /* g_main_loop_run (loop); */
2128
2129   g_bus_unown_name (id);
2130   g_main_loop_unref (loop);
2131 }
2132
2133 /* ---------------------------------------------------------------------------------------------------- */
2134 /* This checks that forcing names via org.gtk.GDBus.Name works (see test-codegen.xml) */
2135
2136 extern gpointer name_forcing_1;
2137 extern gpointer name_forcing_2;
2138 extern gpointer name_forcing_3;
2139 extern gpointer name_forcing_4;
2140 extern gpointer name_forcing_5;
2141 extern gpointer name_forcing_6;
2142 extern gpointer name_forcing_7;
2143 gpointer name_forcing_1 = foo_rocket123_get_gtype;
2144 gpointer name_forcing_2 = foo_rocket123_call_ignite_xyz;
2145 gpointer name_forcing_3 = foo_rocket123_emit_exploded_xyz;
2146 gpointer name_forcing_4 = foo_rocket123_get_speed_xyz;
2147 gpointer name_forcing_5 = foo_test_ugly_case_interface_call_get_iscsi_servers;
2148 gpointer name_forcing_6 = foo_test_ugly_case_interface_emit_servers_updated_now;
2149 gpointer name_forcing_7 = foo_test_ugly_case_interface_get_ugly_name;
2150
2151 /* ---------------------------------------------------------------------------------------------------- */
2152
2153 /* See https://bugzilla.gnome.org/show_bug.cgi?id=647577#c5 for details */
2154
2155 #define CHECK_FIELD(name, v1, v2) g_assert_cmpint (G_STRUCT_OFFSET (FooChangingInterface##v1##Iface, name), ==, G_STRUCT_OFFSET (FooChangingInterface##v2##Iface, name));
2156
2157 static void
2158 test_interface_stability (void)
2159 {
2160   CHECK_FIELD(handle_foo_method, V1, V2);
2161   CHECK_FIELD(handle_bar_method, V1, V2);
2162   CHECK_FIELD(handle_baz_method, V1, V2);
2163   CHECK_FIELD(foo_signal, V1, V2);
2164   CHECK_FIELD(bar_signal, V1, V2);
2165   CHECK_FIELD(baz_signal, V1, V2);
2166   CHECK_FIELD(handle_new_method_in2, V2, V10);
2167   CHECK_FIELD(new_signal_in2, V2, V10);
2168 }
2169
2170 #undef CHECK_FIELD
2171
2172 /* ---------------------------------------------------------------------------------------------------- */
2173
2174 int
2175 main (int   argc,
2176       char *argv[])
2177 {
2178   gint ret;
2179
2180   g_type_init ();
2181   g_test_init (&argc, &argv, NULL);
2182
2183   /* all the tests use a session bus with a well-known address that we can bring up and down
2184    * using session_bus_up() and session_bus_down().
2185    */
2186   g_unsetenv ("DISPLAY");
2187   g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
2188
2189   session_bus_up ();
2190
2191   /* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
2192    * until one can connect to the bus but that's not how things work right now
2193    */
2194   usleep (500 * 1000);
2195
2196   g_test_add_func ("/gdbus/codegen/annotations", test_annotations);
2197   g_test_add_func ("/gdbus/codegen/interface_stability", test_interface_stability);
2198   g_test_add_func ("/gdbus/codegen/object-manager", test_object_manager);
2199
2200   ret = g_test_run();
2201
2202   /* tear down bus */
2203   session_bus_down ();
2204
2205   return ret;
2206 }