tizen: kdbus: make i explicitly positive in make_single_header_vector
[platform/upstream/glib.git] / gio / tests / gdbus-names.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  * Copyright (C) 2021 Frederic Martinsons
5  *
6  * SPDX-License-Identifier: LGPL-2.1-or-later
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General
19  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20  *
21  * Author: David Zeuthen <davidz@redhat.com>
22  * Author: Frederic Martinsons <frederic.martinsons@gmail.com>
23  */
24
25 #include <gio/gio.h>
26 #include <unistd.h>
27
28 #include "gdbus-tests.h"
29
30 /* ---------------------------------------------------------------------------------------------------- */
31 /* Test that g_bus_own_name() works correctly */
32 /* ---------------------------------------------------------------------------------------------------- */
33
34 typedef struct
35 {
36   gboolean expect_null_connection;
37   guint num_bus_acquired;
38   guint num_acquired;
39   guint num_lost;
40   guint num_free_func;
41   GMainContext *main_context;  /* (unowned) */
42 } OwnNameData;
43
44 static void
45 own_name_data_free_func (OwnNameData *data)
46 {
47   data->num_free_func++;
48   g_main_context_wakeup (data->main_context);
49 }
50
51 static void
52 bus_acquired_handler (GDBusConnection *connection,
53                       const gchar     *name,
54                       gpointer         user_data)
55 {
56   OwnNameData *data = user_data;
57   g_dbus_connection_set_exit_on_close (connection, FALSE);
58   data->num_bus_acquired += 1;
59   g_main_context_wakeup (data->main_context);
60 }
61
62 static void
63 name_acquired_handler (GDBusConnection *connection,
64                        const gchar     *name,
65                        gpointer         user_data)
66 {
67   OwnNameData *data = user_data;
68   data->num_acquired += 1;
69   g_main_context_wakeup (data->main_context);
70 }
71
72 static void
73 name_lost_handler (GDBusConnection *connection,
74                    const gchar     *name,
75                    gpointer         user_data)
76 {
77   OwnNameData *data = user_data;
78   if (data->expect_null_connection)
79     {
80       g_assert (connection == NULL);
81     }
82   else
83     {
84       g_assert (connection != NULL);
85       g_dbus_connection_set_exit_on_close (connection, FALSE);
86     }
87   data->num_lost += 1;
88   g_main_context_wakeup (data->main_context);
89 }
90
91 static void
92 test_bus_own_name (void)
93 {
94   guint id;
95   guint id2;
96   OwnNameData data;
97   OwnNameData data2;
98   const gchar *name;
99   GDBusConnection *c;
100   GError *error;
101   gboolean name_has_owner_reply;
102   GDBusConnection *c2;
103   GVariant *result;
104   GMainContext *main_context = NULL;  /* use the global default for now */
105
106   error = NULL;
107   name = "org.gtk.GDBus.Name1";
108
109   /*
110    * First check that name_lost_handler() is invoked if there is no bus.
111    *
112    * Also make sure name_lost_handler() isn't invoked when unowning the name.
113    */
114   data.num_bus_acquired = 0;
115   data.num_free_func = 0;
116   data.num_acquired = 0;
117   data.num_lost = 0;
118   data.expect_null_connection = TRUE;
119   data.main_context = main_context;
120   id = g_bus_own_name (G_BUS_TYPE_SESSION,
121                        name,
122                        G_BUS_NAME_OWNER_FLAGS_NONE,
123                        bus_acquired_handler,
124                        name_acquired_handler,
125                        name_lost_handler,
126                        &data,
127                        (GDestroyNotify) own_name_data_free_func);
128   g_assert_cmpint (data.num_bus_acquired, ==, 0);
129   g_assert_cmpint (data.num_acquired, ==, 0);
130   g_assert_cmpint (data.num_lost,     ==, 0);
131
132   while (data.num_lost < 1)
133     g_main_context_iteration (main_context, TRUE);
134
135   g_assert_cmpint (data.num_bus_acquired, ==, 0);
136   g_assert_cmpint (data.num_acquired, ==, 0);
137   g_assert_cmpint (data.num_lost,     ==, 1);
138   g_bus_unown_name (id);
139   g_assert_cmpint (data.num_acquired, ==, 0);
140   g_assert_cmpint (data.num_lost,     ==, 1);
141   g_assert_cmpint (data.num_free_func, ==, 1);
142
143   /*
144    * Bring up a bus, then own a name and check bus_acquired_handler() then name_acquired_handler() is invoked.
145    */
146   session_bus_up ();
147   data.num_bus_acquired = 0;
148   data.num_acquired = 0;
149   data.num_lost = 0;
150   data.expect_null_connection = FALSE;
151   id = g_bus_own_name (G_BUS_TYPE_SESSION,
152                        name,
153                        G_BUS_NAME_OWNER_FLAGS_NONE,
154                        bus_acquired_handler,
155                        name_acquired_handler,
156                        name_lost_handler,
157                        &data,
158                        (GDestroyNotify) own_name_data_free_func);
159   g_assert_cmpint (data.num_bus_acquired, ==, 0);
160   g_assert_cmpint (data.num_acquired, ==, 0);
161   g_assert_cmpint (data.num_lost,     ==, 0);
162
163   while (data.num_bus_acquired < 1)
164     g_main_context_iteration (main_context, TRUE);
165
166   g_assert_cmpint (data.num_bus_acquired, ==, 1);
167   g_assert_cmpint (data.num_acquired, ==, 0);
168   g_assert_cmpint (data.num_lost,     ==, 0);
169
170   while (data.num_acquired < 1)
171     g_main_context_iteration (main_context, TRUE);
172
173   g_assert_cmpint (data.num_bus_acquired, ==, 1);
174   g_assert_cmpint (data.num_acquired, ==, 1);
175   g_assert_cmpint (data.num_lost,     ==, 0);
176
177   /*
178    * Check that the name was actually acquired.
179    */
180   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
181   g_assert (c != NULL);
182   g_assert (!g_dbus_connection_is_closed (c));
183   result = g_dbus_connection_call_sync (c,
184                                         "org.freedesktop.DBus",  /* bus name */
185                                         "/org/freedesktop/DBus", /* object path */
186                                         "org.freedesktop.DBus",  /* interface name */
187                                         "NameHasOwner",          /* method name */
188                                         g_variant_new ("(s)", name),
189                                         G_VARIANT_TYPE ("(b)"),
190                                         G_DBUS_CALL_FLAGS_NONE,
191                                         -1,
192                                         NULL,
193                                         &error);
194   g_assert_no_error (error);
195   g_assert (result != NULL);
196   g_variant_get (result, "(b)", &name_has_owner_reply);
197   g_assert (name_has_owner_reply);
198   g_variant_unref (result);
199
200   /*
201    * Stop owning the name - this should invoke our free func
202    */
203   g_bus_unown_name (id);
204   while (data.num_free_func < 2)
205     g_main_context_iteration (main_context, TRUE);
206   g_assert_cmpint (data.num_free_func, ==, 2);
207
208   /*
209    * Check that the name was actually released.
210    */
211   result = g_dbus_connection_call_sync (c,
212                                         "org.freedesktop.DBus",  /* bus name */
213                                         "/org/freedesktop/DBus", /* object path */
214                                         "org.freedesktop.DBus",  /* interface name */
215                                         "NameHasOwner",          /* method name */
216                                         g_variant_new ("(s)", name),
217                                         G_VARIANT_TYPE ("(b)"),
218                                         G_DBUS_CALL_FLAGS_NONE,
219                                         -1,
220                                         NULL,
221                                         &error);
222   g_assert_no_error (error);
223   g_assert (result != NULL);
224   g_variant_get (result, "(b)", &name_has_owner_reply);
225   g_assert (!name_has_owner_reply);
226   g_variant_unref (result);
227
228   /* Now try owning the name and then immediately decide to unown the name */
229   g_assert_cmpint (data.num_bus_acquired, ==, 1);
230   g_assert_cmpint (data.num_acquired, ==, 1);
231   g_assert_cmpint (data.num_lost,     ==, 0);
232   g_assert_cmpint (data.num_free_func, ==, 2);
233   id = g_bus_own_name (G_BUS_TYPE_SESSION,
234                        name,
235                        G_BUS_NAME_OWNER_FLAGS_NONE,
236                        bus_acquired_handler,
237                        name_acquired_handler,
238                        name_lost_handler,
239                        &data,
240                        (GDestroyNotify) own_name_data_free_func);
241   g_assert_cmpint (data.num_bus_acquired, ==, 1);
242   g_assert_cmpint (data.num_acquired, ==, 1);
243   g_assert_cmpint (data.num_lost,     ==, 0);
244   g_assert_cmpint (data.num_free_func, ==, 2);
245   g_bus_unown_name (id);
246   g_assert_cmpint (data.num_bus_acquired, ==, 1);
247   g_assert_cmpint (data.num_acquired, ==, 1);
248   g_assert_cmpint (data.num_lost,     ==, 0);
249   g_assert_cmpint (data.num_free_func, ==, 2);
250
251   /* the GDestroyNotify is called in idle because the bus is acquired in idle */
252   while (data.num_free_func < 3)
253     g_main_context_iteration (main_context, TRUE);
254
255   g_assert_cmpint (data.num_free_func, ==, 3);
256
257   /*
258    * Own the name again.
259    */
260   data.num_bus_acquired = 0;
261   data.num_acquired = 0;
262   data.num_lost = 0;
263   data.expect_null_connection = FALSE;
264   id = g_bus_own_name_with_closures (G_BUS_TYPE_SESSION,
265                                      name,
266                                      G_BUS_NAME_OWNER_FLAGS_NONE,
267                                      g_cclosure_new (G_CALLBACK (bus_acquired_handler),
268                                                      &data,
269                                                      NULL),
270                                      g_cclosure_new (G_CALLBACK (name_acquired_handler),
271                                                      &data,
272                                                      NULL),
273                                      g_cclosure_new (G_CALLBACK (name_lost_handler),
274                                                      &data,
275                                                      (GClosureNotify) own_name_data_free_func));
276   g_assert_cmpint (data.num_bus_acquired, ==, 0);
277   g_assert_cmpint (data.num_acquired, ==, 0);
278   g_assert_cmpint (data.num_lost,     ==, 0);
279
280   while (data.num_bus_acquired < 1)
281     g_main_context_iteration (main_context, TRUE);
282
283   g_assert_cmpint (data.num_bus_acquired, ==, 1);
284   g_assert_cmpint (data.num_acquired, ==, 0);
285   g_assert_cmpint (data.num_lost,     ==, 0);
286
287   while (data.num_acquired < 1)
288     g_main_context_iteration (main_context, TRUE);
289
290   g_assert_cmpint (data.num_bus_acquired, ==, 1);
291   g_assert_cmpint (data.num_acquired, ==, 1);
292   g_assert_cmpint (data.num_lost,     ==, 0);
293
294   /*
295    * Try owning the name with another object on the same connection  - this should
296    * fail because we already own the name.
297    */
298   data2.num_free_func = 0;
299   data2.num_bus_acquired = 0;
300   data2.num_acquired = 0;
301   data2.num_lost = 0;
302   data2.expect_null_connection = FALSE;
303   data2.main_context = main_context;
304   id2 = g_bus_own_name (G_BUS_TYPE_SESSION,
305                         name,
306                         G_BUS_NAME_OWNER_FLAGS_NONE,
307                         bus_acquired_handler,
308                         name_acquired_handler,
309                         name_lost_handler,
310                         &data2,
311                         (GDestroyNotify) own_name_data_free_func);
312   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
313   g_assert_cmpint (data2.num_acquired, ==, 0);
314   g_assert_cmpint (data2.num_lost,     ==, 0);
315
316   while (data2.num_bus_acquired < 1)
317     g_main_context_iteration (main_context, TRUE);
318
319   g_assert_cmpint (data2.num_bus_acquired, ==, 1);
320   g_assert_cmpint (data2.num_acquired, ==, 0);
321   g_assert_cmpint (data2.num_lost,     ==, 0);
322
323   while (data2.num_lost < 1)
324     g_main_context_iteration (main_context, TRUE);
325
326   g_assert_cmpint (data2.num_bus_acquired, ==, 1);
327   g_assert_cmpint (data2.num_acquired, ==, 0);
328   g_assert_cmpint (data2.num_lost,     ==, 1);
329
330   g_bus_unown_name (id2);
331   while (data2.num_free_func < 1)
332     g_main_context_iteration (main_context, TRUE);
333
334   g_assert_cmpint (data2.num_bus_acquired, ==, 1);
335   g_assert_cmpint (data2.num_acquired, ==, 0);
336   g_assert_cmpint (data2.num_lost,     ==, 1);
337   g_assert_cmpint (data2.num_free_func, ==, 1);
338
339   /*
340    * Create a secondary (e.g. private) connection and try owning the name on that
341    * connection. This should fail both with and without _REPLACE because we
342    * didn't specify ALLOW_REPLACEMENT.
343    */
344   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
345   g_assert (c2 != NULL);
346   g_assert (!g_dbus_connection_is_closed (c2));
347   /* first without _REPLACE */
348   data2.num_bus_acquired = 0;
349   data2.num_acquired = 0;
350   data2.num_lost = 0;
351   data2.expect_null_connection = FALSE;
352   data2.num_free_func = 0;
353   id2 = g_bus_own_name_on_connection (c2,
354                                       name,
355                                       G_BUS_NAME_OWNER_FLAGS_NONE,
356                                       name_acquired_handler,
357                                       name_lost_handler,
358                                       &data2,
359                                       (GDestroyNotify) own_name_data_free_func);
360   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
361   g_assert_cmpint (data2.num_acquired, ==, 0);
362   g_assert_cmpint (data2.num_lost,     ==, 0);
363
364   while (data2.num_lost < 1)
365     g_main_context_iteration (main_context, TRUE);
366
367   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
368   g_assert_cmpint (data2.num_acquired, ==, 0);
369   g_assert_cmpint (data2.num_lost,     ==, 1);
370
371   g_bus_unown_name (id2);
372   while (data2.num_free_func < 1)
373     g_main_context_iteration (main_context, TRUE);
374
375   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
376   g_assert_cmpint (data2.num_acquired, ==, 0);
377   g_assert_cmpint (data2.num_lost,     ==, 1);
378   g_assert_cmpint (data2.num_free_func, ==, 1);
379   /* then with _REPLACE */
380   data2.num_bus_acquired = 0;
381   data2.num_acquired = 0;
382   data2.num_lost = 0;
383   data2.expect_null_connection = FALSE;
384   data2.num_free_func = 0;
385   id2 = g_bus_own_name_on_connection (c2,
386                                       name,
387                                       G_BUS_NAME_OWNER_FLAGS_REPLACE,
388                                       name_acquired_handler,
389                                       name_lost_handler,
390                                       &data2,
391                                       (GDestroyNotify) own_name_data_free_func);
392   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
393   g_assert_cmpint (data2.num_acquired, ==, 0);
394   g_assert_cmpint (data2.num_lost,     ==, 0);
395
396   while (data2.num_lost < 1)
397     g_main_context_iteration (main_context, TRUE);
398
399   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
400   g_assert_cmpint (data2.num_acquired, ==, 0);
401   g_assert_cmpint (data2.num_lost,     ==, 1);
402
403   g_bus_unown_name (id2);
404   while (data2.num_free_func < 1)
405     g_main_context_iteration (main_context, TRUE);
406
407   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
408   g_assert_cmpint (data2.num_acquired, ==, 0);
409   g_assert_cmpint (data2.num_lost,     ==, 1);
410   g_assert_cmpint (data2.num_free_func, ==, 1);
411
412   /*
413    * Stop owning the name and grab it again with _ALLOW_REPLACEMENT.
414    */
415   data.expect_null_connection = FALSE;
416   g_bus_unown_name (id);
417   while (data.num_bus_acquired < 1 || data.num_free_func < 4)
418     g_main_context_iteration (main_context, TRUE);
419
420   g_assert_cmpint (data.num_bus_acquired, ==, 1);
421   g_assert_cmpint (data.num_acquired, ==, 1);
422   g_assert_cmpint (data.num_free_func, ==, 4);
423   /* grab it again */
424   data.num_bus_acquired = 0;
425   data.num_acquired = 0;
426   data.num_lost = 0;
427   data.expect_null_connection = FALSE;
428   id = g_bus_own_name (G_BUS_TYPE_SESSION,
429                        name,
430                        G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
431                        bus_acquired_handler,
432                        name_acquired_handler,
433                        name_lost_handler,
434                        &data,
435                        (GDestroyNotify) own_name_data_free_func);
436   g_assert_cmpint (data.num_bus_acquired, ==, 0);
437   g_assert_cmpint (data.num_acquired, ==, 0);
438   g_assert_cmpint (data.num_lost,     ==, 0);
439
440   while (data.num_bus_acquired < 1)
441     g_main_context_iteration (main_context, TRUE);
442
443   g_assert_cmpint (data.num_bus_acquired, ==, 1);
444   g_assert_cmpint (data.num_acquired, ==, 0);
445   g_assert_cmpint (data.num_lost,     ==, 0);
446
447   while (data.num_acquired < 1)
448     g_main_context_iteration (main_context, TRUE);
449
450   g_assert_cmpint (data.num_bus_acquired, ==, 1);
451   g_assert_cmpint (data.num_acquired, ==, 1);
452   g_assert_cmpint (data.num_lost,     ==, 0);
453
454   /*
455    * Now try to grab the name from the secondary connection.
456    *
457    */
458   /* first without _REPLACE - this won't make us acquire the name */
459   data2.num_bus_acquired = 0;
460   data2.num_acquired = 0;
461   data2.num_lost = 0;
462   data2.expect_null_connection = FALSE;
463   data2.num_free_func = 0;
464   id2 = g_bus_own_name_on_connection (c2,
465                                       name,
466                                       G_BUS_NAME_OWNER_FLAGS_NONE,
467                                       name_acquired_handler,
468                                       name_lost_handler,
469                                       &data2,
470                                       (GDestroyNotify) own_name_data_free_func);
471   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
472   g_assert_cmpint (data2.num_acquired, ==, 0);
473   g_assert_cmpint (data2.num_lost,     ==, 0);
474
475   while (data2.num_lost < 1)
476     g_main_context_iteration (main_context, TRUE);
477
478   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
479   g_assert_cmpint (data2.num_acquired, ==, 0);
480   g_assert_cmpint (data2.num_lost,     ==, 1);
481
482   g_bus_unown_name (id2);
483   while (data2.num_free_func < 1)
484     g_main_context_iteration (main_context, TRUE);
485
486   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
487   g_assert_cmpint (data2.num_acquired, ==, 0);
488   g_assert_cmpint (data2.num_lost,     ==, 1);
489   g_assert_cmpint (data2.num_free_func, ==, 1);
490   /* then with _REPLACE - here we should acquire the name - e.g. owner should lose it
491    * and owner2 should acquire it  */
492   data2.num_bus_acquired = 0;
493   data2.num_acquired = 0;
494   data2.num_lost = 0;
495   data2.expect_null_connection = FALSE;
496   data2.num_free_func = 0;
497   id2 = g_bus_own_name_on_connection (c2,
498                                       name,
499                                       G_BUS_NAME_OWNER_FLAGS_REPLACE,
500                                       name_acquired_handler,
501                                       name_lost_handler,
502                                       &data2,
503                                       (GDestroyNotify) own_name_data_free_func);
504   g_assert_cmpint (data.num_acquired, ==, 1);
505   g_assert_cmpint (data.num_lost,     ==, 0);
506   g_assert_cmpint (data2.num_acquired, ==, 0);
507   g_assert_cmpint (data2.num_lost,     ==, 0);
508
509   /* wait for handlers for both owner and owner2 to fire */
510   while (data.num_lost == 0 || data2.num_acquired == 0)
511     g_main_context_iteration (main_context, TRUE);
512
513   g_assert_cmpint (data.num_acquired, ==, 1);
514   g_assert_cmpint (data.num_lost,     ==, 1);
515   g_assert_cmpint (data2.num_acquired, ==, 1);
516   g_assert_cmpint (data2.num_lost,     ==, 0);
517   g_assert_cmpint (data2.num_bus_acquired, ==, 0);
518
519   /* ok, make owner2 release the name - then wait for owner to automagically reacquire it */
520   g_bus_unown_name (id2);
521   while (data.num_acquired < 2 || data2.num_free_func < 1)
522     g_main_context_iteration (main_context, TRUE);
523
524   g_assert_cmpint (data2.num_free_func, ==, 1);
525   g_assert_cmpint (data.num_acquired, ==, 2);
526   g_assert_cmpint (data.num_lost,     ==, 1);
527
528   /*
529    * Finally, nuke the bus and check name_lost_handler() is invoked.
530    *
531    */
532   data.expect_null_connection = TRUE;
533   session_bus_stop ();
534   while (data.num_lost != 2)
535     g_main_context_iteration (main_context, TRUE);
536
537   g_assert_cmpint (data.num_acquired, ==, 2);
538   g_assert_cmpint (data.num_lost,     ==, 2);
539
540   g_bus_unown_name (id);
541   while (data.num_free_func < 5)
542     g_main_context_iteration (main_context, TRUE);
543
544   g_assert_cmpint (data.num_free_func, ==, 5);
545
546   g_object_unref (c);
547   g_object_unref (c2);
548
549   session_bus_down ();
550 }
551
552 /* ---------------------------------------------------------------------------------------------------- */
553 /* Test that g_bus_watch_name() works correctly */
554 /* ---------------------------------------------------------------------------------------------------- */
555
556 typedef struct
557 {
558   gboolean expect_null_connection;
559   guint num_acquired;
560   guint num_lost;
561   guint num_appeared;
562   guint num_vanished;
563   guint num_free_func;
564   GMainContext *main_context;  /* (unowned), for the main test thread */
565 } WatchNameData;
566
567 typedef struct
568 {
569   WatchNameData data;
570   GDBusConnection *connection;
571   GMutex cond_mutex;
572   GCond cond;
573   gboolean started;
574   gboolean name_acquired;
575   gboolean ended;
576   gboolean unwatch_early;
577   GMutex mutex;
578   guint watch_id;
579   GMainContext *thread_context;  /* (unowned), only accessed from watcher_thread() */
580 } WatchNameThreadData;
581
582 static void
583 watch_name_data_free_func (WatchNameData *data)
584 {
585   data->num_free_func++;
586   g_main_context_wakeup (data->main_context);
587 }
588
589 static void
590 w_bus_acquired_handler (GDBusConnection *connection,
591                         const gchar     *name,
592                         gpointer         user_data)
593 {
594 }
595
596 static void
597 w_name_acquired_handler (GDBusConnection *connection,
598                          const gchar     *name,
599                          gpointer         user_data)
600 {
601   OwnNameData *data = user_data;
602   data->num_acquired += 1;
603   g_main_context_wakeup (data->main_context);
604 }
605
606 static void
607 w_name_lost_handler (GDBusConnection *connection,
608                      const gchar     *name,
609                      gpointer         user_data)
610 {
611   OwnNameData *data = user_data;
612   data->num_lost += 1;
613   g_main_context_wakeup (data->main_context);
614 }
615
616 static void
617 name_appeared_handler (GDBusConnection *connection,
618                        const gchar     *name,
619                        const gchar     *name_owner,
620                        gpointer         user_data)
621 {
622   WatchNameData *data = user_data;
623
624   if (data->expect_null_connection)
625     {
626       g_assert (connection == NULL);
627     }
628   else
629     {
630       g_assert (connection != NULL);
631       g_dbus_connection_set_exit_on_close (connection, FALSE);
632     }
633   data->num_appeared += 1;
634   g_main_context_wakeup (data->main_context);
635 }
636
637 static void
638 name_vanished_handler (GDBusConnection *connection,
639                        const gchar     *name,
640                        gpointer         user_data)
641 {
642   WatchNameData *data = user_data;
643
644   if (data->expect_null_connection)
645     {
646       g_assert (connection == NULL);
647     }
648   else
649     {
650       g_assert (connection != NULL);
651       g_dbus_connection_set_exit_on_close (connection, FALSE);
652     }
653   data->num_vanished += 1;
654   g_main_context_wakeup (data->main_context);
655 }
656
657 typedef struct
658 {
659   guint watcher_flags;
660   gboolean watch_with_closures;
661   gboolean existing_service;
662 } WatchNameTest;
663
664 static const WatchNameTest watch_no_closures_no_flags = {
665   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE,
666   .watch_with_closures = FALSE,
667   .existing_service = FALSE
668 };
669
670 static const WatchNameTest watch_no_closures_flags_auto_start = {
671   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
672   .watch_with_closures = FALSE,
673   .existing_service = FALSE
674 };
675
676 static const WatchNameTest watch_no_closures_flags_auto_start_service_exist = {
677   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
678   .watch_with_closures = FALSE,
679   .existing_service = TRUE
680 };
681
682 static const WatchNameTest watch_closures_no_flags = {
683   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE,
684   .watch_with_closures = TRUE,
685   .existing_service = FALSE
686 };
687
688 static const WatchNameTest watch_closures_flags_auto_start = {
689   .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
690   .watch_with_closures = TRUE,
691   .existing_service = FALSE
692 };
693
694 static void
695 stop_service (GDBusConnection *connection,
696               WatchNameData   *data)
697 {
698   GError *error = NULL;
699   GDBusProxy *proxy = NULL;
700   GVariant *result = NULL;
701   GMainContext *main_context = NULL;  /* use the global default for now */
702
703   data->num_vanished = 0;
704
705   proxy = g_dbus_proxy_new_sync (connection,
706                                  G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
707                                  NULL,
708                                  "org.gtk.GDBus.FakeService",
709                                  "/org/gtk/GDBus/FakeService",
710                                  "org.gtk.GDBus.FakeService",
711                                  NULL,
712                                  &error);
713   g_assert_no_error (error);
714
715   result = g_dbus_proxy_call_sync (proxy,
716                                    "Quit",
717                                    NULL,
718                                    G_DBUS_CALL_FLAGS_NO_AUTO_START,
719                                    100,
720                                    NULL,
721                                    &error);
722   g_assert_no_error (error);
723   g_object_unref (proxy);
724   if (result)
725     g_variant_unref (result);
726   while (data->num_vanished == 0)
727     g_main_context_iteration (main_context, TRUE);
728 }
729
730 static void
731 test_bus_watch_name (gconstpointer d)
732 {
733   WatchNameData data;
734   OwnNameData own_data;
735   guint id;
736   guint owner_id;
737   GDBusConnection *connection;
738   const WatchNameTest *watch_name_test;
739   const gchar *name;
740   GMainContext *main_context = NULL;  /* use the global default for now */
741
742   watch_name_test = (WatchNameTest *) d;
743
744   if (watch_name_test->existing_service)
745     {
746       name = "org.gtk.GDBus.FakeService";
747     }
748   else
749     {
750       name = "org.gtk.GDBus.Name1";
751     }
752
753   /*
754    * First check that name_vanished_handler() is invoked if there is no bus.
755    *
756    * Also make sure name_vanished_handler() isn't invoked when unwatching the name.
757    */
758   data.num_free_func = 0;
759   data.num_appeared = 0;
760   data.num_vanished = 0;
761   data.expect_null_connection = TRUE;
762   data.main_context = main_context;
763   id = g_bus_watch_name (G_BUS_TYPE_SESSION,
764                          name,
765                          watch_name_test->watcher_flags,
766                          name_appeared_handler,
767                          name_vanished_handler,
768                          &data,
769                          (GDestroyNotify) watch_name_data_free_func);
770   g_assert_cmpint (data.num_appeared, ==, 0);
771   g_assert_cmpint (data.num_vanished, ==, 0);
772
773   while (data.num_vanished < 1)
774     g_main_context_iteration (main_context, TRUE);
775
776   g_assert_cmpint (data.num_appeared, ==, 0);
777   g_assert_cmpint (data.num_vanished, ==, 1);
778
779   g_bus_unwatch_name (id);
780   while (data.num_free_func < 1)
781     g_main_context_iteration (main_context, TRUE);
782
783   g_assert_cmpint (data.num_appeared, ==, 0);
784   g_assert_cmpint (data.num_vanished, ==, 1);
785   g_assert_cmpint (data.num_free_func, ==, 1);
786   data.num_free_func = 0;
787
788   /*
789    * Now bring up a bus, own a name, and then start watching it.
790    */
791   session_bus_up ();
792   /* own the name */
793   own_data.num_free_func = 0;
794   own_data.num_acquired = 0;
795   own_data.num_lost = 0;
796   data.expect_null_connection = FALSE;
797   own_data.main_context = main_context;
798   owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
799                              name,
800                              G_BUS_NAME_OWNER_FLAGS_NONE,
801                              w_bus_acquired_handler,
802                              w_name_acquired_handler,
803                              w_name_lost_handler,
804                              &own_data,
805                              (GDestroyNotify) own_name_data_free_func);
806
807   while (own_data.num_acquired < 1)
808     g_main_context_iteration (main_context, TRUE);
809
810   g_assert_cmpint (own_data.num_acquired, ==, 1);
811   g_assert_cmpint (own_data.num_lost, ==, 0);
812
813   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
814   g_assert (connection != NULL);
815
816   /* now watch the name */
817   data.num_appeared = 0;
818   data.num_vanished = 0;
819   if (watch_name_test->watch_with_closures)
820     {
821       id = g_bus_watch_name_on_connection_with_closures (connection,
822                                                          name,
823                                                          watch_name_test->watcher_flags,
824                                                          g_cclosure_new (G_CALLBACK (name_appeared_handler),
825                                                                          &data,
826                                                                          NULL),
827                                                          g_cclosure_new (G_CALLBACK (name_vanished_handler),
828                                                                          &data,
829                                                                          (GClosureNotify) watch_name_data_free_func));
830     }
831   else
832     {
833       id = g_bus_watch_name_on_connection (connection,
834                                            name,
835                                            watch_name_test->watcher_flags,
836                                            name_appeared_handler,
837                                            name_vanished_handler,
838                                            &data,
839                                            (GDestroyNotify) watch_name_data_free_func);
840     }
841   g_assert_cmpint (data.num_appeared, ==, 0);
842   g_assert_cmpint (data.num_vanished, ==, 0);
843
844   while (data.num_appeared < 1)
845     g_main_context_iteration (main_context, TRUE);
846
847   g_assert_cmpint (data.num_appeared, ==, 1);
848   g_assert_cmpint (data.num_vanished, ==, 0);
849
850   /*
851    * Unwatch the name.
852    */
853   g_bus_unwatch_name (id);
854   while (data.num_free_func < 1)
855     g_main_context_iteration (main_context, TRUE);
856
857   g_assert_cmpint (data.num_free_func, ==, 1);
858
859   /* unown the name */
860   g_bus_unown_name (owner_id);
861   while (own_data.num_free_func < 1)
862     g_main_context_iteration (main_context, TRUE);
863
864   g_assert_cmpint (own_data.num_acquired, ==, 1);
865   g_assert_cmpint (own_data.num_free_func, ==, 1);
866   own_data.num_free_func = 0;
867   /*
868    * Create a watcher and then make a name be owned.
869    *
870    * This should trigger name_appeared_handler() ...
871    */
872   /* watch the name */
873   data.num_appeared = 0;
874   data.num_vanished = 0;
875   data.num_free_func = 0;
876   if (watch_name_test->watch_with_closures)
877     {
878       id = g_bus_watch_name_with_closures (G_BUS_TYPE_SESSION,
879                                            name,
880                                            watch_name_test->watcher_flags,
881                                            g_cclosure_new (G_CALLBACK (name_appeared_handler),
882                                                            &data,
883                                                            NULL),
884                                            g_cclosure_new (G_CALLBACK (name_vanished_handler),
885                                                            &data,
886                                                            (GClosureNotify) watch_name_data_free_func));
887     }
888   else
889     {
890       id = g_bus_watch_name (G_BUS_TYPE_SESSION,
891                              name,
892                              watch_name_test->watcher_flags,
893                              name_appeared_handler,
894                              name_vanished_handler,
895                              &data,
896                              (GDestroyNotify) watch_name_data_free_func);
897     }
898
899   g_assert_cmpint (data.num_appeared, ==, 0);
900   g_assert_cmpint (data.num_vanished, ==, 0);
901
902   while (data.num_appeared == 0 && data.num_vanished == 0)
903     g_main_context_iteration (main_context, TRUE);
904
905   if (watch_name_test->existing_service)
906     {
907       g_assert_cmpint (data.num_appeared, ==, 1);
908       g_assert_cmpint (data.num_vanished, ==, 0);
909     }
910   else
911     {
912       g_assert_cmpint (data.num_appeared, ==, 0);
913       g_assert_cmpint (data.num_vanished, ==, 1);
914     }
915
916   if (!watch_name_test->existing_service)
917     {
918       /* own the name */
919       own_data.num_acquired = 0;
920       own_data.num_lost = 0;
921       own_data.expect_null_connection = FALSE;
922       own_data.main_context = main_context;
923       owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
924                                  name,
925                                  G_BUS_NAME_OWNER_FLAGS_NONE,
926                                  w_bus_acquired_handler,
927                                  w_name_acquired_handler,
928                                  w_name_lost_handler,
929                                  &own_data,
930                                  (GDestroyNotify) own_name_data_free_func);
931
932       while (own_data.num_acquired == 0 || data.num_appeared == 0)
933         g_main_context_iteration (main_context, TRUE);
934
935       g_assert_cmpint (own_data.num_acquired, ==, 1);
936       g_assert_cmpint (own_data.num_lost, ==, 0);
937       g_assert_cmpint (data.num_appeared, ==, 1);
938       g_assert_cmpint (data.num_vanished, ==, 1);
939     }
940
941   data.expect_null_connection = TRUE;
942   if (watch_name_test->existing_service)
943     {
944       data.expect_null_connection = FALSE;
945       stop_service (connection, &data);
946     }
947   g_object_unref (connection);
948   /*
949    * Nuke the bus and check that the name vanishes and is lost.
950    */
951   session_bus_stop ();
952   if (!watch_name_test->existing_service)
953     {
954       while (own_data.num_lost < 1 || data.num_vanished < 2)
955         g_main_context_iteration (main_context, TRUE);
956       g_assert_cmpint (own_data.num_lost, ==, 1);
957       g_assert_cmpint (data.num_vanished, ==, 2);
958     }
959   else
960     {
961       g_assert_cmpint (own_data.num_lost, ==, 0);
962       g_assert_cmpint (data.num_vanished, ==, 1);
963     }
964
965   g_bus_unwatch_name (id);
966   while (data.num_free_func < 1)
967     g_main_context_iteration (main_context, TRUE);
968
969   g_assert_cmpint (data.num_free_func, ==, 1);
970
971   if (!watch_name_test->existing_service)
972     {
973       g_bus_unown_name (owner_id);
974       while (own_data.num_free_func < 1)
975         g_main_context_iteration (main_context, TRUE);
976
977       g_assert_cmpint (own_data.num_free_func, ==, 1);
978     }
979   session_bus_down ();
980 }
981
982 /* ---------------------------------------------------------------------------------------------------- */
983
984 /* Called in the same thread as watcher_thread() */
985 static void
986 t_watch_name_data_free_func (WatchNameThreadData *thread_data)
987 {
988   thread_data->data.num_free_func++;
989
990   g_assert_true (g_main_context_is_owner (thread_data->thread_context));
991   g_main_context_wakeup (thread_data->thread_context);
992 }
993
994 /* Called in the same thread as watcher_thread() */
995 static void
996 t_name_appeared_handler (GDBusConnection *connection,
997                          const gchar     *name,
998                          const gchar     *name_owner,
999                          gpointer         user_data)
1000 {
1001   WatchNameThreadData *thread_data = user_data;
1002   thread_data->data.num_appeared += 1;
1003
1004   g_assert_true (g_main_context_is_owner (thread_data->thread_context));
1005   g_main_context_wakeup (thread_data->thread_context);
1006 }
1007
1008 /* Called in the same thread as watcher_thread() */
1009 static void
1010 t_name_vanished_handler (GDBusConnection *connection,
1011                          const gchar     *name,
1012                          gpointer         user_data)
1013 {
1014   WatchNameThreadData *thread_data = user_data;
1015   thread_data->data.num_vanished += 1;
1016
1017   g_assert_true (g_main_context_is_owner (thread_data->thread_context));
1018   g_main_context_wakeup (thread_data->thread_context);
1019 }
1020
1021 /* Called in the thread which constructed the GDBusConnection */
1022 static void
1023 connection_closed_cb (GDBusConnection *connection,
1024                       gboolean         remote_peer_vanished,
1025                       GError          *error,
1026                       gpointer         user_data)
1027 {
1028   WatchNameThreadData *thread_data = (WatchNameThreadData *) user_data;
1029   if (thread_data->unwatch_early)
1030     {
1031       g_mutex_lock (&thread_data->mutex);
1032       g_bus_unwatch_name (g_atomic_int_get (&thread_data->watch_id));
1033       g_atomic_int_set (&thread_data->watch_id, 0);
1034       g_cond_signal (&thread_data->cond);
1035       g_mutex_unlock (&thread_data->mutex);
1036     }
1037 }
1038
1039 static gpointer
1040 watcher_thread (gpointer user_data)
1041 {
1042   WatchNameThreadData *thread_data = user_data;
1043   GMainContext *thread_context;
1044
1045   thread_context = g_main_context_new ();
1046   thread_data->thread_context = thread_context;
1047   g_main_context_push_thread_default (thread_context);
1048
1049   // Notify that the thread has started
1050   g_mutex_lock (&thread_data->cond_mutex);
1051   g_atomic_int_set (&thread_data->started, TRUE);
1052   g_cond_signal (&thread_data->cond);
1053   g_mutex_unlock (&thread_data->cond_mutex);
1054
1055   // Wait for the main thread to own the name before watching it
1056   g_mutex_lock (&thread_data->cond_mutex);
1057   while (!g_atomic_int_get (&thread_data->name_acquired))
1058     g_cond_wait (&thread_data->cond, &thread_data->cond_mutex);
1059   g_mutex_unlock (&thread_data->cond_mutex);
1060
1061   thread_data->data.num_appeared = 0;
1062   thread_data->data.num_vanished = 0;
1063   thread_data->data.num_free_func = 0;
1064   // g_signal_connect_after is important to have default handler be called before our code
1065   g_signal_connect_after (thread_data->connection, "closed", G_CALLBACK (connection_closed_cb), thread_data);
1066
1067   g_mutex_lock (&thread_data->mutex);
1068   thread_data->watch_id = g_bus_watch_name_on_connection (thread_data->connection,
1069                                                           "org.gtk.GDBus.Name1",
1070                                                           G_BUS_NAME_WATCHER_FLAGS_NONE,
1071                                                           t_name_appeared_handler,
1072                                                           t_name_vanished_handler,
1073                                                           thread_data,
1074                                                           (GDestroyNotify) t_watch_name_data_free_func);
1075   g_mutex_unlock (&thread_data->mutex);
1076
1077   g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1078   g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1079   while (thread_data->data.num_appeared == 0)
1080     g_main_context_iteration (thread_context, TRUE);
1081   g_assert_cmpint (thread_data->data.num_appeared, ==, 1);
1082   g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1083   thread_data->data.num_appeared = 0;
1084
1085   /* Close the connection and:
1086    *  - check that we had received a vanished event even begin in different thread
1087    *  - or check that unwatching the bus when a vanished had been scheduled
1088    *    make it correctly unscheduled (unwatch_early condition)
1089    */
1090   g_dbus_connection_close_sync (thread_data->connection, NULL, NULL);
1091   if (thread_data->unwatch_early)
1092     {
1093       // Wait for the main thread to iterate in order to have close connection handled
1094       g_mutex_lock (&thread_data->mutex);
1095       while (g_atomic_int_get (&thread_data->watch_id) != 0)
1096         g_cond_wait (&thread_data->cond, &thread_data->mutex);
1097       g_mutex_unlock (&thread_data->mutex);
1098
1099       while (thread_data->data.num_free_func == 0)
1100         g_main_context_iteration (thread_context, TRUE);
1101       g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1102       g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1103       g_assert_cmpint (thread_data->data.num_free_func, ==, 1);
1104     }
1105   else
1106     {
1107       while (thread_data->data.num_vanished == 0)
1108         {
1109           /*
1110            * Close of connection is treated in the context of the thread which
1111            * creates the connection. We must run iteration on it (to have the 'closed'
1112            * signal handled) and also run current thread loop to have name_vanished
1113            * callback handled.
1114            */
1115           g_main_context_iteration (thread_context, TRUE);
1116         }
1117       g_assert_cmpint (thread_data->data.num_vanished, ==, 1);
1118       g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1119       g_mutex_lock (&thread_data->mutex);
1120       g_bus_unwatch_name (g_atomic_int_get (&thread_data->watch_id));
1121       g_atomic_int_set (&thread_data->watch_id, 0);
1122       g_mutex_unlock (&thread_data->mutex);
1123       while (thread_data->data.num_free_func == 0)
1124         g_main_context_iteration (thread_context, TRUE);
1125       g_assert_cmpint (thread_data->data.num_free_func, ==, 1);
1126     }
1127
1128   g_mutex_lock (&thread_data->cond_mutex);
1129   thread_data->ended = TRUE;
1130   g_main_context_wakeup (NULL);
1131   g_cond_signal (&thread_data->cond);
1132   g_mutex_unlock (&thread_data->cond_mutex);
1133
1134   g_signal_handlers_disconnect_by_func (thread_data->connection, connection_closed_cb, thread_data);
1135   g_object_unref (thread_data->connection);
1136   g_main_context_pop_thread_default (thread_context);
1137   g_main_context_unref (thread_context);
1138
1139   g_mutex_lock (&thread_data->mutex);
1140   g_assert_cmpint (thread_data->watch_id, ==, 0);
1141   g_mutex_unlock (&thread_data->mutex);
1142   return NULL;
1143 }
1144
1145 static void
1146 watch_with_different_context (gboolean unwatch_early)
1147 {
1148   OwnNameData own_data;
1149   WatchNameThreadData thread_data;
1150   GDBusConnection *connection;
1151   GThread *watcher;
1152   guint id;
1153   GMainContext *main_context = NULL;  /* use the global default for now */
1154
1155   session_bus_up ();
1156
1157   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
1158   g_assert (connection != NULL);
1159
1160   g_mutex_init (&thread_data.mutex);
1161   g_mutex_init (&thread_data.cond_mutex);
1162   g_cond_init (&thread_data.cond);
1163   thread_data.started = FALSE;
1164   thread_data.name_acquired = FALSE;
1165   thread_data.ended = FALSE;
1166   thread_data.connection = g_object_ref (connection);
1167   thread_data.unwatch_early = unwatch_early;
1168
1169   // Create a thread which will watch a name and wait for it to be ready
1170   g_mutex_lock (&thread_data.cond_mutex);
1171   watcher = g_thread_new ("watcher", watcher_thread, &thread_data);
1172   while (!g_atomic_int_get (&thread_data.started))
1173     g_cond_wait (&thread_data.cond, &thread_data.cond_mutex);
1174   g_mutex_unlock (&thread_data.cond_mutex);
1175
1176   own_data.num_acquired = 0;
1177   own_data.num_lost = 0;
1178   own_data.num_free_func = 0;
1179   own_data.expect_null_connection = FALSE;
1180   own_data.main_context = main_context;
1181   // Own the name to avoid direct name vanished in watcher thread
1182   id = g_bus_own_name_on_connection (connection,
1183                                      "org.gtk.GDBus.Name1",
1184                                      G_BUS_NAME_OWNER_FLAGS_REPLACE,
1185                                      w_name_acquired_handler,
1186                                      w_name_lost_handler,
1187                                      &own_data,
1188                                      (GDestroyNotify) own_name_data_free_func);
1189   while (own_data.num_acquired == 0)
1190     g_main_context_iteration (main_context, TRUE);
1191   g_assert_cmpint (own_data.num_acquired, ==, 1);
1192   g_assert_cmpint (own_data.num_lost, ==, 0);
1193
1194   // Wake the thread for it to begin watch
1195   g_mutex_lock (&thread_data.cond_mutex);
1196   g_atomic_int_set (&thread_data.name_acquired, TRUE);
1197   g_cond_signal (&thread_data.cond);
1198   g_mutex_unlock (&thread_data.cond_mutex);
1199
1200   // Iterate the loop until thread is waking us up
1201   while (!thread_data.ended)
1202     g_main_context_iteration (main_context, TRUE);
1203
1204   g_thread_join (watcher);
1205
1206   g_bus_unown_name (id);
1207   while (own_data.num_free_func == 0)
1208     g_main_context_iteration (main_context, TRUE);
1209   g_assert_cmpint (own_data.num_free_func, ==, 1);
1210
1211   g_mutex_clear (&thread_data.mutex);
1212   g_mutex_clear (&thread_data.cond_mutex);
1213   g_cond_clear (&thread_data.cond);
1214
1215   session_bus_stop ();
1216   g_assert_true (g_dbus_connection_is_closed (connection));
1217   g_object_unref (connection);
1218   session_bus_down ();
1219 }
1220
1221 static void
1222 test_bus_watch_different_context (void)
1223 {
1224   watch_with_different_context (FALSE);
1225 }
1226
1227 /* ---------------------------------------------------------------------------------------------------- */
1228
1229 static void
1230 test_bus_unwatch_early (void)
1231 {
1232   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/604");
1233   watch_with_different_context (TRUE);
1234 }
1235
1236 /* ---------------------------------------------------------------------------------------------------- */
1237
1238 static void
1239 test_validate_names (void)
1240 {
1241   guint n;
1242   static const struct
1243   {
1244     gboolean name;
1245     gboolean unique;
1246     gboolean interface;
1247     const gchar *string;
1248   } names[] = {
1249     { 1, 0, 1, "valid.well_known.name"},
1250     { 1, 0, 0, "valid.well-known.name"},
1251     { 1, 1, 0, ":valid.unique.name"},
1252     { 0, 0, 0, "invalid.5well_known.name"},
1253     { 0, 0, 0, "4invalid.5well_known.name"},
1254     { 1, 1, 0, ":4valid.5unique.name"},
1255     { 0, 0, 0, ""},
1256     { 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 */
1257     { 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! */
1258     { 0, 0, 0, ".starts.with.a.dot"},
1259     { 0, 0, 0, "contains.invalid;.characters"},
1260     { 0, 0, 0, "contains.inva/lid.characters"},
1261     { 0, 0, 0, "contains.inva[lid.characters"},
1262     { 0, 0, 0, "contains.inva]lid.characters"},
1263     { 0, 0, 0, "contains.inva_æøå_lid.characters"},
1264     { 1, 1, 0, ":1.1"},
1265   };
1266
1267   for (n = 0; n < G_N_ELEMENTS (names); n++)
1268     {
1269       if (names[n].name)
1270         g_assert (g_dbus_is_name (names[n].string));
1271       else
1272         g_assert (!g_dbus_is_name (names[n].string));
1273
1274       if (names[n].unique)
1275         g_assert (g_dbus_is_unique_name (names[n].string));
1276       else
1277         g_assert (!g_dbus_is_unique_name (names[n].string));
1278
1279       if (names[n].interface)
1280         {
1281           g_assert (g_dbus_is_interface_name (names[n].string));
1282           g_assert (g_dbus_is_error_name (names[n].string)); 
1283         }
1284       else
1285         {
1286           g_assert (!g_dbus_is_interface_name (names[n].string));
1287           g_assert (!g_dbus_is_error_name (names[n].string));
1288         }        
1289     }
1290 }
1291
1292 static void
1293 assert_cmp_escaped_object_path (const gchar *s,
1294                                 const gchar *correct_escaped)
1295 {
1296   gchar *escaped;
1297   guint8 *unescaped;
1298
1299   escaped = g_dbus_escape_object_path (s);
1300   g_assert_cmpstr (escaped, ==, correct_escaped);
1301
1302   g_free (escaped);
1303   escaped = g_dbus_escape_object_path_bytestring ((const guint8 *) s);
1304   g_assert_cmpstr (escaped, ==, correct_escaped);
1305
1306   unescaped = g_dbus_unescape_object_path (escaped);
1307   g_assert_cmpstr ((const gchar *) unescaped, ==, s);
1308
1309   g_free (escaped);
1310   g_free (unescaped);
1311 }
1312
1313 static void
1314 test_escape_object_path (void)
1315 {
1316   assert_cmp_escaped_object_path ("Foo42", "Foo42");
1317   assert_cmp_escaped_object_path ("foo.bar.baz", "foo_2ebar_2ebaz");
1318   assert_cmp_escaped_object_path ("foo_bar_baz", "foo_5fbar_5fbaz");
1319   assert_cmp_escaped_object_path ("_", "_5f");
1320   assert_cmp_escaped_object_path ("__", "_5f_5f");
1321   assert_cmp_escaped_object_path ("", "_");
1322   assert_cmp_escaped_object_path (":1.42", "_3a1_2e42");
1323   assert_cmp_escaped_object_path ("a/b", "a_2fb");
1324   assert_cmp_escaped_object_path (" ", "_20");
1325   assert_cmp_escaped_object_path ("\n", "_0a");
1326
1327   g_assert_null (g_dbus_unescape_object_path ("_ii"));
1328   g_assert_null (g_dbus_unescape_object_path ("döner"));
1329   g_assert_null (g_dbus_unescape_object_path ("_00"));
1330   g_assert_null (g_dbus_unescape_object_path ("_61"));
1331   g_assert_null (g_dbus_unescape_object_path ("_ga"));
1332   g_assert_null (g_dbus_unescape_object_path ("_ag"));
1333 }
1334
1335 /* ---------------------------------------------------------------------------------------------------- */
1336
1337 int
1338 main (int   argc,
1339       char *argv[])
1340 {
1341   gint ret;
1342
1343   g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1344
1345   g_test_dbus_unset ();
1346
1347   g_test_add_func ("/gdbus/validate-names", test_validate_names);
1348   g_test_add_func ("/gdbus/bus-own-name", test_bus_own_name);
1349   g_test_add_data_func ("/gdbus/bus-watch-name",
1350                         &watch_no_closures_no_flags,
1351                         test_bus_watch_name);
1352   g_test_add_data_func ("/gdbus/bus-watch-name-auto-start",
1353                         &watch_no_closures_flags_auto_start,
1354                         test_bus_watch_name);
1355   g_test_add_data_func ("/gdbus/bus-watch-name-auto-start-service-exist",
1356                         &watch_no_closures_flags_auto_start_service_exist,
1357                         test_bus_watch_name);
1358   g_test_add_data_func ("/gdbus/bus-watch-name-closures",
1359                         &watch_closures_no_flags,
1360                         test_bus_watch_name);
1361   g_test_add_data_func ("/gdbus/bus-watch-name-closures-auto-start",
1362                         &watch_closures_flags_auto_start,
1363                         test_bus_watch_name);
1364   g_test_add_func ("/gdbus/bus-watch-different-context", test_bus_watch_different_context);
1365   g_test_add_func ("/gdbus/bus-unwatch-early", test_bus_unwatch_early);
1366   g_test_add_func ("/gdbus/escape-object-path", test_escape_object_path);
1367   ret = g_test_run();
1368
1369   return ret;
1370 }