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