Revert "Add GTestDBus object"
[platform/upstream/glib.git] / gio / tests / actions.c
1 #include <gio/gio.h>
2 #include <stdlib.h>
3
4 #include "gdbus-sessionbus.h"
5
6 typedef struct
7 {
8   GVariant *params;
9   gboolean did_run;
10 } Activation;
11
12 static void
13 activate (GAction  *action,
14           GVariant *parameter,
15           gpointer  user_data)
16 {
17   Activation *activation = user_data;
18
19   if (parameter)
20     activation->params = g_variant_ref (parameter);
21   else
22     activation->params = NULL;
23   activation->did_run = TRUE;
24 }
25
26 static void
27 test_basic (void)
28 {
29   Activation a = { 0, };
30   GSimpleAction *action;
31   gchar *name;
32   GVariantType *parameter_type;
33   gboolean enabled;
34   GVariantType *state_type;
35   GVariant *state;
36
37   action = g_simple_action_new ("foo", NULL);
38   g_assert (g_action_get_enabled (G_ACTION (action)));
39   g_assert (g_action_get_parameter_type (G_ACTION (action)) == NULL);
40   g_assert (g_action_get_state_type (G_ACTION (action)) == NULL);
41   g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
42   g_assert (g_action_get_state (G_ACTION (action)) == NULL);
43   g_object_get (action,
44                 "name", &name,
45                 "parameter-type", &parameter_type,
46                 "enabled", &enabled,
47                 "state-type", &state_type,
48                 "state", &state,
49                  NULL);
50   g_assert_cmpstr (name, ==, "foo");
51   g_assert (parameter_type == NULL);
52   g_assert (enabled);
53   g_assert (state_type == NULL);
54   g_assert (state == NULL);
55   g_free (name);
56
57   g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
58   g_assert (!a.did_run);
59   g_action_activate (G_ACTION (action), NULL);
60   g_assert (a.did_run);
61   a.did_run = FALSE;
62
63   g_simple_action_set_enabled (action, FALSE);
64   g_action_activate (G_ACTION (action), NULL);
65   g_assert (!a.did_run);
66
67   if (g_test_undefined ())
68     {
69       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
70         {
71           g_action_activate (G_ACTION (action), g_variant_new_string ("xxx"));
72           exit (0);
73         }
74       g_test_trap_assert_failed ();
75     }
76
77   g_object_unref (action);
78   g_assert (!a.did_run);
79
80   action = g_simple_action_new ("foo", G_VARIANT_TYPE_STRING);
81   g_assert (g_action_get_enabled (G_ACTION (action)));
82   g_assert (g_variant_type_equal (g_action_get_parameter_type (G_ACTION (action)), G_VARIANT_TYPE_STRING));
83   g_assert (g_action_get_state_type (G_ACTION (action)) == NULL);
84   g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
85   g_assert (g_action_get_state (G_ACTION (action)) == NULL);
86
87   g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
88   g_assert (!a.did_run);
89   g_action_activate (G_ACTION (action), g_variant_new_string ("Hello world"));
90   g_assert (a.did_run);
91   g_assert_cmpstr (g_variant_get_string (a.params, NULL), ==, "Hello world");
92   g_variant_unref (a.params);
93   a.did_run = FALSE;
94
95   if (g_test_undefined ())
96     {
97       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
98         {
99           g_action_activate (G_ACTION (action), NULL);
100           exit (0);
101         }
102
103       g_test_trap_assert_failed ();
104     }
105
106   g_object_unref (action);
107   g_assert (!a.did_run);
108 }
109
110 static gboolean
111 strv_has_string (gchar       **haystack,
112                  const gchar  *needle)
113 {
114   guint n;
115
116   for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
117     {
118       if (g_strcmp0 (haystack[n], needle) == 0)
119         return TRUE;
120     }
121   return FALSE;
122 }
123
124 static gboolean
125 strv_strv_cmp (gchar **a, gchar **b)
126 {
127   guint n;
128
129   for (n = 0; a[n] != NULL; n++)
130     {
131        if (!strv_has_string (b, a[n]))
132          return FALSE;
133     }
134
135   for (n = 0; b[n] != NULL; n++)
136     {
137        if (!strv_has_string (a, b[n]))
138          return FALSE;
139     }
140
141   return TRUE;
142 }
143
144 static gboolean
145 strv_set_equal (gchar **strv, ...)
146 {
147   gint count;
148   va_list list;
149   const gchar *str;
150   gboolean res;
151
152   res = TRUE;
153   count = 0;
154   va_start (list, strv);
155   while (1)
156     {
157       str = va_arg (list, const gchar *);
158       if (str == NULL)
159         break;
160       if (!strv_has_string (strv, str))
161         {
162           res = FALSE;
163           break;
164         }
165       count++;
166     }
167   va_end (list);
168
169   if (res)
170     res = g_strv_length ((gchar**)strv) == count;
171
172   return res;
173 }
174
175 static void
176 test_simple_group (void)
177 {
178   GSimpleActionGroup *group;
179   Activation a = { 0, };
180   GSimpleAction *simple;
181   GAction *action;
182   gchar **actions;
183   GVariant *state;
184
185   simple = g_simple_action_new ("foo", NULL);
186   g_signal_connect (simple, "activate", G_CALLBACK (activate), &a);
187   g_assert (!a.did_run);
188   g_action_activate (G_ACTION (simple), NULL);
189   g_assert (a.did_run);
190   a.did_run = FALSE;
191
192   group = g_simple_action_group_new ();
193   g_simple_action_group_insert (group, G_ACTION (simple));
194   g_object_unref (simple);
195
196   g_assert (!a.did_run);
197   g_action_group_activate_action (G_ACTION_GROUP (group), "foo", NULL);
198   g_assert (a.did_run);
199
200   simple = g_simple_action_new_stateful ("bar", G_VARIANT_TYPE_STRING, g_variant_new_string ("hihi"));
201   g_simple_action_group_insert (group, G_ACTION (simple));
202   g_object_unref (simple);
203
204   g_assert (g_action_group_has_action (G_ACTION_GROUP (group), "foo"));
205   g_assert (g_action_group_has_action (G_ACTION_GROUP (group), "bar"));
206   g_assert (!g_action_group_has_action (G_ACTION_GROUP (group), "baz"));
207   actions = g_action_group_list_actions (G_ACTION_GROUP (group));
208   g_assert_cmpint (g_strv_length (actions), ==, 2);
209   g_assert (strv_set_equal (actions, "foo", "bar", NULL));
210   g_strfreev (actions);
211   g_assert (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "foo"));
212   g_assert (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
213   g_assert (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "foo") == NULL);
214   g_assert (g_variant_type_equal (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
215   g_assert (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "foo") == NULL);
216   g_assert (g_variant_type_equal (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
217   g_assert (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "foo") == NULL);
218   g_assert (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "bar") == NULL);
219   g_assert (g_action_group_get_action_state (G_ACTION_GROUP (group), "foo") == NULL);
220   state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
221   g_assert (g_variant_type_equal (g_variant_get_type (state), G_VARIANT_TYPE_STRING));
222   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
223   g_variant_unref (state);
224
225   g_action_group_change_action_state (G_ACTION_GROUP (group), "bar", g_variant_new_string ("boo"));
226   state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
227   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "boo");
228   g_variant_unref (state);
229
230   action = g_simple_action_group_lookup (group, "bar");
231   g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
232   g_assert (!g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
233
234   g_simple_action_group_remove (group, "bar");
235   action = g_simple_action_group_lookup (group, "foo");
236   g_assert_cmpstr (g_action_get_name (action), ==, "foo");
237   action = g_simple_action_group_lookup (group, "bar");
238   g_assert (action == NULL);
239
240   a.did_run = FALSE;
241   g_object_unref (group);
242   g_assert (!a.did_run);
243 }
244
245 static void
246 test_stateful (void)
247 {
248   GSimpleAction *action;
249   GVariant *state;
250
251   action = g_simple_action_new_stateful ("foo", NULL, g_variant_new_string ("hihi"));
252   g_assert (g_action_get_enabled (G_ACTION (action)));
253   g_assert (g_action_get_parameter_type (G_ACTION (action)) == NULL);
254   g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
255   g_assert (g_variant_type_equal (g_action_get_state_type (G_ACTION (action)),
256                                   G_VARIANT_TYPE_STRING));
257   state = g_action_get_state (G_ACTION (action));
258   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
259   g_variant_unref (state);
260
261   if (g_test_undefined ())
262     {
263       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
264         {
265           g_simple_action_set_state (action, g_variant_new_int32 (123));
266           exit (0);
267         }
268       g_test_trap_assert_failed ();
269     }
270
271   g_simple_action_set_state (action, g_variant_new_string ("hello"));
272   state = g_action_get_state (G_ACTION (action));
273   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hello");
274   g_variant_unref (state);
275
276   g_object_unref (action);
277
278   action = g_simple_action_new ("foo", NULL);
279
280   if (g_test_undefined ())
281     {
282       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
283         {
284           g_simple_action_set_state (action, g_variant_new_int32 (123));
285           exit (0);
286         }
287       g_test_trap_assert_failed ();
288     }
289
290   g_object_unref (action);
291 }
292
293 static gboolean foo_activated = FALSE;
294 static gboolean bar_activated = FALSE;
295
296 static void
297 activate_foo (GSimpleAction *simple,
298               GVariant      *parameter,
299               gpointer       user_data)
300 {
301   g_assert (user_data == GINT_TO_POINTER (123));
302   g_assert (parameter == NULL);
303   foo_activated = TRUE;
304 }
305
306 static void
307 activate_bar (GSimpleAction *simple,
308               GVariant      *parameter,
309               gpointer       user_data)
310 {
311   g_assert (user_data == GINT_TO_POINTER (123));
312   g_assert_cmpstr (g_variant_get_string (parameter, NULL), ==, "param");
313   bar_activated = TRUE;
314 }
315
316 static void
317 change_volume_state (GSimpleAction *action,
318                      GVariant      *value,
319                      gpointer       user_data)
320 {
321   gint requested;
322
323   requested = g_variant_get_int32 (value);
324
325   /* Volume only goes from 0 to 10 */
326   if (0 <= requested && requested <= 10)
327     g_simple_action_set_state (action, value);
328 }
329
330 static void
331 test_entries (void)
332 {
333   const GActionEntry entries[] = {
334     { "foo",    activate_foo                                     },
335     { "bar",    activate_bar, "s"                                },
336     { "toggle", NULL,         NULL, "false"                      },
337     { "volume", NULL,         NULL, "0",     change_volume_state }
338   };
339   GSimpleActionGroup *actions;
340   GVariant *state;
341
342   actions = g_simple_action_group_new ();
343   g_simple_action_group_add_entries (actions, entries,
344                                      G_N_ELEMENTS (entries),
345                                      GINT_TO_POINTER (123));
346
347   g_assert (!foo_activated);
348   g_action_group_activate_action (G_ACTION_GROUP (actions), "foo", NULL);
349   g_assert (foo_activated);
350   foo_activated = FALSE;
351
352   g_assert (!bar_activated);
353   g_action_group_activate_action (G_ACTION_GROUP (actions), "bar",
354                                   g_variant_new_string ("param"));
355   g_assert (bar_activated);
356   g_assert (!foo_activated);
357
358   if (g_test_undefined ())
359     {
360       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
361         {
362           const GActionEntry bad_type = {
363             "bad-type", NULL, "ss"
364           };
365
366           g_simple_action_group_add_entries (actions, &bad_type, 1, NULL);
367           exit (0);
368         }
369       g_test_trap_assert_failed ();
370
371       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
372         {
373           const GActionEntry bad_state = {
374             "bad-state", NULL, NULL, "flse"
375           };
376
377           g_simple_action_group_add_entries (actions, &bad_state, 1, NULL);
378           exit (0);
379         }
380       g_test_trap_assert_failed ();
381     }
382
383   state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
384   g_assert_cmpint (g_variant_get_int32 (state), ==, 0);
385   g_variant_unref (state);
386
387   /* should change */
388   g_action_group_change_action_state (G_ACTION_GROUP (actions), "volume",
389                                       g_variant_new_int32 (7));
390   state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
391   g_assert_cmpint (g_variant_get_int32 (state), ==, 7);
392   g_variant_unref (state);
393
394   /* should not change */
395   g_action_group_change_action_state (G_ACTION_GROUP (actions), "volume",
396                                       g_variant_new_int32 (11));
397   state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
398   g_assert_cmpint (g_variant_get_int32 (state), ==, 7);
399   g_variant_unref (state);
400
401   g_object_unref (actions);
402 }
403
404
405 GHashTable *activation_counts;
406
407 static void
408 count_activation (const gchar *action)
409 {
410   gint count;
411
412   if (activation_counts == NULL)
413     activation_counts = g_hash_table_new (g_str_hash, g_str_equal);
414   count = GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action));
415   count++;
416   g_hash_table_insert (activation_counts, (gpointer)action, GINT_TO_POINTER (count));
417 }
418
419 static gint
420 activation_count (const gchar *action)
421 {
422   if (activation_counts == NULL)
423     return 0;
424
425   return GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action));
426 }
427
428 static void
429 activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data)
430 {
431   count_activation (g_action_get_name (G_ACTION (action)));
432 }
433
434 static void
435 activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data)
436 {
437   GVariant *old_state, *new_state;
438
439   count_activation (g_action_get_name (G_ACTION (action)));
440
441   old_state = g_action_get_state (G_ACTION (action));
442   new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
443   g_simple_action_set_state (action, new_state);
444   g_variant_unref (old_state);
445 }
446
447 static void
448 activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data)
449 {
450   GVariant *new_state;
451
452   count_activation (g_action_get_name (G_ACTION (action)));
453
454   new_state = g_variant_new_string (g_variant_get_string (parameter, NULL));
455   g_simple_action_set_state (action, new_state);
456 }
457
458 static gboolean
459 compare_action_groups (GActionGroup *a, GActionGroup *b)
460 {
461   gchar **alist;
462   gchar **blist;
463   gint i;
464   gboolean equal;
465   gboolean ares, bres;
466   gboolean aenabled, benabled;
467   const GVariantType *aparameter_type, *bparameter_type;
468   const GVariantType *astate_type, *bstate_type;
469   GVariant *astate_hint, *bstate_hint;
470   GVariant *astate, *bstate;
471
472   alist = g_action_group_list_actions (a);
473   blist = g_action_group_list_actions (b);
474   equal = strv_strv_cmp (alist, blist);
475
476   for (i = 0; equal && alist[i]; i++)
477     {
478       ares = g_action_group_query_action (a, alist[i], &aenabled, &aparameter_type, &astate_type, &astate_hint, &astate);
479       bres = g_action_group_query_action (b, alist[i], &benabled, &bparameter_type, &bstate_type, &bstate_hint, &bstate);
480
481       if (ares && bres)
482         {
483           equal = equal && (aenabled == benabled);
484           equal = equal && ((!aparameter_type && !bparameter_type) || g_variant_type_equal (aparameter_type, bparameter_type));
485           equal = equal && ((!astate_type && !bstate_type) || g_variant_type_equal (astate_type, bstate_type));
486           equal = equal && ((!astate_hint && !bstate_hint) || g_variant_equal (astate_hint, bstate_hint));
487           equal = equal && ((!astate && !bstate) || g_variant_equal (astate, bstate));
488
489           if (astate_hint)
490             g_variant_unref (astate_hint);
491           if (bstate_hint)
492             g_variant_unref (bstate_hint);
493           if (astate)
494             g_variant_unref (astate);
495           if (bstate)
496             g_variant_unref (bstate);
497         }
498       else
499         equal = FALSE;
500     }
501
502   g_strfreev (alist);
503   g_strfreev (blist);
504
505   return equal;
506 }
507
508 static gboolean
509 stop_loop (gpointer data)
510 {
511   GMainLoop *loop = data;
512
513   g_main_loop_quit (loop);
514
515   return G_SOURCE_REMOVE;
516 }
517
518 static void
519 test_dbus_export (void)
520 {
521   GDBusConnection *bus;
522   GSimpleActionGroup *group;
523   GDBusActionGroup *proxy;
524   GSimpleAction *action;
525   GMainLoop *loop;
526   static GActionEntry entries[] = {
527     { "undo",  activate_action, NULL, NULL,      NULL },
528     { "redo",  activate_action, NULL, NULL,      NULL },
529     { "cut",   activate_action, NULL, NULL,      NULL },
530     { "copy",  activate_action, NULL, NULL,      NULL },
531     { "paste", activate_action, NULL, NULL,      NULL },
532     { "bold",  activate_toggle, NULL, "true",    NULL },
533     { "lang",  activate_radio,  "s",  "'latin'", NULL },
534   };
535   GError *error = NULL;
536   GVariant *v;
537   guint id;
538
539   loop = g_main_loop_new (NULL, FALSE);
540
541   session_bus_up ();
542   bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
543
544   group = g_simple_action_group_new ();
545   g_simple_action_group_add_entries (group, entries, G_N_ELEMENTS (entries), NULL);
546
547   id = g_dbus_connection_export_action_group (bus, "/", G_ACTION_GROUP (group), &error);
548   g_assert_no_error (error);
549
550   proxy = g_dbus_action_group_get (bus, g_dbus_connection_get_unique_name (bus), "/");
551   g_strfreev (g_action_group_list_actions (G_ACTION_GROUP (proxy)));
552
553   g_timeout_add (100, stop_loop, loop);
554   g_main_loop_run (loop);
555
556   /* test that the initial transfer works */
557   g_assert (G_IS_DBUS_ACTION_GROUP (proxy));
558   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
559
560   /* test that various changes get propagated from group to proxy */
561   action = g_simple_action_new_stateful ("italic", NULL, g_variant_new_boolean (FALSE));
562   g_simple_action_group_insert (group, G_ACTION (action));
563   g_object_unref (action);
564
565   g_timeout_add (100, stop_loop, loop);
566   g_main_loop_run (loop);
567
568   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
569
570   action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "cut"));
571   g_simple_action_set_enabled (action, FALSE);
572
573   g_timeout_add (100, stop_loop, loop);
574   g_main_loop_run (loop);
575
576   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
577
578   action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "bold"));
579   g_simple_action_set_state (action, g_variant_new_boolean (FALSE));
580
581   g_timeout_add (100, stop_loop, loop);
582   g_main_loop_run (loop);
583
584   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
585
586   g_simple_action_group_remove (group, "italic");
587
588   g_timeout_add (100, stop_loop, loop);
589   g_main_loop_run (loop);
590
591   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
592
593   /* test that activations and state changes propagate the other way */
594
595   g_assert_cmpint (activation_count ("copy"), ==, 0);
596   g_action_group_activate_action (G_ACTION_GROUP (proxy), "copy", NULL);
597
598   g_timeout_add (100, stop_loop, loop);
599   g_main_loop_run (loop);
600
601   g_assert_cmpint (activation_count ("copy"), ==, 1);
602   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
603
604   g_assert_cmpint (activation_count ("bold"), ==, 0);
605   g_action_group_activate_action (G_ACTION_GROUP (proxy), "bold", NULL);
606
607   g_timeout_add (100, stop_loop, loop);
608   g_main_loop_run (loop);
609
610   g_assert_cmpint (activation_count ("bold"), ==, 1);
611   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
612   v = g_action_group_get_action_state (G_ACTION_GROUP (group), "bold");
613   g_assert (g_variant_get_boolean (v));
614   g_variant_unref (v);
615
616   g_action_group_change_action_state (G_ACTION_GROUP (proxy), "bold", g_variant_new_boolean (FALSE));
617
618   g_timeout_add (100, stop_loop, loop);
619   g_main_loop_run (loop);
620
621   g_assert_cmpint (activation_count ("bold"), ==, 1);
622   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
623   v = g_action_group_get_action_state (G_ACTION_GROUP (group), "bold");
624   g_assert (!g_variant_get_boolean (v));
625   g_variant_unref (v);
626
627   g_dbus_connection_unexport_action_group (bus, id);
628
629   g_object_unref (proxy);
630   g_object_unref (group);
631   g_main_loop_unref (loop);
632   g_object_unref (bus);
633
634   session_bus_down ();
635 }
636
637 static gpointer
638 do_export (gpointer data)
639 {
640   GActionGroup *group = data;
641   GMainContext *ctx;
642   gint i;
643   GError *error = NULL;
644   guint id;
645   GDBusConnection *bus;
646   GAction *action;
647   gchar *path;
648
649   ctx = g_main_context_new ();
650
651   g_main_context_push_thread_default (ctx);
652
653   bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
654   path = g_strdup_printf("/%p", data);
655
656   for (i = 0; i < 100000; i++)
657     {
658       id = g_dbus_connection_export_action_group (bus, path, G_ACTION_GROUP (group), &error);
659       g_assert_no_error (error);
660
661       action = g_simple_action_group_lookup (G_SIMPLE_ACTION_GROUP (group), "a");
662       g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
663                                    !g_action_get_enabled (action));
664
665       g_dbus_connection_unexport_action_group (bus, id);
666
667       while (g_main_context_iteration (ctx, FALSE));
668     }
669
670   g_free (path);
671   g_object_unref (bus);
672
673   g_main_context_pop_thread_default (ctx);
674
675   g_main_context_unref (ctx);
676
677   return NULL;
678 }
679
680 static void
681 test_dbus_threaded (void)
682 {
683   GSimpleActionGroup *group[10];
684   GThread *export[10];
685   static GActionEntry entries[] = {
686     { "a",  activate_action, NULL, NULL, NULL },
687     { "b",  activate_action, NULL, NULL, NULL },
688   };
689   gint i;
690
691   session_bus_up ();
692
693   for (i = 0; i < 10; i++)
694     {
695       group[i] = g_simple_action_group_new ();
696       g_simple_action_group_add_entries (group[i], entries, G_N_ELEMENTS (entries), NULL);
697       export[i] = g_thread_new ("export", do_export, group[i]);
698     }
699
700   for (i = 0; i < 10; i++)
701     g_thread_join (export[i]);
702
703   for (i = 0; i < 10; i++)
704     g_object_unref (group[i]);
705
706   session_bus_down ();
707 }
708
709 int
710 main (int argc, char **argv)
711 {
712   g_type_init ();
713   g_test_init (&argc, &argv, NULL);
714
715   g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
716
717   g_test_add_func ("/actions/basic", test_basic);
718   g_test_add_func ("/actions/simplegroup", test_simple_group);
719   g_test_add_func ("/actions/stateful", test_stateful);
720   g_test_add_func ("/actions/entries", test_entries);
721   g_test_add_func ("/actions/dbus/export", test_dbus_export);
722   g_test_add_func ("/actions/dbus/threaded", test_dbus_threaded);
723
724   return g_test_run ();
725 }