various tests: do not provoke SIGTRAP with -m no-undefined
[platform/upstream/glib.git] / gio / tests / gdbus-proxy.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2008-2010 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
27 #include "gdbus-tests.h"
28
29 /* all tests rely on a shared mainloop */
30 static GMainLoop *loop = NULL;
31
32 /* ---------------------------------------------------------------------------------------------------- */
33 /* Test that the method aspects of GDBusProxy works */
34 /* ---------------------------------------------------------------------------------------------------- */
35
36 static void
37 test_methods (GDBusProxy *proxy)
38 {
39   GVariant *result;
40   GError *error;
41   const gchar *str;
42   gchar *dbus_error_name;
43
44   /* check that we can invoke a method */
45   error = NULL;
46   result = g_dbus_proxy_call_sync (proxy,
47                                    "HelloWorld",
48                                    g_variant_new ("(s)", "Hey"),
49                                    G_DBUS_CALL_FLAGS_NONE,
50                                    -1,
51                                    NULL,
52                                    &error);
53   g_assert_no_error (error);
54   g_assert (result != NULL);
55   g_assert_cmpstr (g_variant_get_type_string (result), ==, "(s)");
56   g_variant_get (result, "(&s)", &str);
57   g_assert_cmpstr (str, ==, "You greeted me with 'Hey'. Thanks!");
58   g_variant_unref (result);
59
60   /* Check that we can completely recover the returned error */
61   result = g_dbus_proxy_call_sync (proxy,
62                                    "HelloWorld",
63                                    g_variant_new ("(s)", "Yo"),
64                                    G_DBUS_CALL_FLAGS_NONE,
65                                    -1,
66                                    NULL,
67                                    &error);
68   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
69   g_assert (g_dbus_error_is_remote_error (error));
70   g_assert (g_dbus_error_is_remote_error (error));
71   g_assert (result == NULL);
72   dbus_error_name = g_dbus_error_get_remote_error (error);
73   g_assert_cmpstr (dbus_error_name, ==, "com.example.TestException");
74   g_free (dbus_error_name);
75   g_assert (g_dbus_error_strip_remote_error (error));
76   g_assert_cmpstr (error->message, ==, "Yo is not a proper greeting");
77   g_clear_error (&error);
78
79   /* Check that we get a timeout if the method handling is taking longer than timeout */
80   error = NULL;
81   result = g_dbus_proxy_call_sync (proxy,
82                                    "Sleep",
83                                    g_variant_new ("(i)", 500 /* msec */),
84                                    G_DBUS_CALL_FLAGS_NONE,
85                                    100 /* msec */,
86                                    NULL,
87                                    &error);
88   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
89   g_assert (!g_dbus_error_is_remote_error (error));
90   g_assert (result == NULL);
91   g_clear_error (&error);
92
93   /* Check that proxy-default timeouts work. */
94   g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, -1);
95
96   /* the default timeout is 25000 msec so this should work */
97   result = g_dbus_proxy_call_sync (proxy,
98                                    "Sleep",
99                                    g_variant_new ("(i)", 500 /* msec */),
100                                    G_DBUS_CALL_FLAGS_NONE,
101                                    -1, /* use proxy default (e.g. -1 -> e.g. 25000 msec) */
102                                    NULL,
103                                    &error);
104   g_assert_no_error (error);
105   g_assert (result != NULL);
106   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
107   g_variant_unref (result);
108
109   /* now set the proxy-default timeout to 250 msec and try the 500 msec call - this should FAIL */
110   g_dbus_proxy_set_default_timeout (proxy, 250);
111   g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, 250);
112   result = g_dbus_proxy_call_sync (proxy,
113                                    "Sleep",
114                                    g_variant_new ("(i)", 500 /* msec */),
115                                    G_DBUS_CALL_FLAGS_NONE,
116                                    -1, /* use proxy default (e.g. 250 msec) */
117                                    NULL,
118                                    &error);
119   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
120   g_assert (!g_dbus_error_is_remote_error (error));
121   g_assert (result == NULL);
122   g_clear_error (&error);
123
124   /* clean up after ourselves */
125   g_dbus_proxy_set_default_timeout (proxy, -1);
126 }
127
128 static gboolean
129 strv_equal (gchar **strv, ...)
130 {
131   gint count;
132   va_list list;
133   const gchar *str;
134   gboolean res;
135
136   res = TRUE;
137   count = 0;
138   va_start (list, strv);
139   while (1)
140     {
141       str = va_arg (list, const gchar *);
142       if (str == NULL)
143         break;
144       if (g_strcmp0 (str, strv[count]) != 0)
145         {
146           res = FALSE;
147           break;
148         }
149       count++;
150     }
151   va_end (list);
152
153   if (res)
154     res = g_strv_length (strv) == count;
155
156   return res;
157 }
158
159 /* ---------------------------------------------------------------------------------------------------- */
160 /* Test that the property aspects of GDBusProxy works */
161 /* ---------------------------------------------------------------------------------------------------- */
162
163 static void
164 test_properties (GDBusProxy *proxy)
165 {
166   GError *error;
167   GVariant *variant;
168   GVariant *variant2;
169   GVariant *result;
170   gchar **names;
171
172   error = NULL;
173
174   if (g_dbus_proxy_get_flags (proxy) & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
175     {
176        g_assert (g_dbus_proxy_get_cached_property_names (proxy) == NULL);
177        return;
178     }
179
180   /*
181    * Check that we can list all cached properties.
182    */
183   names = g_dbus_proxy_get_cached_property_names (proxy);
184
185   g_assert (strv_equal (names,
186                         "PropertyThatWillBeInvalidated",
187                         "ab",
188                         "ad",
189                         "ai",
190                         "an",
191                         "ao",
192                         "aq",
193                         "as",
194                         "at",
195                         "au",
196                         "ax",
197                         "ay",
198                         "b",
199                         "d",
200                         "foo",
201                         "i",
202                         "n",
203                         "o",
204                         "q",
205                         "s",
206                         "t",
207                         "u",
208                         "x",
209                         "y",
210                         NULL));
211
212   g_strfreev (names);
213
214   /*
215    * Check that we can read cached properties.
216    *
217    * No need to test all properties - GVariant has already been tested
218    */
219   variant = g_dbus_proxy_get_cached_property (proxy, "y");
220   g_assert (variant != NULL);
221   g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
222   g_variant_unref (variant);
223   variant = g_dbus_proxy_get_cached_property (proxy, "o");
224   g_assert (variant != NULL);
225   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "/some/path");
226   g_variant_unref (variant);
227
228   /*
229    * Now ask the service to change a property and check that #GDBusProxy::g-property-changed
230    * is received. Also check that the cache is updated.
231    */
232   variant2 = g_variant_new_byte (42);
233   result = g_dbus_proxy_call_sync (proxy,
234                                    "FrobSetProperty",
235                                    g_variant_new ("(sv)",
236                                                   "y",
237                                                   variant2),
238                                    G_DBUS_CALL_FLAGS_NONE,
239                                    -1,
240                                    NULL,
241                                    &error);
242   g_assert_no_error (error);
243   g_assert (result != NULL);
244   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
245   g_variant_unref (result);
246   _g_assert_signal_received (proxy, "g-properties-changed");
247   variant = g_dbus_proxy_get_cached_property (proxy, "y");
248   g_assert (variant != NULL);
249   g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
250   g_variant_unref (variant);
251
252   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (142));
253   variant = g_dbus_proxy_get_cached_property (proxy, "y");
254   g_assert (variant != NULL);
255   g_assert_cmpint (g_variant_get_byte (variant), ==, 142);
256   g_variant_unref (variant);
257
258   g_dbus_proxy_set_cached_property (proxy, "y", NULL);
259   variant = g_dbus_proxy_get_cached_property (proxy, "y");
260   g_assert (variant == NULL);
261
262   /* Check that the invalidation feature of the PropertiesChanged()
263    * signal works... First, check that we have a cached value of the
264    * property (from the initial GetAll() call)
265    */
266   variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
267   g_assert (variant != NULL);
268   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "InitialValue");
269   g_variant_unref (variant);
270   /* now ask to invalidate the property - this causes a
271    *
272    *   PropertiesChanaged("com.example.Frob",
273    *                      {},
274    *                      ["PropertyThatWillBeInvalidated")
275    *
276    * signal to be emitted. This is received before the method reply
277    * for FrobInvalidateProperty *but* since the proxy was created in
278    * the same thread as we're doing this synchronous call, we'll get
279    * the method reply before...
280    */
281   result = g_dbus_proxy_call_sync (proxy,
282                                    "FrobInvalidateProperty",
283                                    NULL,
284                                    G_DBUS_CALL_FLAGS_NONE,
285                                    -1,
286                                    NULL,
287                                    &error);
288   g_assert_no_error (error);
289   g_assert (result != NULL);
290   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
291   g_variant_unref (result);
292   /* ... hence we wait for the g-properties-changed signal to be delivered */
293   _g_assert_signal_received (proxy, "g-properties-changed");
294   /* ... and now we finally, check that the cached value has been invalidated */
295   variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
296   g_assert (variant == NULL);
297 }
298
299 /* ---------------------------------------------------------------------------------------------------- */
300 /* Test that the signal aspects of GDBusProxy works */
301 /* ---------------------------------------------------------------------------------------------------- */
302
303 static void
304 test_proxy_signals_on_signal (GDBusProxy  *proxy,
305                               const gchar *sender_name,
306                               const gchar *signal_name,
307                               GVariant    *parameters,
308                               gpointer     user_data)
309 {
310   GString *s = user_data;
311
312   g_assert_cmpstr (signal_name, ==, "TestSignal");
313   g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(sov)");
314
315   g_variant_print_string (parameters, s, TRUE);
316 }
317
318 typedef struct
319 {
320   GMainLoop *internal_loop;
321   GString *s;
322 } TestSignalData;
323
324 static void
325 test_proxy_signals_on_emit_signal_cb (GDBusProxy   *proxy,
326                                       GAsyncResult *res,
327                                       gpointer      user_data)
328 {
329   TestSignalData *data = user_data;
330   GError *error;
331   GVariant *result;
332
333   error = NULL;
334   result = g_dbus_proxy_call_finish (proxy,
335                                      res,
336                                      &error);
337   g_assert_no_error (error);
338   g_assert (result != NULL);
339   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
340   g_variant_unref (result);
341
342   /* check that the signal was recieved before we got the method result */
343   g_assert (strlen (data->s->str) > 0);
344
345   /* break out of the loop */
346   g_main_loop_quit (data->internal_loop);
347 }
348
349 static void
350 test_signals (GDBusProxy *proxy)
351 {
352   GError *error;
353   GString *s;
354   gulong signal_handler_id;
355   TestSignalData data;
356   GVariant *result;
357
358   error = NULL;
359
360   /*
361    * Ask the service to emit a signal and check that we receive it.
362    *
363    * Note that blocking calls don't block in the mainloop so wait for the signal (which
364    * is dispatched before the method reply)
365    */
366   s = g_string_new (NULL);
367   signal_handler_id = g_signal_connect (proxy,
368                                         "g-signal",
369                                         G_CALLBACK (test_proxy_signals_on_signal),
370                                         s);
371
372   result = g_dbus_proxy_call_sync (proxy,
373                                    "EmitSignal",
374                                    g_variant_new ("(so)",
375                                                   "Accept the next proposition you hear",
376                                                   "/some/path"),
377                                    G_DBUS_CALL_FLAGS_NONE,
378                                    -1,
379                                    NULL,
380                                    &error);
381   g_assert_no_error (error);
382   g_assert (result != NULL);
383   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
384   g_variant_unref (result);
385   /* check that we haven't received the signal just yet */
386   g_assert (strlen (s->str) == 0);
387   /* and now wait for the signal */
388   _g_assert_signal_received (proxy, "g-signal");
389   g_assert_cmpstr (s->str,
390                    ==,
391                    "('Accept the next proposition you hear .. in bed!', objectpath '/some/path/in/bed', <'a variant'>)");
392   g_signal_handler_disconnect (proxy, signal_handler_id);
393   g_string_free (s, TRUE);
394
395   /*
396    * Now do this async to check the signal is received before the method returns.
397    */
398   s = g_string_new (NULL);
399   data.internal_loop = g_main_loop_new (NULL, FALSE);
400   data.s = s;
401   signal_handler_id = g_signal_connect (proxy,
402                                         "g-signal",
403                                         G_CALLBACK (test_proxy_signals_on_signal),
404                                         s);
405   g_dbus_proxy_call (proxy,
406                      "EmitSignal",
407                      g_variant_new ("(so)",
408                                     "You will make a great programmer",
409                                     "/some/other/path"),
410                      G_DBUS_CALL_FLAGS_NONE,
411                      -1,
412                      NULL,
413                      (GAsyncReadyCallback) test_proxy_signals_on_emit_signal_cb,
414                      &data);
415   g_main_loop_run (data.internal_loop);
416   g_main_loop_unref (data.internal_loop);
417   g_assert_cmpstr (s->str,
418                    ==,
419                    "('You will make a great programmer .. in bed!', objectpath '/some/other/path/in/bed', <'a variant'>)");
420   g_signal_handler_disconnect (proxy, signal_handler_id);
421   g_string_free (s, TRUE);
422 }
423
424 /* ---------------------------------------------------------------------------------------------------- */
425
426 static void
427 test_bogus_method_return (GDBusProxy *proxy)
428 {
429   GError *error = NULL;
430   GVariant *result;
431
432   result = g_dbus_proxy_call_sync (proxy,
433                                    "PairReturn",
434                                    NULL,
435                                    G_DBUS_CALL_FLAGS_NONE,
436                                    -1,
437                                    NULL,
438                                    &error);
439   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
440   g_error_free (error);
441   g_assert (result == NULL);
442 }
443
444 #if 0 /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999 */
445 static void
446 test_bogus_signal (GDBusProxy *proxy)
447 {
448   GError *error = NULL;
449   GVariant *result;
450   GDBusInterfaceInfo *old_iface_info;
451
452   result = g_dbus_proxy_call_sync (proxy,
453                                    "EmitSignal2",
454                                    NULL,
455                                    G_DBUS_CALL_FLAGS_NONE,
456                                    -1,
457                                    NULL,
458                                    &error);
459   g_assert_no_error (error);
460   g_assert (result != NULL);
461   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
462   g_variant_unref (result);
463
464   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
465     {
466       /* and now wait for the signal that will never arrive */
467       _g_assert_signal_received (proxy, "g-signal");
468     }
469   g_test_trap_assert_stderr ("*Dropping signal TestSignal2 of type (i) since the type from the expected interface is (u)*");
470   g_test_trap_assert_failed();
471
472   /* Our main branch will also do g_warning() when running the mainloop so
473    * temporarily remove the expected interface
474    */
475   old_iface_info = g_dbus_proxy_get_interface_info (proxy);
476   g_dbus_proxy_set_interface_info (proxy, NULL);
477   _g_assert_signal_received (proxy, "g-signal");
478   g_dbus_proxy_set_interface_info (proxy, old_iface_info);
479 }
480
481 static void
482 test_bogus_property (GDBusProxy *proxy)
483 {
484   GError *error = NULL;
485   GVariant *result;
486   GDBusInterfaceInfo *old_iface_info;
487
488   /* Make the service emit a PropertiesChanged signal for property 'i' of type 'i' - since
489    * our introspection data has this as type 'u' we should get a warning on stderr.
490    */
491   result = g_dbus_proxy_call_sync (proxy,
492                                    "FrobSetProperty",
493                                    g_variant_new ("(sv)",
494                                                   "i", g_variant_new_int32 (42)),
495                                    G_DBUS_CALL_FLAGS_NONE,
496                                    -1,
497                                    NULL,
498                                    &error);
499   g_assert_no_error (error);
500   g_assert (result != NULL);
501   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
502   g_variant_unref (result);
503
504   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
505     {
506       /* and now wait for the signal that will never arrive */
507       _g_assert_signal_received (proxy, "g-properties-changed");
508     }
509   g_test_trap_assert_stderr ("*Received property i with type i does not match expected type u in the expected interface*");
510   g_test_trap_assert_failed();
511
512   /* Our main branch will also do g_warning() when running the mainloop so
513    * temporarily remove the expected interface
514    */
515   old_iface_info = g_dbus_proxy_get_interface_info (proxy);
516   g_dbus_proxy_set_interface_info (proxy, NULL);
517   _g_assert_signal_received (proxy, "g-properties-changed");
518   g_dbus_proxy_set_interface_info (proxy, old_iface_info);
519 }
520 #endif /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999 */
521
522 /* ---------------------------------------------------------------------------------------------------- */
523
524 static const gchar *frob_dbus_interface_xml =
525   "<node>"
526   "  <interface name='com.example.Frob'>"
527   /* PairReturn() is deliberately different from gdbus-testserver.py's definition */
528   "    <method name='PairReturn'>"
529   "      <arg type='u' name='somenumber' direction='in'/>"
530   "      <arg type='s' name='somestring' direction='out'/>"
531   "    </method>"
532   "    <method name='HelloWorld'>"
533   "      <arg type='s' name='somestring' direction='in'/>"
534   "      <arg type='s' name='somestring' direction='out'/>"
535   "    </method>"
536   "    <method name='Sleep'>"
537   "      <arg type='i' name='timeout' direction='in'/>"
538   "    </method>"
539   /* We deliberately only mention a single property here */
540   "    <property name='y' type='y' access='readwrite'/>"
541   /* The 'i' property is deliberately different from gdbus-testserver.py's definition */
542   "    <property name='i' type='u' access='readwrite'/>"
543   /* ::TestSignal2 is deliberately different from gdbus-testserver.py's definition */
544   "    <signal name='TestSignal2'>"
545   "      <arg type='u' name='somenumber'/>"
546   "    </signal>"
547   "  </interface>"
548   "</node>";
549 static GDBusInterfaceInfo *frob_dbus_interface_info;
550
551 static void
552 test_expected_interface (GDBusProxy *proxy)
553 {
554   GVariant *value;
555   GError *error;
556
557   /* This is obviously wrong but expected interface is not set so we don't fail... */
558   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
559   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
560   g_dbus_proxy_set_cached_property (proxy, "does-not-exist", g_variant_new_string ("something"));
561   g_dbus_proxy_set_cached_property (proxy, "does-not-exist", NULL);
562
563   /* Now repeat the method tests, with an expected interface set */
564   g_dbus_proxy_set_interface_info (proxy, frob_dbus_interface_info);
565   test_methods (proxy);
566   test_signals (proxy);
567
568   /* And also where we deliberately set the expected interface definition incorrectly */
569   test_bogus_method_return (proxy);
570   /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999
571   test_bogus_signal (proxy);
572   test_bogus_property (proxy);
573   */
574
575   if (g_test_undefined ())
576     {
577       /* Also check that we complain if setting a cached property of the wrong type */
578       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
579         {
580           g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
581         }
582       g_test_trap_assert_stderr ("*Trying to set property y of type s but according to the expected interface the type is y*");
583       g_test_trap_assert_failed();
584     }
585
586   /* this should work, however (since the type is correct) */
587   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
588
589   if (g_test_undefined ())
590     {
591       /* Try to get the value of a property where the type we expect is different from
592        * what we have in our cache (e.g. what the service returned)
593        */
594       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
595         {
596           value = g_dbus_proxy_get_cached_property (proxy, "i");
597         }
598       g_test_trap_assert_stderr ("*Trying to get property i with type i but according to the expected interface the type is u*");
599       g_test_trap_assert_failed();
600     }
601
602   /* Even if a property does not exist in expected_interface, looking it
603    * up, or setting it, should never fail. Because it could be that the
604    * property has been added to the service but the GDBusInterfaceInfo*
605    * passed to g_dbus_proxy_set_interface_info() just haven't been updated.
606    *
607    * See https://bugzilla.gnome.org/show_bug.cgi?id=660886
608    */
609   value = g_dbus_proxy_get_cached_property (proxy, "d");
610   g_assert (value != NULL);
611   g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
612   g_assert_cmpfloat (g_variant_get_double (value), ==, 7.5);
613   g_variant_unref (value);
614   /* update it via the cached property... */
615   g_dbus_proxy_set_cached_property (proxy, "d", g_variant_new_double (75.0));
616   /* ... and finally check that it has changed */
617   value = g_dbus_proxy_get_cached_property (proxy, "d");
618   g_assert (value != NULL);
619   g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
620   g_assert_cmpfloat (g_variant_get_double (value), ==, 75.0);
621   g_variant_unref (value);
622   /* now update it via the D-Bus interface... */
623   error = NULL;
624   value = g_dbus_proxy_call_sync (proxy, "FrobSetProperty",
625                                   g_variant_new ("(sv)", "d", g_variant_new_double (85.0)),
626                                   G_DBUS_CALL_FLAGS_NONE,
627                                   -1, NULL, &error);
628   g_assert_no_error (error);
629   g_assert (value != NULL);
630   g_assert_cmpstr (g_variant_get_type_string (value), ==, "()");
631   g_variant_unref (value);
632   /* ...ensure we receive the ::PropertiesChanged signal... */
633   _g_assert_signal_received (proxy, "g-properties-changed");
634   /* ... and finally check that it has changed */
635   value = g_dbus_proxy_get_cached_property (proxy, "d");
636   g_assert (value != NULL);
637   g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
638   g_assert_cmpfloat (g_variant_get_double (value), ==, 85.0);
639   g_variant_unref (value);
640 }
641
642 static void
643 test_basic (GDBusProxy *proxy)
644 {
645   GDBusConnection *connection;
646   GDBusConnection *conn;
647   GDBusProxyFlags flags;
648   GDBusInterfaceInfo *info;
649   gchar *name;
650   gchar *path;
651   gchar *interface;
652   gint timeout;
653
654   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
655
656   g_assert (g_dbus_proxy_get_connection (proxy) == connection);
657   g_assert (g_dbus_proxy_get_flags (proxy) == G_DBUS_PROXY_FLAGS_NONE);
658   g_assert (g_dbus_proxy_get_interface_info (proxy) == NULL);
659   g_assert_cmpstr (g_dbus_proxy_get_name (proxy), ==, "com.example.TestService");
660   g_assert_cmpstr (g_dbus_proxy_get_object_path (proxy), ==, "/com/example/TestObject");
661   g_assert_cmpstr (g_dbus_proxy_get_interface_name (proxy), ==, "com.example.Frob");
662   g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, -1);
663
664   g_object_get (proxy,
665                 "g-connection", &conn,
666                 "g-interface-info", &info,
667                 "g-flags", &flags,
668                 "g-name", &name,
669                 "g-object-path", &path,
670                 "g-interface-name", &interface,
671                 "g-default-timeout", &timeout,
672                 NULL);
673
674   g_assert (conn == connection);
675   g_assert (info == NULL);
676   g_assert_cmpint (flags, ==, G_DBUS_PROXY_FLAGS_NONE);
677   g_assert_cmpstr (name, ==, "com.example.TestService");
678   g_assert_cmpstr (path, ==, "/com/example/TestObject");
679   g_assert_cmpstr (interface, ==, "com.example.Frob");
680   g_assert_cmpint (timeout, ==, -1);
681
682   g_object_unref (conn);
683   g_free (name);
684   g_free (path);
685   g_free (interface);
686
687   g_object_unref (connection);
688 }
689
690 static void
691 test_proxy (void)
692 {
693   GDBusProxy *proxy;
694   GDBusConnection *connection;
695   GError *error;
696
697   session_bus_up ();
698
699   /* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
700    * until one can connect to the bus but that's not how things work right now
701    */
702   usleep (500 * 1000);
703
704   error = NULL;
705   connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
706                                NULL,
707                                &error);
708   g_assert_no_error (error);
709   error = NULL;
710   proxy = g_dbus_proxy_new_sync (connection,
711                                  G_DBUS_PROXY_FLAGS_NONE,
712                                  NULL,                      /* GDBusInterfaceInfo */
713                                  "com.example.TestService", /* name */
714                                  "/com/example/TestObject", /* object path */
715                                  "com.example.Frob",        /* interface */
716                                  NULL, /* GCancellable */
717                                  &error);
718   g_assert_no_error (error);
719
720   /* this is safe; testserver will exit once the bus goes away */
721   g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
722
723   _g_assert_property_notify (proxy, "g-name-owner");
724
725   test_basic (proxy);
726   test_methods (proxy);
727   test_properties (proxy);
728   test_signals (proxy);
729   test_expected_interface (proxy);
730
731   g_object_unref (proxy);
732   g_object_unref (connection);
733 }
734
735 /* ---------------------------------------------------------------------------------------------------- */
736
737 static void
738 proxy_ready (GObject      *source,
739              GAsyncResult *result,
740              gpointer      user_data)
741 {
742   GDBusProxy *proxy;
743   GError *error;
744
745   error = NULL;
746   proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
747   g_assert_no_error (error);
748
749   test_basic (proxy);
750   test_methods (proxy);
751   test_properties (proxy);
752   test_signals (proxy);
753   test_expected_interface (proxy);
754
755   g_object_unref (proxy);
756 }
757
758 static void
759 test_async (void)
760 {
761   g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
762                             G_DBUS_PROXY_FLAGS_NONE,
763                             NULL,                      /* GDBusInterfaceInfo */
764                             "com.example.TestService", /* name */
765                             "/com/example/TestObject", /* object path */
766                             "com.example.Frob",        /* interface */
767                             NULL, /* GCancellable */
768                             proxy_ready,
769                             NULL);
770 }
771
772 static void
773 test_no_properties (void)
774 {
775   GDBusProxy *proxy;
776   GError *error;
777
778   error = NULL;
779   proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
780                                          G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
781                                          NULL,                      /* GDBusInterfaceInfo */
782                                          "com.example.TestService", /* name */
783                                          "/com/example/TestObject", /* object path */
784                                          "com.example.Frob",        /* interface */
785                                          NULL, /* GCancellable */
786                                          &error);
787   g_assert_no_error (error);
788
789   test_properties (proxy);
790
791   g_object_unref (proxy);
792 }
793
794 int
795 main (int   argc,
796       char *argv[])
797 {
798   gint ret;
799   GDBusNodeInfo *introspection_data = NULL;
800
801   g_type_init ();
802   g_test_init (&argc, &argv, NULL);
803
804   introspection_data = g_dbus_node_info_new_for_xml (frob_dbus_interface_xml, NULL);
805   g_assert (introspection_data != NULL);
806   frob_dbus_interface_info = introspection_data->interfaces[0];
807
808   /* all the tests rely on a shared main loop */
809   loop = g_main_loop_new (NULL, FALSE);
810
811   /* all the tests use a session bus with a well-known address that we can bring up and down
812    * using session_bus_up() and session_bus_down().
813    */
814   g_unsetenv ("DISPLAY");
815   g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
816
817   g_test_add_func ("/gdbus/proxy", test_proxy);
818   g_test_add_func ("/gdbus/proxy/async", test_async);
819   g_test_add_func ("/gdbus/proxy/no-properties", test_no_properties);
820
821   ret = g_test_run();
822
823   g_dbus_node_info_unref (introspection_data);
824   return ret;
825 }