gio/tests: port some stuff to g_test_expect_message()
[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       g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
70                              "*assertion*g_variant_is_of_type*failed*");
71       g_action_activate (G_ACTION (action), g_variant_new_string ("xxx"));
72       g_test_assert_expected_messages ();
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       g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
96                              "*assertion*!= NULL*failed*");
97       g_action_activate (G_ACTION (action), NULL);
98       g_test_assert_expected_messages ();
99     }
100
101   g_object_unref (action);
102   g_assert (!a.did_run);
103 }
104
105 static gboolean
106 strv_has_string (gchar       **haystack,
107                  const gchar  *needle)
108 {
109   guint n;
110
111   for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
112     {
113       if (g_strcmp0 (haystack[n], needle) == 0)
114         return TRUE;
115     }
116   return FALSE;
117 }
118
119 static gboolean
120 strv_strv_cmp (gchar **a, gchar **b)
121 {
122   guint n;
123
124   for (n = 0; a[n] != NULL; n++)
125     {
126        if (!strv_has_string (b, a[n]))
127          return FALSE;
128     }
129
130   for (n = 0; b[n] != NULL; n++)
131     {
132        if (!strv_has_string (a, b[n]))
133          return FALSE;
134     }
135
136   return TRUE;
137 }
138
139 static gboolean
140 strv_set_equal (gchar **strv, ...)
141 {
142   gint count;
143   va_list list;
144   const gchar *str;
145   gboolean res;
146
147   res = TRUE;
148   count = 0;
149   va_start (list, strv);
150   while (1)
151     {
152       str = va_arg (list, const gchar *);
153       if (str == NULL)
154         break;
155       if (!strv_has_string (strv, str))
156         {
157           res = FALSE;
158           break;
159         }
160       count++;
161     }
162   va_end (list);
163
164   if (res)
165     res = g_strv_length ((gchar**)strv) == count;
166
167   return res;
168 }
169
170 static void
171 test_simple_group (void)
172 {
173   GSimpleActionGroup *group;
174   Activation a = { 0, };
175   GSimpleAction *simple;
176   GAction *action;
177   gchar **actions;
178   GVariant *state;
179
180   simple = g_simple_action_new ("foo", NULL);
181   g_signal_connect (simple, "activate", G_CALLBACK (activate), &a);
182   g_assert (!a.did_run);
183   g_action_activate (G_ACTION (simple), NULL);
184   g_assert (a.did_run);
185   a.did_run = FALSE;
186
187   group = g_simple_action_group_new ();
188   g_simple_action_group_insert (group, G_ACTION (simple));
189   g_object_unref (simple);
190
191   g_assert (!a.did_run);
192   g_action_group_activate_action (G_ACTION_GROUP (group), "foo", NULL);
193   g_assert (a.did_run);
194
195   simple = g_simple_action_new_stateful ("bar", G_VARIANT_TYPE_STRING, g_variant_new_string ("hihi"));
196   g_simple_action_group_insert (group, G_ACTION (simple));
197   g_object_unref (simple);
198
199   g_assert (g_action_group_has_action (G_ACTION_GROUP (group), "foo"));
200   g_assert (g_action_group_has_action (G_ACTION_GROUP (group), "bar"));
201   g_assert (!g_action_group_has_action (G_ACTION_GROUP (group), "baz"));
202   actions = g_action_group_list_actions (G_ACTION_GROUP (group));
203   g_assert_cmpint (g_strv_length (actions), ==, 2);
204   g_assert (strv_set_equal (actions, "foo", "bar", NULL));
205   g_strfreev (actions);
206   g_assert (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "foo"));
207   g_assert (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
208   g_assert (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "foo") == NULL);
209   g_assert (g_variant_type_equal (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
210   g_assert (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "foo") == NULL);
211   g_assert (g_variant_type_equal (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
212   g_assert (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "foo") == NULL);
213   g_assert (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "bar") == NULL);
214   g_assert (g_action_group_get_action_state (G_ACTION_GROUP (group), "foo") == NULL);
215   state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
216   g_assert (g_variant_type_equal (g_variant_get_type (state), G_VARIANT_TYPE_STRING));
217   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
218   g_variant_unref (state);
219
220   g_action_group_change_action_state (G_ACTION_GROUP (group), "bar", g_variant_new_string ("boo"));
221   state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
222   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "boo");
223   g_variant_unref (state);
224
225   action = g_simple_action_group_lookup (group, "bar");
226   g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
227   g_assert (!g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
228
229   g_simple_action_group_remove (group, "bar");
230   action = g_simple_action_group_lookup (group, "foo");
231   g_assert_cmpstr (g_action_get_name (action), ==, "foo");
232   action = g_simple_action_group_lookup (group, "bar");
233   g_assert (action == NULL);
234
235   a.did_run = FALSE;
236   g_object_unref (group);
237   g_assert (!a.did_run);
238 }
239
240 static void
241 test_stateful (void)
242 {
243   GSimpleAction *action;
244   GVariant *state;
245
246   action = g_simple_action_new_stateful ("foo", NULL, g_variant_new_string ("hihi"));
247   g_assert (g_action_get_enabled (G_ACTION (action)));
248   g_assert (g_action_get_parameter_type (G_ACTION (action)) == NULL);
249   g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
250   g_assert (g_variant_type_equal (g_action_get_state_type (G_ACTION (action)),
251                                   G_VARIANT_TYPE_STRING));
252   state = g_action_get_state (G_ACTION (action));
253   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
254   g_variant_unref (state);
255
256   if (g_test_undefined ())
257     {
258       g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
259                              "*assertion*g_variant_is_of_type*failed*");
260       g_simple_action_set_state (action, g_variant_new_int32 (123));
261       g_test_assert_expected_messages ();
262     }
263
264   g_simple_action_set_state (action, g_variant_new_string ("hello"));
265   state = g_action_get_state (G_ACTION (action));
266   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hello");
267   g_variant_unref (state);
268
269   g_object_unref (action);
270
271   action = g_simple_action_new ("foo", NULL);
272
273   if (g_test_undefined ())
274     {
275       g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
276                              "*assertion*!= NULL*failed*");
277       g_simple_action_set_state (action, g_variant_new_int32 (123));
278       g_test_assert_expected_messages ();
279     }
280
281   g_object_unref (action);
282 }
283
284 static gboolean foo_activated = FALSE;
285 static gboolean bar_activated = FALSE;
286
287 static void
288 activate_foo (GSimpleAction *simple,
289               GVariant      *parameter,
290               gpointer       user_data)
291 {
292   g_assert (user_data == GINT_TO_POINTER (123));
293   g_assert (parameter == NULL);
294   foo_activated = TRUE;
295 }
296
297 static void
298 activate_bar (GSimpleAction *simple,
299               GVariant      *parameter,
300               gpointer       user_data)
301 {
302   g_assert (user_data == GINT_TO_POINTER (123));
303   g_assert_cmpstr (g_variant_get_string (parameter, NULL), ==, "param");
304   bar_activated = TRUE;
305 }
306
307 static void
308 change_volume_state (GSimpleAction *action,
309                      GVariant      *value,
310                      gpointer       user_data)
311 {
312   gint requested;
313
314   requested = g_variant_get_int32 (value);
315
316   /* Volume only goes from 0 to 10 */
317   if (0 <= requested && requested <= 10)
318     g_simple_action_set_state (action, value);
319 }
320
321 static void
322 test_entries (void)
323 {
324   const GActionEntry entries[] = {
325     { "foo",    activate_foo                                     },
326     { "bar",    activate_bar, "s"                                },
327     { "toggle", NULL,         NULL, "false"                      },
328     { "volume", NULL,         NULL, "0",     change_volume_state }
329   };
330   GSimpleActionGroup *actions;
331   GVariant *state;
332
333   actions = g_simple_action_group_new ();
334   g_simple_action_group_add_entries (actions, entries,
335                                      G_N_ELEMENTS (entries),
336                                      GINT_TO_POINTER (123));
337
338   g_assert (!foo_activated);
339   g_action_group_activate_action (G_ACTION_GROUP (actions), "foo", NULL);
340   g_assert (foo_activated);
341   foo_activated = FALSE;
342
343   g_assert (!bar_activated);
344   g_action_group_activate_action (G_ACTION_GROUP (actions), "bar",
345                                   g_variant_new_string ("param"));
346   g_assert (bar_activated);
347   g_assert (!foo_activated);
348
349   if (g_test_undefined ())
350     {
351       const GActionEntry bad_type = {
352         "bad-type", NULL, "ss"
353       };
354       const GActionEntry bad_state = {
355         "bad-state", NULL, NULL, "flse"
356       };
357
358       g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
359                              "*not a valid GVariant type string*");
360       g_simple_action_group_add_entries (actions, &bad_type, 1, NULL);
361       g_test_assert_expected_messages ();
362
363       g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
364                              "*could not parse*");
365       g_simple_action_group_add_entries (actions, &bad_state, 1, NULL);
366       g_test_assert_expected_messages ();
367     }
368
369   state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
370   g_assert_cmpint (g_variant_get_int32 (state), ==, 0);
371   g_variant_unref (state);
372
373   /* should change */
374   g_action_group_change_action_state (G_ACTION_GROUP (actions), "volume",
375                                       g_variant_new_int32 (7));
376   state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
377   g_assert_cmpint (g_variant_get_int32 (state), ==, 7);
378   g_variant_unref (state);
379
380   /* should not change */
381   g_action_group_change_action_state (G_ACTION_GROUP (actions), "volume",
382                                       g_variant_new_int32 (11));
383   state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
384   g_assert_cmpint (g_variant_get_int32 (state), ==, 7);
385   g_variant_unref (state);
386
387   g_object_unref (actions);
388 }
389
390
391 GHashTable *activation_counts;
392
393 static void
394 count_activation (const gchar *action)
395 {
396   gint count;
397
398   if (activation_counts == NULL)
399     activation_counts = g_hash_table_new (g_str_hash, g_str_equal);
400   count = GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action));
401   count++;
402   g_hash_table_insert (activation_counts, (gpointer)action, GINT_TO_POINTER (count));
403 }
404
405 static gint
406 activation_count (const gchar *action)
407 {
408   if (activation_counts == NULL)
409     return 0;
410
411   return GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action));
412 }
413
414 static void
415 activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data)
416 {
417   count_activation (g_action_get_name (G_ACTION (action)));
418 }
419
420 static void
421 activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data)
422 {
423   GVariant *old_state, *new_state;
424
425   count_activation (g_action_get_name (G_ACTION (action)));
426
427   old_state = g_action_get_state (G_ACTION (action));
428   new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
429   g_simple_action_set_state (action, new_state);
430   g_variant_unref (old_state);
431 }
432
433 static void
434 activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data)
435 {
436   GVariant *new_state;
437
438   count_activation (g_action_get_name (G_ACTION (action)));
439
440   new_state = g_variant_new_string (g_variant_get_string (parameter, NULL));
441   g_simple_action_set_state (action, new_state);
442 }
443
444 static gboolean
445 compare_action_groups (GActionGroup *a, GActionGroup *b)
446 {
447   gchar **alist;
448   gchar **blist;
449   gint i;
450   gboolean equal;
451   gboolean ares, bres;
452   gboolean aenabled, benabled;
453   const GVariantType *aparameter_type, *bparameter_type;
454   const GVariantType *astate_type, *bstate_type;
455   GVariant *astate_hint, *bstate_hint;
456   GVariant *astate, *bstate;
457
458   alist = g_action_group_list_actions (a);
459   blist = g_action_group_list_actions (b);
460   equal = strv_strv_cmp (alist, blist);
461
462   for (i = 0; equal && alist[i]; i++)
463     {
464       ares = g_action_group_query_action (a, alist[i], &aenabled, &aparameter_type, &astate_type, &astate_hint, &astate);
465       bres = g_action_group_query_action (b, alist[i], &benabled, &bparameter_type, &bstate_type, &bstate_hint, &bstate);
466
467       if (ares && bres)
468         {
469           equal = equal && (aenabled == benabled);
470           equal = equal && ((!aparameter_type && !bparameter_type) || g_variant_type_equal (aparameter_type, bparameter_type));
471           equal = equal && ((!astate_type && !bstate_type) || g_variant_type_equal (astate_type, bstate_type));
472           equal = equal && ((!astate_hint && !bstate_hint) || g_variant_equal (astate_hint, bstate_hint));
473           equal = equal && ((!astate && !bstate) || g_variant_equal (astate, bstate));
474
475           if (astate_hint)
476             g_variant_unref (astate_hint);
477           if (bstate_hint)
478             g_variant_unref (bstate_hint);
479           if (astate)
480             g_variant_unref (astate);
481           if (bstate)
482             g_variant_unref (bstate);
483         }
484       else
485         equal = FALSE;
486     }
487
488   g_strfreev (alist);
489   g_strfreev (blist);
490
491   return equal;
492 }
493
494 static gboolean
495 stop_loop (gpointer data)
496 {
497   GMainLoop *loop = data;
498
499   g_main_loop_quit (loop);
500
501   return G_SOURCE_REMOVE;
502 }
503
504 static GActionEntry exported_entries[] = {
505   { "undo",  activate_action, NULL, NULL,      NULL },
506   { "redo",  activate_action, NULL, NULL,      NULL },
507   { "cut",   activate_action, NULL, NULL,      NULL },
508   { "copy",  activate_action, NULL, NULL,      NULL },
509   { "paste", activate_action, NULL, NULL,      NULL },
510   { "bold",  activate_toggle, NULL, "true",    NULL },
511   { "lang",  activate_radio,  "s",  "'latin'", NULL },
512 };
513
514 static void
515 list_cb (GObject      *source,
516          GAsyncResult *res,
517          gpointer      user_data)
518 {
519   GDBusConnection *bus = G_DBUS_CONNECTION (source);
520   GMainLoop *loop = user_data;
521   GError *error = NULL;
522   GVariant *v;
523   gchar **actions;
524
525   v = g_dbus_connection_call_finish (bus, res, &error);
526   g_assert (v);
527   g_variant_get (v, "(^a&s)", &actions);
528   g_assert_cmpint (g_strv_length (actions), ==, G_N_ELEMENTS (exported_entries));
529   g_free (actions);
530   g_variant_unref (v);
531   g_main_loop_quit (loop);
532 }
533
534 static gboolean
535 call_list (gpointer user_data)
536 {
537   GDBusConnection *bus;
538
539   bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
540   g_dbus_connection_call (bus,
541                           g_dbus_connection_get_unique_name (bus),
542                           "/",
543                           "org.gtk.Actions",
544                           "List",
545                           NULL,
546                           NULL,
547                           0,
548                           G_MAXINT,
549                           NULL,
550                           list_cb,
551                           user_data);
552   g_object_unref (bus);
553
554   return G_SOURCE_REMOVE;
555 }
556
557 static void
558 describe_cb (GObject      *source,
559              GAsyncResult *res,
560              gpointer      user_data)
561 {
562   GDBusConnection *bus = G_DBUS_CONNECTION (source);
563   GMainLoop *loop = user_data;
564   GError *error = NULL;
565   GVariant *v;
566   gboolean enabled;
567   gchar *param;
568   GVariantIter *iter;
569
570   v = g_dbus_connection_call_finish (bus, res, &error);
571   g_assert (v);
572   /* FIXME: there's an extra level of tuplelization in here */
573   g_variant_get (v, "((bgav))", &enabled, &param, &iter);
574   g_assert (enabled == TRUE);
575   g_assert_cmpstr (param, ==, "");
576   g_assert_cmpint (g_variant_iter_n_children (iter), ==, 0);
577   g_free (param);
578   g_variant_iter_free (iter);
579   g_variant_unref (v);
580
581   g_main_loop_quit (loop);
582 }
583
584 static gboolean
585 call_describe (gpointer user_data)
586 {
587   GDBusConnection *bus;
588
589   bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
590   g_dbus_connection_call (bus,
591                           g_dbus_connection_get_unique_name (bus),
592                           "/",
593                           "org.gtk.Actions",
594                           "Describe",
595                           g_variant_new ("(s)", "copy"),
596                           NULL,
597                           0,
598                           G_MAXINT,
599                           NULL,
600                           describe_cb,
601                           user_data);
602   g_object_unref (bus);
603
604   return G_SOURCE_REMOVE;
605 }
606
607 static void
608 test_dbus_export (void)
609 {
610   GDBusConnection *bus;
611   GSimpleActionGroup *group;
612   GDBusActionGroup *proxy;
613   GSimpleAction *action;
614   GMainLoop *loop;
615   GError *error = NULL;
616   GVariant *v;
617   guint id;
618   gchar **actions;
619
620   loop = g_main_loop_new (NULL, FALSE);
621
622   session_bus_up ();
623   bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
624
625   group = g_simple_action_group_new ();
626   g_simple_action_group_add_entries (group,
627                                      exported_entries,
628                                      G_N_ELEMENTS (exported_entries),
629                                      NULL);
630
631   id = g_dbus_connection_export_action_group (bus, "/", G_ACTION_GROUP (group), &error);
632   g_assert_no_error (error);
633
634   proxy = g_dbus_action_group_get (bus, g_dbus_connection_get_unique_name (bus), "/");
635
636   actions = g_action_group_list_actions (G_ACTION_GROUP (proxy));
637   g_assert_cmpint (g_strv_length (actions), ==, 0);
638   g_strfreev (actions);
639
640   g_timeout_add (100, stop_loop, loop);
641   g_main_loop_run (loop);
642
643   actions = g_action_group_list_actions (G_ACTION_GROUP (proxy));
644   g_assert_cmpint (g_strv_length (actions), ==, G_N_ELEMENTS (exported_entries));
645   g_strfreev (actions);
646
647   /* check that calling "List" works too */
648   g_idle_add (call_list, loop);
649   g_main_loop_run (loop);
650
651   /* check that calling "Describe" works */
652   g_idle_add (call_describe, loop);
653   g_main_loop_run (loop);
654
655   /* test that the initial transfer works */
656   g_assert (G_IS_DBUS_ACTION_GROUP (proxy));
657   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
658
659   /* test that various changes get propagated from group to proxy */
660   action = g_simple_action_new_stateful ("italic", NULL, g_variant_new_boolean (FALSE));
661   g_simple_action_group_insert (group, G_ACTION (action));
662   g_object_unref (action);
663
664   g_timeout_add (100, stop_loop, loop);
665   g_main_loop_run (loop);
666
667   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
668
669   action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "cut"));
670   g_simple_action_set_enabled (action, FALSE);
671
672   g_timeout_add (100, stop_loop, loop);
673   g_main_loop_run (loop);
674
675   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
676
677   action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "bold"));
678   g_simple_action_set_state (action, g_variant_new_boolean (FALSE));
679
680   g_timeout_add (100, stop_loop, loop);
681   g_main_loop_run (loop);
682
683   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
684
685   g_simple_action_group_remove (group, "italic");
686
687   g_timeout_add (100, stop_loop, loop);
688   g_main_loop_run (loop);
689
690   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
691
692   /* test that activations and state changes propagate the other way */
693
694   g_assert_cmpint (activation_count ("copy"), ==, 0);
695   g_action_group_activate_action (G_ACTION_GROUP (proxy), "copy", NULL);
696
697   g_timeout_add (100, stop_loop, loop);
698   g_main_loop_run (loop);
699
700   g_assert_cmpint (activation_count ("copy"), ==, 1);
701   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
702
703   g_assert_cmpint (activation_count ("bold"), ==, 0);
704   g_action_group_activate_action (G_ACTION_GROUP (proxy), "bold", NULL);
705
706   g_timeout_add (100, stop_loop, loop);
707   g_main_loop_run (loop);
708
709   g_assert_cmpint (activation_count ("bold"), ==, 1);
710   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
711   v = g_action_group_get_action_state (G_ACTION_GROUP (group), "bold");
712   g_assert (g_variant_get_boolean (v));
713   g_variant_unref (v);
714
715   g_action_group_change_action_state (G_ACTION_GROUP (proxy), "bold", g_variant_new_boolean (FALSE));
716
717   g_timeout_add (100, stop_loop, loop);
718   g_main_loop_run (loop);
719
720   g_assert_cmpint (activation_count ("bold"), ==, 1);
721   g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
722   v = g_action_group_get_action_state (G_ACTION_GROUP (group), "bold");
723   g_assert (!g_variant_get_boolean (v));
724   g_variant_unref (v);
725
726   g_dbus_connection_unexport_action_group (bus, id);
727
728   g_object_unref (proxy);
729   g_object_unref (group);
730   g_main_loop_unref (loop);
731   g_object_unref (bus);
732
733   session_bus_down ();
734 }
735
736 static gpointer
737 do_export (gpointer data)
738 {
739   GActionGroup *group = data;
740   GMainContext *ctx;
741   gint i;
742   GError *error = NULL;
743   guint id;
744   GDBusConnection *bus;
745   GAction *action;
746   gchar *path;
747
748   ctx = g_main_context_new ();
749
750   g_main_context_push_thread_default (ctx);
751
752   bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
753   path = g_strdup_printf("/%p", data);
754
755   for (i = 0; i < 100000; i++)
756     {
757       id = g_dbus_connection_export_action_group (bus, path, G_ACTION_GROUP (group), &error);
758       g_assert_no_error (error);
759
760       action = g_simple_action_group_lookup (G_SIMPLE_ACTION_GROUP (group), "a");
761       g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
762                                    !g_action_get_enabled (action));
763
764       g_dbus_connection_unexport_action_group (bus, id);
765
766       while (g_main_context_iteration (ctx, FALSE));
767     }
768
769   g_free (path);
770   g_object_unref (bus);
771
772   g_main_context_pop_thread_default (ctx);
773
774   g_main_context_unref (ctx);
775
776   return NULL;
777 }
778
779 static void
780 test_dbus_threaded (void)
781 {
782   GSimpleActionGroup *group[10];
783   GThread *export[10];
784   static GActionEntry entries[] = {
785     { "a",  activate_action, NULL, NULL, NULL },
786     { "b",  activate_action, NULL, NULL, NULL },
787   };
788   gint i;
789
790   session_bus_up ();
791
792   for (i = 0; i < 10; i++)
793     {
794       group[i] = g_simple_action_group_new ();
795       g_simple_action_group_add_entries (group[i], entries, G_N_ELEMENTS (entries), NULL);
796       export[i] = g_thread_new ("export", do_export, group[i]);
797     }
798
799   for (i = 0; i < 10; i++)
800     g_thread_join (export[i]);
801
802   for (i = 0; i < 10; i++)
803     g_object_unref (group[i]);
804
805   session_bus_down ();
806 }
807
808 static void
809 test_bug679509 (void)
810 {
811   GDBusConnection *bus;
812   GDBusActionGroup *proxy;
813   GMainLoop *loop;
814
815   loop = g_main_loop_new (NULL, FALSE);
816
817   session_bus_up ();
818   bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
819
820   proxy = g_dbus_action_group_get (bus, g_dbus_connection_get_unique_name (bus), "/");
821   g_strfreev (g_action_group_list_actions (G_ACTION_GROUP (proxy)));
822   g_object_unref (proxy);
823
824   g_timeout_add (100, stop_loop, loop);
825   g_main_loop_run (loop);
826
827   g_main_loop_unref (loop);
828   g_object_unref (bus);
829
830   session_bus_down ();
831 }
832
833 int
834 main (int argc, char **argv)
835 {
836   g_type_init ();
837   g_test_init (&argc, &argv, NULL);
838
839   g_test_add_func ("/actions/basic", test_basic);
840   g_test_add_func ("/actions/simplegroup", test_simple_group);
841   g_test_add_func ("/actions/stateful", test_stateful);
842   g_test_add_func ("/actions/entries", test_entries);
843   g_test_add_func ("/actions/dbus/export", test_dbus_export);
844   g_test_add_func ("/actions/dbus/threaded", test_dbus_threaded);
845   g_test_add_func ("/actions/dbus/bug679509", test_bug679509);
846
847   return g_test_run ();
848 }