Fix make check with builddir != srcdir
[platform/upstream/glib.git] / gio / tests / gapplication.c
1 #include <gio/gio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5
6 #include "gdbus-tests.h"
7 #include "gdbus-sessionbus.h"
8
9 static const gchar *datapath;
10 static const gchar *binpath;
11
12 static gint outstanding_watches;
13 static GMainLoop *main_loop;
14
15 typedef struct
16 {
17   const gchar *expected_stdout;
18   gint stdout_pipe;
19 } ChildData;
20
21 static void
22 child_quit (GPid     pid,
23             gint     status,
24             gpointer data)
25 {
26   ChildData *child = data;
27   gssize expected, actual;
28   gchar *buffer;
29
30   g_assert_cmpint (status, ==, 0);
31
32   if (--outstanding_watches == 0)
33     g_main_loop_quit (main_loop);
34
35   expected = strlen (child->expected_stdout);
36   buffer = g_alloca (expected + 100);
37   actual = read (child->stdout_pipe, buffer, expected + 100);
38   close (child->stdout_pipe);
39
40   g_assert_cmpint (actual, >=, 0);
41
42   if (actual != expected ||
43       memcmp (buffer, child->expected_stdout, expected) != 0)
44     {
45       buffer[MIN(expected + 100, actual)] = '\0';
46
47       g_error ("\nExpected\n-----\n%s-----\nGot (%s)\n-----\n%s-----\n",
48                child->expected_stdout,
49                (actual > expected) ? "truncated" : "full", buffer);
50     }
51
52   g_slice_free (ChildData, child);
53 }
54
55 static void
56 spawn (const gchar *expected_stdout,
57        const gchar *first_arg,
58        ...)
59 {
60   GError *error = NULL;
61   const gchar *arg;
62   GPtrArray *array;
63   ChildData *data;
64   gchar **args;
65   va_list ap;
66   GPid pid;
67   GPollFD fd;
68
69   va_start (ap, first_arg);
70   array = g_ptr_array_new ();
71   g_ptr_array_add (array, g_build_filename (binpath, "basic-application", NULL));
72   for (arg = first_arg; arg; arg = va_arg (ap, const gchar *))
73     g_ptr_array_add (array, g_strdup (arg));
74   g_ptr_array_add (array, NULL);
75   args = (gchar **) g_ptr_array_free (array, FALSE);
76
77   va_end (ap);
78
79   data = g_slice_new (ChildData);
80   data->expected_stdout = expected_stdout;
81
82   g_spawn_async_with_pipes (NULL, args, NULL,
83                             G_SPAWN_DO_NOT_REAP_CHILD,
84                             NULL, NULL, &pid, NULL,
85                             &data->stdout_pipe, NULL, &error);
86   g_assert_no_error (error);
87
88   g_child_watch_add (pid, child_quit, data);
89   outstanding_watches++;
90
91   /* we block until the children write to stdout to make sure
92    * they have started, as they need to be executed in order;
93    * see https://bugzilla.gnome.org/show_bug.cgi?id=664627
94    */
95   fd.fd = data->stdout_pipe;
96   fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
97   g_poll (&fd, 1, -1);
98 }
99
100 static void
101 basic (void)
102 {
103   GDBusConnection *c;
104
105   session_bus_up ();
106   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
107
108   main_loop = g_main_loop_new (NULL, 0);
109
110   /* spawn the master */
111   spawn ("activated\n"
112          "open file:///a file:///b\n"
113          "cmdline '40 +' '2'\n"
114          "exit status: 0\n",
115          "./app", NULL);
116
117   /* send it some files */
118   spawn ("exit status: 0\n",
119          "./app", "/a", "/b", NULL);
120
121   spawn ("40 + 2 = 42\n"
122          "exit status: 42\n",
123          "./cmd", "40 +", "2", NULL);
124
125   g_main_loop_run (main_loop);
126
127   g_object_unref (c);
128   session_bus_down ();
129 }
130
131
132 #if 0
133 /* Now that we register non-unique apps on the bus we need to fix the
134  * following test not to assume that it's safe to create multiple instances
135  * of the same app in one process.
136  *
137  * See https://bugzilla.gnome.org/show_bug.cgi?id=647986 for the patch that
138  * introduced this problem.
139  */
140
141 static GApplication *recently_activated;
142 static GMainLoop *loop;
143
144 static void
145 nonunique_activate (GApplication *application)
146 {
147   recently_activated = application;
148
149   if (loop != NULL)
150     g_main_loop_quit (loop);
151 }
152
153 static GApplication *
154 make_app (gboolean non_unique)
155 {
156   GApplication *app;
157   gboolean ok;
158
159   app = g_application_new ("org.gtk.Test-Application",
160                            non_unique ? G_APPLICATION_NON_UNIQUE : 0);
161   g_signal_connect (app, "activate", G_CALLBACK (nonunique_activate), NULL);
162   ok = g_application_register (app, NULL, NULL);
163   if (!ok)
164     {
165       g_object_unref (app);
166       return NULL;
167     }
168
169   g_application_activate (app);
170
171   return app;
172 }
173
174 static void
175 test_nonunique (void)
176 {
177   GApplication *first, *second, *third, *fourth;
178
179   session_bus_up ();
180
181   first = make_app (TRUE);
182   /* non-remote because it is non-unique */
183   g_assert (!g_application_get_is_remote (first));
184   g_assert (recently_activated == first);
185   recently_activated = NULL;
186
187   second = make_app (FALSE);
188   /* non-remote because it is first */
189   g_assert (!g_application_get_is_remote (second));
190   g_assert (recently_activated == second);
191   recently_activated = NULL;
192
193   third = make_app (TRUE);
194   /* non-remote because it is non-unique */
195   g_assert (!g_application_get_is_remote (third));
196   g_assert (recently_activated == third);
197   recently_activated = NULL;
198
199   fourth = make_app (FALSE);
200   /* should have failed to register due to being
201    * unable to register the object paths
202    */
203   g_assert (fourth == NULL);
204   g_assert (recently_activated == NULL);
205
206   g_object_unref (first);
207   g_object_unref (second);
208   g_object_unref (third);
209
210   session_bus_down ();
211 }
212 #endif
213
214 static void
215 properties (void)
216 {
217   GDBusConnection *c;
218   GObject *app;
219   gchar *id;
220   GApplicationFlags flags;
221   gboolean registered;
222   guint timeout;
223   gboolean remote;
224   gboolean ret;
225   GError *error = NULL;
226
227   session_bus_up ();
228   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
229
230   app = g_object_new (G_TYPE_APPLICATION,
231                       "application-id", "org.gtk.TestApplication",
232                       NULL);
233
234   g_object_get (app,
235                 "application-id", &id,
236                 "flags", &flags,
237                 "is-registered", &registered,
238                 "inactivity-timeout", &timeout,
239                 NULL);
240
241   g_assert_cmpstr (id, ==, "org.gtk.TestApplication");
242   g_assert_cmpint (flags, ==, G_APPLICATION_FLAGS_NONE);
243   g_assert (!registered);
244   g_assert_cmpint (timeout, ==, 0);
245
246   ret = g_application_register (G_APPLICATION (app), NULL, &error);
247   g_assert (ret);
248   g_assert_no_error (error);
249
250   g_object_get (app,
251                 "is-registered", &registered,
252                 "is-remote", &remote,
253                 NULL);
254
255   g_assert (registered);
256   g_assert (!remote);
257
258   g_object_set (app,
259                 "inactivity-timeout", 1000,
260                 NULL);
261
262   g_application_quit (G_APPLICATION (app));
263
264   g_object_unref (c);
265   g_object_unref (app);
266   g_free (id);
267
268   session_bus_down ();
269 }
270
271 static void
272 appid (void)
273 {
274   gchar *id;
275
276   g_assert (!g_application_id_is_valid (""));
277   g_assert (!g_application_id_is_valid ("."));
278   g_assert (!g_application_id_is_valid ("a"));
279   g_assert (!g_application_id_is_valid ("abc"));
280   g_assert (!g_application_id_is_valid (".abc"));
281   g_assert (!g_application_id_is_valid ("abc."));
282   g_assert (!g_application_id_is_valid ("a..b"));
283   g_assert (!g_application_id_is_valid ("a/b"));
284   g_assert (!g_application_id_is_valid ("a\nb"));
285   g_assert (!g_application_id_is_valid ("a\nb"));
286   g_assert (!g_application_id_is_valid ("_a.b"));
287   g_assert (!g_application_id_is_valid ("-a.b"));
288   id = g_new0 (gchar, 261);
289   memset (id, 'a', 260);
290   id[1] = '.';
291   id[260] = 0;
292   g_assert (!g_application_id_is_valid (id));
293   g_free (id);
294
295   g_assert (g_application_id_is_valid ("a.b"));
296   g_assert (g_application_id_is_valid ("A.B"));
297   g_assert (g_application_id_is_valid ("A-.B"));
298   g_assert (g_application_id_is_valid ("a_b.c-d"));
299   g_assert (g_application_id_is_valid ("org.gnome.SessionManager"));
300 }
301
302 static gboolean nodbus_activated;
303
304 static gboolean
305 release_app (gpointer user_data)
306 {
307   g_application_release (user_data);
308   return G_SOURCE_REMOVE;
309 }
310
311 static void
312 nodbus_activate (GApplication *app)
313 {
314   nodbus_activated = TRUE;
315   g_application_hold (app);
316
317   g_assert (g_application_get_dbus_connection (app) == NULL);
318   g_assert (g_application_get_dbus_object_path (app) == NULL);
319
320   g_idle_add (release_app, app);
321 }
322
323 static void
324 test_nodbus (void)
325 {
326   char *binpath = g_build_filename (datapath, "unimportant", NULL);
327   gchar *argv[] = { binpath, NULL };
328   GApplication *app;
329
330   app = g_application_new ("org.gtk.Unimportant", G_APPLICATION_FLAGS_NONE);
331   g_signal_connect (app, "activate", G_CALLBACK (nodbus_activate), NULL);
332   g_application_run (app, 1, argv);
333   g_object_unref (app);
334
335   g_assert (nodbus_activated);
336   g_free (binpath);
337 }
338
339 static gboolean noappid_activated;
340
341 static void
342 noappid_activate (GApplication *app)
343 {
344   noappid_activated = TRUE;
345   g_application_hold (app);
346
347   g_assert (g_application_get_flags (app) & G_APPLICATION_NON_UNIQUE);
348
349   g_idle_add (release_app, app);
350 }
351
352 /* test that no appid -> non-unique */
353 static void
354 test_noappid (void)
355 {
356   char *binpath = g_build_filename (datapath, "unimportant", NULL);
357   gchar *argv[] = { binpath, NULL };
358   GApplication *app;
359
360   app = g_application_new (NULL, G_APPLICATION_FLAGS_NONE);
361   g_signal_connect (app, "activate", G_CALLBACK (noappid_activate), NULL);
362   g_application_run (app, 1, argv);
363   g_object_unref (app);
364
365   g_assert (noappid_activated);
366   g_free (binpath);
367 }
368
369
370 static gboolean
371 quit_app (gpointer user_data)
372 {
373   g_application_quit (user_data);
374   return G_SOURCE_REMOVE;
375 }
376
377 static gboolean quit_activated;
378
379 static void
380 quit_activate (GApplication *app)
381 {
382   quit_activated = TRUE;
383   g_application_hold (app);
384
385   g_assert (g_application_get_dbus_connection (app) != NULL);
386   g_assert (g_application_get_dbus_object_path (app) != NULL);
387
388   g_idle_add (quit_app, app);
389 }
390
391 static void
392 test_quit (void)
393 {
394   GDBusConnection *c;
395   char *binpath = g_build_filename (datapath, "unimportant", NULL);
396   gchar *argv[] = { binpath, NULL };
397   GApplication *app;
398
399   session_bus_up ();
400   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
401
402   app = g_application_new ("org.gtk.Unimportant",
403                            G_APPLICATION_FLAGS_NONE);
404   g_signal_connect (app, "activate", G_CALLBACK (quit_activate), NULL);
405   g_application_run (app, 1, argv);
406   g_object_unref (app);
407   g_object_unref (c);
408
409   g_assert (quit_activated);
410
411   session_bus_down ();
412   g_free (binpath);
413 }
414
415 static void
416 on_activate (GApplication *app)
417 {
418   gchar **actions;
419   GAction *action;
420   GVariant *state;
421
422   g_assert (!g_application_get_is_remote (app));
423
424   actions = g_action_group_list_actions (G_ACTION_GROUP (app));
425   g_assert (g_strv_length (actions) == 0);
426   g_strfreev (actions);
427
428   action = (GAction*)g_simple_action_new_stateful ("test", G_VARIANT_TYPE_BOOLEAN, g_variant_new_boolean (FALSE));
429   g_action_map_add_action (G_ACTION_MAP (app), action);
430
431   actions = g_action_group_list_actions (G_ACTION_GROUP (app));
432   g_assert (g_strv_length (actions) == 1);
433   g_strfreev (actions);
434
435   g_action_group_change_action_state (G_ACTION_GROUP (app), "test", g_variant_new_boolean (TRUE));
436   state = g_action_group_get_action_state (G_ACTION_GROUP (app), "test");
437   g_assert (g_variant_get_boolean (state) == TRUE);
438
439   g_action_map_remove_action (G_ACTION_MAP (app), "test");
440
441   actions = g_action_group_list_actions (G_ACTION_GROUP (app));
442   g_assert (g_strv_length (actions) == 0);
443   g_strfreev (actions);
444
445   g_idle_add (quit_app, app);
446 }
447
448 static void
449 test_actions (void)
450 {
451   char *binpath = g_build_filename (datapath, "unimportant", NULL);
452   gchar *argv[] = { binpath, NULL };
453   GApplication *app;
454
455   g_unsetenv ("DBUS_SESSION_BUS_ADDRESS");
456
457   app = g_application_new ("org.gtk.Unimportant",
458                            G_APPLICATION_FLAGS_NONE);
459   g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
460   g_application_run (app, 1, argv);
461   g_object_unref (app);
462   g_free (binpath);
463 }
464
465 typedef GApplication TestLocCmdApp;
466 typedef GApplicationClass TestLocCmdAppClass;
467
468 static GType test_loc_cmd_app_get_type (void);
469 G_DEFINE_TYPE (TestLocCmdApp, test_loc_cmd_app, G_TYPE_APPLICATION)
470
471 static void
472 test_loc_cmd_app_init (TestLocCmdApp *app)
473 {
474 }
475
476 static void
477 test_loc_cmd_app_startup (GApplication *app)
478 {
479   g_assert_not_reached ();
480 }
481
482 static void
483 test_loc_cmd_app_shutdown (GApplication *app)
484 {
485   g_assert_not_reached ();
486 }
487
488 static gboolean
489 test_loc_cmd_app_local_command_line (GApplication   *application,
490                                      gchar        ***arguments,
491                                      gint           *exit_status)
492 {
493   return TRUE;
494 }
495
496 static void
497 test_loc_cmd_app_class_init (TestLocCmdAppClass *klass)
498 {
499   G_APPLICATION_CLASS (klass)->startup = test_loc_cmd_app_startup;
500   G_APPLICATION_CLASS (klass)->shutdown = test_loc_cmd_app_shutdown;
501   G_APPLICATION_CLASS (klass)->local_command_line = test_loc_cmd_app_local_command_line;
502 }
503
504 static void
505 test_local_command_line (void)
506 {
507   char *binpath = g_build_filename (datapath, "unimportant", NULL);
508   gchar *argv[] = { binpath, "-invalid", NULL };
509   GApplication *app;
510
511   g_unsetenv ("DBUS_SESSION_BUS_ADDRESS");
512
513   app = g_object_new (test_loc_cmd_app_get_type (),
514                       "application-id", "org.gtk.Unimportant",
515                       "flags", G_APPLICATION_FLAGS_NONE,
516                       NULL);
517   g_application_run (app, 1, argv);
518   g_object_unref (app);
519   g_free (binpath);
520 }
521
522 int
523 main (int argc, char **argv)
524 {
525   if (g_getenv ("G_TEST_DATA"))
526     datapath = binpath = g_getenv ("G_TEST_DATA");
527   else
528     {
529       datapath = SRCDIR;
530       binpath = BUILDDIR;
531     }
532
533   g_test_init (&argc, &argv, NULL);
534
535   g_test_dbus_unset ();
536
537   g_test_add_func ("/gapplication/no-dbus", test_nodbus);
538   g_test_add_func ("/gapplication/basic", basic);
539   g_test_add_func ("/gapplication/no-appid", test_noappid);
540 /*  g_test_add_func ("/gapplication/non-unique", test_nonunique); */
541   g_test_add_func ("/gapplication/properties", properties);
542   g_test_add_func ("/gapplication/app-id", appid);
543   g_test_add_func ("/gapplication/quit", test_quit);
544   g_test_add_func ("/gapplication/actions", test_actions);
545   g_test_add_func ("/gapplication/local-command-line", test_local_command_line);
546
547   return g_test_run ();
548 }