• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20 
21 #include <gio/gio.h>
22 #include <unistd.h>
23 
24 #include "gdbus-tests.h"
25 
26 /* all tests rely on a shared mainloop */
27 static GMainLoop *loop;
28 
29 /* ---------------------------------------------------------------------------------------------------- */
30 /* Test that g_bus_own_name() works correctly */
31 /* ---------------------------------------------------------------------------------------------------- */
32 
33 typedef struct
34 {
35   gboolean expect_null_connection;
36   guint num_bus_acquired;
37   guint num_acquired;
38   guint num_lost;
39   guint num_free_func;
40 } OwnNameData;
41 
42 static void
own_name_data_free_func(OwnNameData * data)43 own_name_data_free_func (OwnNameData *data)
44 {
45   data->num_free_func++;
46   g_main_loop_quit (loop);
47 }
48 
49 static void
bus_acquired_handler(GDBusConnection * connection,const gchar * name,gpointer user_data)50 bus_acquired_handler (GDBusConnection *connection,
51                       const gchar     *name,
52                       gpointer         user_data)
53 {
54   OwnNameData *data = user_data;
55   g_dbus_connection_set_exit_on_close (connection, FALSE);
56   data->num_bus_acquired += 1;
57   g_main_loop_quit (loop);
58 }
59 
60 static void
name_acquired_handler(GDBusConnection * connection,const gchar * name,gpointer user_data)61 name_acquired_handler (GDBusConnection *connection,
62                        const gchar     *name,
63                        gpointer         user_data)
64 {
65   OwnNameData *data = user_data;
66   data->num_acquired += 1;
67   g_main_loop_quit (loop);
68 }
69 
70 static void
name_lost_handler(GDBusConnection * connection,const gchar * name,gpointer user_data)71 name_lost_handler (GDBusConnection *connection,
72                    const gchar     *name,
73                    gpointer         user_data)
74 {
75   OwnNameData *data = user_data;
76   if (data->expect_null_connection)
77     {
78       g_assert (connection == NULL);
79     }
80   else
81     {
82       g_assert (connection != NULL);
83       g_dbus_connection_set_exit_on_close (connection, FALSE);
84     }
85   data->num_lost += 1;
86   g_main_loop_quit (loop);
87 }
88 
89 static void
test_bus_own_name(void)90 test_bus_own_name (void)
91 {
92   guint id;
93   guint id2;
94   OwnNameData data;
95   OwnNameData data2;
96   const gchar *name;
97   GDBusConnection *c;
98   GError *error;
99   gboolean name_has_owner_reply;
100   GDBusConnection *c2;
101   GVariant *result;
102 
103   error = NULL;
104   name = "org.gtk.GDBus.Name1";
105 
106   /*
107    * First check that name_lost_handler() is invoked if there is no bus.
108    *
109    * Also make sure name_lost_handler() isn't invoked when unowning the name.
110    */
111   data.num_bus_acquired = 0;
112   data.num_free_func = 0;
113   data.num_acquired = 0;
114   data.num_lost = 0;
115   data.expect_null_connection = TRUE;
116   id = g_bus_own_name (G_BUS_TYPE_SESSION,
117                        name,
118                        G_BUS_NAME_OWNER_FLAGS_NONE,
119                        bus_acquired_handler,
120                        name_acquired_handler,
121                        name_lost_handler,
122                        &data,
123                        (GDestroyNotify) own_name_data_free_func);
124   g_assert_cmpint (data.num_bus_acquired, ==, 0);
125   g_assert_cmpint (data.num_acquired, ==, 0);
126   g_assert_cmpint (data.num_lost,     ==, 0);
127   g_main_loop_run (loop);
128   g_assert_cmpint (data.num_bus_acquired, ==, 0);
129   g_assert_cmpint (data.num_acquired, ==, 0);
130   g_assert_cmpint (data.num_lost,     ==, 1);
131   g_bus_unown_name (id);
132   g_assert_cmpint (data.num_acquired, ==, 0);
133   g_assert_cmpint (data.num_lost,     ==, 1);
134   g_assert_cmpint (data.num_free_func, ==, 1);
135 
136   /*
137    * Bring up a bus, then own a name and check bus_acquired_handler() then name_acquired_handler() is invoked.
138    */
139   session_bus_up ();
140   data.num_bus_acquired = 0;
141   data.num_acquired = 0;
142   data.num_lost = 0;
143   data.expect_null_connection = FALSE;
144   id = g_bus_own_name (G_BUS_TYPE_SESSION,
145                        name,
146                        G_BUS_NAME_OWNER_FLAGS_NONE,
147                        bus_acquired_handler,
148                        name_acquired_handler,
149                        name_lost_handler,
150                        &data,
151                        (GDestroyNotify) own_name_data_free_func);
152   g_assert_cmpint (data.num_bus_acquired, ==, 0);
153   g_assert_cmpint (data.num_acquired, ==, 0);
154   g_assert_cmpint (data.num_lost,     ==, 0);
155   g_main_loop_run (loop);
156   g_assert_cmpint (data.num_bus_acquired, ==, 1);
157   g_assert_cmpint (data.num_acquired, ==, 0);
158   g_assert_cmpint (data.num_lost,     ==, 0);
159   g_main_loop_run (loop);
160   g_assert_cmpint (data.num_bus_acquired, ==, 1);
161   g_assert_cmpint (data.num_acquired, ==, 1);
162   g_assert_cmpint (data.num_lost,     ==, 0);
163 
164   /*
165    * Check that the name was actually acquired.
166    */
167   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
168   g_assert (c != NULL);
169   g_assert (!g_dbus_connection_is_closed (c));
170   result = g_dbus_connection_call_sync (c,
171                                         "org.freedesktop.DBus",  /* bus name */
172                                         "/org/freedesktop/DBus", /* object path */
173                                         "org.freedesktop.DBus",  /* interface name */
174                                         "NameHasOwner",          /* method name */
175                                         g_variant_new ("(s)", name),
176                                         G_VARIANT_TYPE ("(b)"),
177                                         G_DBUS_CALL_FLAGS_NONE,
178                                         -1,
179                                         NULL,
180                                         &error);
181   g_assert_no_error (error);
182   g_assert (result != NULL);
183   g_variant_get (result, "(b)", &name_has_owner_reply);
184   g_assert (name_has_owner_reply);
185   g_variant_unref (result);
186 
187   /*
188    * Stop owning the name - this should invoke our free func
189    */
190   g_bus_unown_name (id);
191   g_main_loop_run (loop);
192   g_assert_cmpint (data.num_free_func, ==, 2);
193 
194   /*
195    * Check that the name was actually released.
196    */
197   result = g_dbus_connection_call_sync (c,
198                                         "org.freedesktop.DBus",  /* bus name */
199                                         "/org/freedesktop/DBus", /* object path */
200                                         "org.freedesktop.DBus",  /* interface name */
201                                         "NameHasOwner",          /* method name */
202                                         g_variant_new ("(s)", name),
203                                         G_VARIANT_TYPE ("(b)"),
204                                         G_DBUS_CALL_FLAGS_NONE,
205                                         -1,
206                                         NULL,
207                                         &error);
208   g_assert_no_error (error);
209   g_assert (result != NULL);
210   g_variant_get (result, "(b)", &name_has_owner_reply);
211   g_assert (!name_has_owner_reply);
212   g_variant_unref (result);
213 
214   /* Now try owning the name and then immediately decide to unown the name */
215   g_assert_cmpint (data.num_bus_acquired, ==, 1);
216   g_assert_cmpint (data.num_acquired, ==, 1);
217   g_assert_cmpint (data.num_lost,     ==, 0);
218   g_assert_cmpint (data.num_free_func, ==, 2);
219   id = g_bus_own_name (G_BUS_TYPE_SESSION,
220                        name,
221                        G_BUS_NAME_OWNER_FLAGS_NONE,
222                        bus_acquired_handler,
223                        name_acquired_handler,
224                        name_lost_handler,
225                        &data,
226                        (GDestroyNotify) own_name_data_free_func);
227   g_assert_cmpint (data.num_bus_acquired, ==, 1);
228   g_assert_cmpint (data.num_acquired, ==, 1);
229   g_assert_cmpint (data.num_lost,     ==, 0);
230   g_assert_cmpint (data.num_free_func, ==, 2);
231   g_bus_unown_name (id);
232   g_assert_cmpint (data.num_bus_acquired, ==, 1);
233   g_assert_cmpint (data.num_acquired, ==, 1);
234   g_assert_cmpint (data.num_lost,     ==, 0);
235   g_assert_cmpint (data.num_free_func, ==, 2);
236   g_main_loop_run (loop); /* the GDestroyNotify is called in idle because the bus is acquired in idle */
237   g_assert_cmpint (data.num_free_func, ==, 3);
238 
239   /*
240    * Own the name again.
241    */
242   data.num_bus_acquired = 0;
243   data.num_acquired = 0;
244   data.num_lost = 0;
245   data.expect_null_connection = FALSE;
246   id = g_bus_own_name_with_closures (G_BUS_TYPE_SESSION,
247                                      name,
248                                      G_BUS_NAME_OWNER_FLAGS_NONE,
249                                      g_cclosure_new (G_CALLBACK (bus_acquired_handler),
250                                                      &data,
251                                                      NULL),
252                                      g_cclosure_new (G_CALLBACK (name_acquired_handler),
253                                                      &data,
254                                                      NULL),
255                                      g_cclosure_new (G_CALLBACK (name_lost_handler),
256                                                      &data,
257                                                      (GClosureNotify) own_name_data_free_func));
258   g_assert_cmpint (data.num_bus_acquired, ==, 0);
259   g_assert_cmpint (data.num_acquired, ==, 0);
260   g_assert_cmpint (data.num_lost,     ==, 0);
261   g_main_loop_run (loop);
262   g_assert_cmpint (data.num_bus_acquired, ==, 1);
263   g_assert_cmpint (data.num_acquired, ==, 0);
264   g_assert_cmpint (data.num_lost,     ==, 0);
265   g_main_loop_run (loop);
266   g_assert_cmpint (data.num_bus_acquired, ==, 1);
267   g_assert_cmpint (data.num_acquired, ==, 1);
268   g_assert_cmpint (data.num_lost,     ==, 0);
269 
270   /*
271    * Try owning the name with another object on the same connection  - this should
272    * fail because we already own the name.
273    */
274   data2.num_free_func = 0;
275   data2.num_bus_acquired = 0;
276   data2.num_acquired = 0;
277   data2.num_lost = 0;
278   data2.expect_null_connection = FALSE;
279   id2 = g_bus_own_name (G_BUS_TYPE_SESSION,
280                         name,
281                         G_BUS_NAME_OWNER_FLAGS_NONE,
282                         bus_acquired_handler,
283                         name_acquired_handler,
284                         name_lost_handler,
285                         &data2,
286                         (GDestroyNotify) own_name_data_free_func);
287   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
288   g_assert_cmpint (data2.num_acquired, ==, 0);
289   g_assert_cmpint (data2.num_lost,     ==, 0);
290   g_main_loop_run (loop);
291   g_assert_cmpint (data2.num_bus_acquired, ==, 1);
292   g_assert_cmpint (data2.num_acquired, ==, 0);
293   g_assert_cmpint (data2.num_lost,     ==, 0);
294   g_main_loop_run (loop);
295   g_assert_cmpint (data2.num_bus_acquired, ==, 1);
296   g_assert_cmpint (data2.num_acquired, ==, 0);
297   g_assert_cmpint (data2.num_lost,     ==, 1);
298   g_bus_unown_name (id2);
299   g_main_loop_run (loop);
300   g_assert_cmpint (data2.num_bus_acquired, ==, 1);
301   g_assert_cmpint (data2.num_acquired, ==, 0);
302   g_assert_cmpint (data2.num_lost,     ==, 1);
303   g_assert_cmpint (data2.num_free_func, ==, 1);
304 
305   /*
306    * Create a secondary (e.g. private) connection and try owning the name on that
307    * connection. This should fail both with and without _REPLACE because we
308    * didn't specify ALLOW_REPLACEMENT.
309    */
310   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
311   g_assert (c2 != NULL);
312   g_assert (!g_dbus_connection_is_closed (c2));
313   /* first without _REPLACE */
314   data2.num_bus_acquired = 0;
315   data2.num_acquired = 0;
316   data2.num_lost = 0;
317   data2.expect_null_connection = FALSE;
318   data2.num_free_func = 0;
319   id2 = g_bus_own_name_on_connection (c2,
320                                       name,
321                                       G_BUS_NAME_OWNER_FLAGS_NONE,
322                                       name_acquired_handler,
323                                       name_lost_handler,
324                                       &data2,
325                                       (GDestroyNotify) own_name_data_free_func);
326   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
327   g_assert_cmpint (data2.num_acquired, ==, 0);
328   g_assert_cmpint (data2.num_lost,     ==, 0);
329   g_main_loop_run (loop);
330   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
331   g_assert_cmpint (data2.num_acquired, ==, 0);
332   g_assert_cmpint (data2.num_lost,     ==, 1);
333   g_bus_unown_name (id2);
334   g_main_loop_run (loop);
335   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
336   g_assert_cmpint (data2.num_acquired, ==, 0);
337   g_assert_cmpint (data2.num_lost,     ==, 1);
338   g_assert_cmpint (data2.num_free_func, ==, 1);
339   /* then with _REPLACE */
340   data2.num_bus_acquired = 0;
341   data2.num_acquired = 0;
342   data2.num_lost = 0;
343   data2.expect_null_connection = FALSE;
344   data2.num_free_func = 0;
345   id2 = g_bus_own_name_on_connection (c2,
346                                       name,
347                                       G_BUS_NAME_OWNER_FLAGS_REPLACE,
348                                       name_acquired_handler,
349                                       name_lost_handler,
350                                       &data2,
351                                       (GDestroyNotify) own_name_data_free_func);
352   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
353   g_assert_cmpint (data2.num_acquired, ==, 0);
354   g_assert_cmpint (data2.num_lost,     ==, 0);
355   g_main_loop_run (loop);
356   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
357   g_assert_cmpint (data2.num_acquired, ==, 0);
358   g_assert_cmpint (data2.num_lost,     ==, 1);
359   g_bus_unown_name (id2);
360   g_main_loop_run (loop);
361   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
362   g_assert_cmpint (data2.num_acquired, ==, 0);
363   g_assert_cmpint (data2.num_lost,     ==, 1);
364   g_assert_cmpint (data2.num_free_func, ==, 1);
365 
366   /*
367    * Stop owning the name and grab it again with _ALLOW_REPLACEMENT.
368    */
369   data.expect_null_connection = FALSE;
370   g_bus_unown_name (id);
371   g_main_loop_run (loop);
372   g_assert_cmpint (data.num_bus_acquired, ==, 1);
373   g_assert_cmpint (data.num_acquired, ==, 1);
374   g_assert_cmpint (data.num_free_func, ==, 4);
375   /* grab it again */
376   data.num_bus_acquired = 0;
377   data.num_acquired = 0;
378   data.num_lost = 0;
379   data.expect_null_connection = FALSE;
380   id = g_bus_own_name (G_BUS_TYPE_SESSION,
381                        name,
382                        G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
383                        bus_acquired_handler,
384                        name_acquired_handler,
385                        name_lost_handler,
386                        &data,
387                        (GDestroyNotify) own_name_data_free_func);
388   g_assert_cmpint (data.num_bus_acquired, ==, 0);
389   g_assert_cmpint (data.num_acquired, ==, 0);
390   g_assert_cmpint (data.num_lost,     ==, 0);
391   g_main_loop_run (loop);
392   g_assert_cmpint (data.num_bus_acquired, ==, 1);
393   g_assert_cmpint (data.num_acquired, ==, 0);
394   g_assert_cmpint (data.num_lost,     ==, 0);
395   g_main_loop_run (loop);
396   g_assert_cmpint (data.num_bus_acquired, ==, 1);
397   g_assert_cmpint (data.num_acquired, ==, 1);
398   g_assert_cmpint (data.num_lost,     ==, 0);
399 
400   /*
401    * Now try to grab the name from the secondary connection.
402    *
403    */
404   /* first without _REPLACE - this won't make us acquire the name */
405   data2.num_bus_acquired = 0;
406   data2.num_acquired = 0;
407   data2.num_lost = 0;
408   data2.expect_null_connection = FALSE;
409   data2.num_free_func = 0;
410   id2 = g_bus_own_name_on_connection (c2,
411                                       name,
412                                       G_BUS_NAME_OWNER_FLAGS_NONE,
413                                       name_acquired_handler,
414                                       name_lost_handler,
415                                       &data2,
416                                       (GDestroyNotify) own_name_data_free_func);
417   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
418   g_assert_cmpint (data2.num_acquired, ==, 0);
419   g_assert_cmpint (data2.num_lost,     ==, 0);
420   g_main_loop_run (loop);
421   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
422   g_assert_cmpint (data2.num_acquired, ==, 0);
423   g_assert_cmpint (data2.num_lost,     ==, 1);
424   g_bus_unown_name (id2);
425   g_main_loop_run (loop);
426   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
427   g_assert_cmpint (data2.num_acquired, ==, 0);
428   g_assert_cmpint (data2.num_lost,     ==, 1);
429   g_assert_cmpint (data2.num_free_func, ==, 1);
430   /* then with _REPLACE - here we should acquire the name - e.g. owner should lose it
431    * and owner2 should acquire it  */
432   data2.num_bus_acquired = 0;
433   data2.num_acquired = 0;
434   data2.num_lost = 0;
435   data2.expect_null_connection = FALSE;
436   data2.num_free_func = 0;
437   id2 = g_bus_own_name_on_connection (c2,
438                                       name,
439                                       G_BUS_NAME_OWNER_FLAGS_REPLACE,
440                                       name_acquired_handler,
441                                       name_lost_handler,
442                                       &data2,
443                                       (GDestroyNotify) own_name_data_free_func);
444   g_assert_cmpint (data.num_acquired, ==, 1);
445   g_assert_cmpint (data.num_lost,     ==, 0);
446   g_assert_cmpint (data2.num_acquired, ==, 0);
447   g_assert_cmpint (data2.num_lost,     ==, 0);
448   /* wait for handlers for both owner and owner2 to fire */
449   while (data.num_lost == 0 || data2.num_acquired == 0)
450     g_main_loop_run (loop);
451   g_assert_cmpint (data.num_acquired, ==, 1);
452   g_assert_cmpint (data.num_lost,     ==, 1);
453   g_assert_cmpint (data2.num_acquired, ==, 1);
454   g_assert_cmpint (data2.num_lost,     ==, 0);
455   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
456   /* ok, make owner2 release the name - then wait for owner to automagically reacquire it */
457   g_bus_unown_name (id2);
458   g_main_loop_run (loop);
459   g_main_loop_run (loop);
460   g_assert_cmpint (data2.num_free_func, ==, 1);
461   g_assert_cmpint (data.num_acquired, ==, 2);
462   g_assert_cmpint (data.num_lost,     ==, 1);
463 
464   /*
465    * Finally, nuke the bus and check name_lost_handler() is invoked.
466    *
467    */
468   data.expect_null_connection = TRUE;
469   session_bus_stop ();
470   while (data.num_lost != 2)
471     g_main_loop_run (loop);
472   g_assert_cmpint (data.num_acquired, ==, 2);
473   g_assert_cmpint (data.num_lost,     ==, 2);
474   g_bus_unown_name (id);
475   g_main_loop_run (loop);
476   g_assert_cmpint (data.num_free_func, ==, 5);
477 
478   g_object_unref (c);
479   g_object_unref (c2);
480 
481   session_bus_down ();
482 }
483 
484 /* ---------------------------------------------------------------------------------------------------- */
485 /* Test that g_bus_watch_name() works correctly */
486 /* ---------------------------------------------------------------------------------------------------- */
487 
488 typedef struct
489 {
490   gboolean expect_null_connection;
491   guint num_acquired;
492   guint num_lost;
493   guint num_appeared;
494   guint num_vanished;
495   guint num_free_func;
496 } WatchNameData;
497 
498 static void
watch_name_data_free_func(WatchNameData * data)499 watch_name_data_free_func (WatchNameData *data)
500 {
501   data->num_free_func++;
502   g_main_loop_quit (loop);
503 }
504 
505 static void
w_bus_acquired_handler(GDBusConnection * connection,const gchar * name,gpointer user_data)506 w_bus_acquired_handler (GDBusConnection *connection,
507                         const gchar     *name,
508                         gpointer         user_data)
509 {
510 }
511 
512 static void
w_name_acquired_handler(GDBusConnection * connection,const gchar * name,gpointer user_data)513 w_name_acquired_handler (GDBusConnection *connection,
514                          const gchar     *name,
515                          gpointer         user_data)
516 {
517   WatchNameData *data = user_data;
518   data->num_acquired += 1;
519   g_main_loop_quit (loop);
520 }
521 
522 static void
w_name_lost_handler(GDBusConnection * connection,const gchar * name,gpointer user_data)523 w_name_lost_handler (GDBusConnection *connection,
524                      const gchar     *name,
525                      gpointer         user_data)
526 {
527   WatchNameData *data = user_data;
528   data->num_lost += 1;
529   g_main_loop_quit (loop);
530 }
531 
532 static void
name_appeared_handler(GDBusConnection * connection,const gchar * name,const gchar * name_owner,gpointer user_data)533 name_appeared_handler (GDBusConnection *connection,
534                        const gchar     *name,
535                        const gchar     *name_owner,
536                        gpointer         user_data)
537 {
538   WatchNameData *data = user_data;
539 
540   if (data->expect_null_connection)
541     {
542       g_assert (connection == NULL);
543     }
544   else
545     {
546       g_assert (connection != NULL);
547       g_dbus_connection_set_exit_on_close (connection, FALSE);
548     }
549   data->num_appeared += 1;
550   g_main_loop_quit (loop);
551 }
552 
553 static void
name_vanished_handler(GDBusConnection * connection,const gchar * name,gpointer user_data)554 name_vanished_handler (GDBusConnection *connection,
555                        const gchar     *name,
556                        gpointer         user_data)
557 {
558   WatchNameData *data = user_data;
559 
560   if (data->expect_null_connection)
561     {
562       g_assert (connection == NULL);
563     }
564   else
565     {
566       g_assert (connection != NULL);
567       g_dbus_connection_set_exit_on_close (connection, FALSE);
568     }
569   data->num_vanished += 1;
570   g_main_loop_quit (loop);
571 }
572 
573 typedef struct
574 {
575   guint watcher_flags;
576   gboolean watch_with_closures;
577   gboolean existing_service;
578 } WatchNameTest;
579 
580 static const WatchNameTest watch_no_closures_no_flags = {
581   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE,
582   .watch_with_closures = FALSE,
583   .existing_service = FALSE
584 };
585 
586 static const WatchNameTest watch_no_closures_flags_auto_start = {
587   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
588   .watch_with_closures = FALSE,
589   .existing_service = FALSE
590 };
591 
592 static const WatchNameTest watch_no_closures_flags_auto_start_service_exist = {
593   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
594   .watch_with_closures = FALSE,
595   .existing_service = TRUE
596 };
597 
598 static const WatchNameTest watch_closures_no_flags = {
599   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE,
600   .watch_with_closures = TRUE,
601   .existing_service = FALSE
602 };
603 
604 static const WatchNameTest watch_closures_flags_auto_start = {
605   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
606   .watch_with_closures = TRUE,
607   .existing_service = FALSE
608 };
609 
610 static void
stop_service(GDBusConnection * connection,WatchNameData * data)611 stop_service (GDBusConnection *connection,
612               WatchNameData   *data)
613 {
614   GError *error = NULL;
615   GDBusProxy *proxy = NULL;
616 
617   data->num_vanished = 0;
618 
619   proxy = g_dbus_proxy_new_sync (connection,
620                                  G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
621                                  NULL,
622                                  "org.gtk.GDBus.FakeService",
623                                  "/org/gtk/GDBus/FakeService",
624                                  "org.gtk.GDBus.FakeService",
625                                  NULL,
626                                  &error);
627   g_assert_no_error (error);
628 
629   g_dbus_proxy_call_sync (proxy,
630                           "Quit",
631                           NULL,
632                           G_DBUS_CALL_FLAGS_NO_AUTO_START,
633                           100,
634                           NULL,
635                           &error);
636   g_assert_no_error (error);
637   g_object_unref (proxy);
638   while (data->num_vanished == 0)
639     g_main_loop_run (loop);
640 }
641 
642 static void
test_bus_watch_name(gconstpointer d)643 test_bus_watch_name (gconstpointer d)
644 {
645   WatchNameData data;
646   guint id;
647   guint owner_id;
648   GDBusConnection *connection;
649   const WatchNameTest *watch_name_test;
650   const gchar *name;
651 
652   watch_name_test = (WatchNameTest *) d;
653 
654   if (watch_name_test->existing_service)
655     {
656       name = "org.gtk.GDBus.FakeService";
657     }
658   else
659     {
660       name = "org.gtk.GDBus.Name1";
661     }
662 
663   /*
664    * First check that name_vanished_handler() is invoked if there is no bus.
665    *
666    * Also make sure name_vanished_handler() isn't invoked when unwatching the name.
667    */
668   data.num_free_func = 0;
669   data.num_appeared = 0;
670   data.num_vanished = 0;
671   data.expect_null_connection = TRUE;
672   id = g_bus_watch_name (G_BUS_TYPE_SESSION,
673                          name,
674                          watch_name_test->watcher_flags,
675                          name_appeared_handler,
676                          name_vanished_handler,
677                          &data,
678                          (GDestroyNotify) watch_name_data_free_func);
679   g_assert_cmpint (data.num_appeared, ==, 0);
680   g_assert_cmpint (data.num_vanished, ==, 0);
681   g_main_loop_run (loop);
682   g_assert_cmpint (data.num_appeared, ==, 0);
683   g_assert_cmpint (data.num_vanished, ==, 1);
684   g_bus_unwatch_name (id);
685   g_assert_cmpint (data.num_appeared, ==, 0);
686   g_assert_cmpint (data.num_vanished, ==, 1);
687   g_assert_cmpint (data.num_free_func, ==, 1);
688 
689   /*
690    * Now bring up a bus, own a name, and then start watching it.
691    */
692   session_bus_up ();
693   /* own the name */
694   data.num_free_func = 0;
695   data.num_acquired = 0;
696   data.num_lost = 0;
697   data.expect_null_connection = FALSE;
698   owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
699                              name,
700                              G_BUS_NAME_OWNER_FLAGS_NONE,
701                              w_bus_acquired_handler,
702                              w_name_acquired_handler,
703                              w_name_lost_handler,
704                              &data,
705                              (GDestroyNotify) watch_name_data_free_func);
706   g_main_loop_run (loop);
707   g_assert_cmpint (data.num_acquired, ==, 1);
708   g_assert_cmpint (data.num_lost, ==, 0);
709 
710   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
711   g_assert (connection != NULL);
712 
713   /* now watch the name */
714   data.num_appeared = 0;
715   data.num_vanished = 0;
716   if (watch_name_test->watch_with_closures)
717     {
718       id = g_bus_watch_name_on_connection_with_closures (connection,
719                                                          name,
720                                                          watch_name_test->watcher_flags,
721                                                          g_cclosure_new (G_CALLBACK (name_appeared_handler),
722                                                                          &data,
723                                                                          NULL),
724                                                          g_cclosure_new (G_CALLBACK (name_vanished_handler),
725                                                                          &data,
726                                                                          (GClosureNotify) watch_name_data_free_func));
727     }
728   else
729     {
730       id = g_bus_watch_name_on_connection (connection,
731                                            name,
732                                            watch_name_test->watcher_flags,
733                                            name_appeared_handler,
734                                            name_vanished_handler,
735                                            &data,
736                                            (GDestroyNotify) watch_name_data_free_func);
737     }
738   g_assert_cmpint (data.num_appeared, ==, 0);
739   g_assert_cmpint (data.num_vanished, ==, 0);
740   g_main_loop_run (loop);
741   g_assert_cmpint (data.num_appeared, ==, 1);
742   g_assert_cmpint (data.num_vanished, ==, 0);
743 
744   /*
745    * Unwatch the name.
746    */
747   g_bus_unwatch_name (id);
748   g_assert_cmpint (data.num_free_func, ==, 1);
749 
750   /* unown the name */
751   g_bus_unown_name (owner_id);
752   g_main_loop_run (loop);
753   g_assert_cmpint (data.num_acquired, ==, 1);
754   g_assert_cmpint (data.num_free_func, ==, 2);
755 
756   /*
757    * Create a watcher and then make a name be owned.
758    *
759    * This should trigger name_appeared_handler() ...
760    */
761   /* watch the name */
762   data.num_appeared = 0;
763   data.num_vanished = 0;
764   data.num_free_func = 0;
765   if (watch_name_test->watch_with_closures)
766     {
767       id = g_bus_watch_name_with_closures (G_BUS_TYPE_SESSION,
768                                            name,
769                                            watch_name_test->watcher_flags,
770                                            g_cclosure_new (G_CALLBACK (name_appeared_handler),
771                                                            &data,
772                                                            NULL),
773                                            g_cclosure_new (G_CALLBACK (name_vanished_handler),
774                                                            &data,
775                                                            (GClosureNotify) watch_name_data_free_func));
776     }
777   else
778     {
779       id = g_bus_watch_name (G_BUS_TYPE_SESSION,
780                              name,
781                              watch_name_test->watcher_flags,
782                              name_appeared_handler,
783                              name_vanished_handler,
784                              &data,
785                              (GDestroyNotify) watch_name_data_free_func);
786     }
787 
788   g_assert_cmpint (data.num_appeared, ==, 0);
789   g_assert_cmpint (data.num_vanished, ==, 0);
790   g_main_loop_run (loop);
791   if (watch_name_test->existing_service)
792     {
793       g_assert_cmpint (data.num_appeared, ==, 1);
794       g_assert_cmpint (data.num_vanished, ==, 0);
795     }
796   else
797     {
798       g_assert_cmpint (data.num_appeared, ==, 0);
799       g_assert_cmpint (data.num_vanished, ==, 1);
800     }
801 
802   if (!watch_name_test->existing_service)
803     {
804       /* own the name */
805       data.num_acquired = 0;
806       data.num_lost = 0;
807       data.expect_null_connection = FALSE;
808       owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
809                                  name,
810                                  G_BUS_NAME_OWNER_FLAGS_NONE,
811                                  w_bus_acquired_handler,
812                                  w_name_acquired_handler,
813                                  w_name_lost_handler,
814                                  &data,
815                                  (GDestroyNotify) watch_name_data_free_func);
816       while (data.num_acquired == 0 || data.num_appeared == 0)
817         g_main_loop_run (loop);
818       g_assert_cmpint (data.num_acquired, ==, 1);
819       g_assert_cmpint (data.num_lost, ==, 0);
820       g_assert_cmpint (data.num_appeared, ==, 1);
821       g_assert_cmpint (data.num_vanished, ==, 1);
822     }
823 
824   data.expect_null_connection = TRUE;
825   if (watch_name_test->existing_service)
826     {
827       data.expect_null_connection = FALSE;
828       stop_service (connection, &data);
829     }
830   g_object_unref (connection);
831   /*
832    * Nuke the bus and check that the name vanishes and is lost.
833    */
834   session_bus_stop ();
835   if (!watch_name_test->existing_service)
836     {
837       g_main_loop_run (loop);
838       g_assert_cmpint (data.num_lost, ==, 1);
839       g_assert_cmpint (data.num_vanished, ==, 2);
840     }
841   else
842     {
843       g_assert_cmpint (data.num_lost, ==, 0);
844       g_assert_cmpint (data.num_vanished, ==, 1);
845     }
846   g_bus_unwatch_name (id);
847   g_assert_cmpint (data.num_free_func, ==, 1);
848 
849   if (!watch_name_test->existing_service)
850     {
851       g_bus_unown_name (owner_id);
852       g_main_loop_run (loop);
853       g_assert_cmpint (data.num_free_func, ==, 2);
854     }
855   session_bus_down ();
856 }
857 
858 /* ---------------------------------------------------------------------------------------------------- */
859 
860 static void
test_validate_names(void)861 test_validate_names (void)
862 {
863   guint n;
864   static const struct
865   {
866     gboolean name;
867     gboolean unique;
868     gboolean interface;
869     const gchar *string;
870   } names[] = {
871     { 1, 0, 1, "valid.well_known.name"},
872     { 1, 0, 0, "valid.well-known.name"},
873     { 1, 1, 0, ":valid.unique.name"},
874     { 0, 0, 0, "invalid.5well_known.name"},
875     { 0, 0, 0, "4invalid.5well_known.name"},
876     { 1, 1, 0, ":4valid.5unique.name"},
877     { 0, 0, 0, ""},
878     { 1, 0, 1, "very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.name1"}, /* 255 */
879     { 0, 0, 0, "very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.name12"}, /* 256 - too long! */
880     { 0, 0, 0, ".starts.with.a.dot"},
881     { 0, 0, 0, "contains.invalid;.characters"},
882     { 0, 0, 0, "contains.inva/lid.characters"},
883     { 0, 0, 0, "contains.inva[lid.characters"},
884     { 0, 0, 0, "contains.inva]lid.characters"},
885     { 0, 0, 0, "contains.inva_æøå_lid.characters"},
886     { 1, 1, 0, ":1.1"},
887   };
888 
889   for (n = 0; n < G_N_ELEMENTS (names); n++)
890     {
891       if (names[n].name)
892         g_assert (g_dbus_is_name (names[n].string));
893       else
894         g_assert (!g_dbus_is_name (names[n].string));
895 
896       if (names[n].unique)
897         g_assert (g_dbus_is_unique_name (names[n].string));
898       else
899         g_assert (!g_dbus_is_unique_name (names[n].string));
900 
901       if (names[n].interface)
902         g_assert (g_dbus_is_interface_name (names[n].string));
903       else
904         g_assert (!g_dbus_is_interface_name (names[n].string));
905     }
906 }
907 
908 static void
assert_cmp_escaped_object_path(const gchar * s,const gchar * correct_escaped)909 assert_cmp_escaped_object_path (const gchar *s,
910                                 const gchar *correct_escaped)
911 {
912   gchar *escaped;
913   guint8 *unescaped;
914 
915   escaped = g_dbus_escape_object_path (s);
916   g_assert_cmpstr (escaped, ==, correct_escaped);
917 
918   g_free (escaped);
919   escaped = g_dbus_escape_object_path_bytestring ((const guint8 *) s);
920   g_assert_cmpstr (escaped, ==, correct_escaped);
921 
922   unescaped = g_dbus_unescape_object_path (escaped);
923   g_assert_cmpstr ((const gchar *) unescaped, ==, s);
924 
925   g_free (escaped);
926   g_free (unescaped);
927 }
928 
929 static void
test_escape_object_path(void)930 test_escape_object_path (void)
931 {
932   assert_cmp_escaped_object_path ("Foo42", "Foo42");
933   assert_cmp_escaped_object_path ("foo.bar.baz", "foo_2ebar_2ebaz");
934   assert_cmp_escaped_object_path ("foo_bar_baz", "foo_5fbar_5fbaz");
935   assert_cmp_escaped_object_path ("_", "_5f");
936   assert_cmp_escaped_object_path ("__", "_5f_5f");
937   assert_cmp_escaped_object_path ("", "_");
938   assert_cmp_escaped_object_path (":1.42", "_3a1_2e42");
939   assert_cmp_escaped_object_path ("a/b", "a_2fb");
940   assert_cmp_escaped_object_path (" ", "_20");
941   assert_cmp_escaped_object_path ("\n", "_0a");
942 
943   g_assert_null (g_dbus_unescape_object_path ("_ii"));
944   g_assert_null (g_dbus_unescape_object_path ("döner"));
945   g_assert_null (g_dbus_unescape_object_path ("_00"));
946   g_assert_null (g_dbus_unescape_object_path ("_61"));
947   g_assert_null (g_dbus_unescape_object_path ("_ga"));
948   g_assert_null (g_dbus_unescape_object_path ("_ag"));
949 }
950 
951 /* ---------------------------------------------------------------------------------------------------- */
952 
953 int
main(int argc,char * argv[])954 main (int   argc,
955       char *argv[])
956 {
957   gint ret;
958 
959   g_test_init (&argc, &argv, NULL);
960 
961   loop = g_main_loop_new (NULL, FALSE);
962 
963   g_test_dbus_unset ();
964 
965   g_test_add_func ("/gdbus/validate-names", test_validate_names);
966   g_test_add_func ("/gdbus/bus-own-name", test_bus_own_name);
967   g_test_add_data_func ("/gdbus/bus-watch-name",
968                         &watch_no_closures_no_flags,
969                         test_bus_watch_name);
970   g_test_add_data_func ("/gdbus/bus-watch-name-auto-start",
971                         &watch_no_closures_flags_auto_start,
972                         test_bus_watch_name);
973   g_test_add_data_func ("/gdbus/bus-watch-name-auto-start-service-exist",
974                         &watch_no_closures_flags_auto_start_service_exist,
975                         test_bus_watch_name);
976   g_test_add_data_func ("/gdbus/bus-watch-name-closures",
977                         &watch_closures_no_flags,
978                         test_bus_watch_name);
979   g_test_add_data_func ("/gdbus/bus-watch-name-closures-auto-start",
980                         &watch_closures_flags_auto_start,
981                         test_bus_watch_name);
982   g_test_add_func ("/gdbus/escape-object-path", test_escape_object_path);
983   ret = g_test_run();
984 
985   g_main_loop_unref (loop);
986 
987   return ret;
988 }
989