gapplication tests: test resource base path
[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 #if 0
10 /* These tests are racy -- there is no guarantee about the order of data
11  * arriving over D-Bus.
12  *
13  * They're also a bit ridiculous -- GApplication was never meant to be
14  * abused in this way...
15  *
16  * We need new tests.
17  */
18 static gint outstanding_watches;
19 static GMainLoop *main_loop;
20
21 typedef struct
22 {
23   gchar *expected_stdout;
24   gint stdout_pipe;
25   gchar *expected_stderr;
26   gint stderr_pipe;
27 } ChildData;
28
29 static void
30 check_data (gint fd, const gchar *expected)
31 {
32   gssize len, actual;
33   gchar *buffer;
34   
35   len = strlen (expected);
36   buffer = g_alloca (len + 100);
37   actual = read (fd, buffer, len + 100);
38
39   g_assert_cmpint (actual, >=, 0);
40
41   if (actual != len ||
42       memcmp (buffer, expected, len) != 0)
43     {
44       buffer[MIN(len + 100, actual)] = '\0';
45
46       g_error ("\nExpected\n-----\n%s-----\nGot (%s)\n-----\n%s-----\n",
47                expected,
48                (actual > len) ? "truncated" : "full", buffer);
49     }
50 }
51
52 static void
53 child_quit (GPid     pid,
54             gint     status,
55             gpointer data)
56 {
57   ChildData *child = data;
58
59   g_assert_cmpint (status, ==, 0);
60
61   if (--outstanding_watches == 0)
62     g_main_loop_quit (main_loop);
63
64   check_data (child->stdout_pipe, child->expected_stdout);
65   close (child->stdout_pipe);
66   g_free (child->expected_stdout);
67
68   if (child->expected_stderr)
69     {
70       check_data (child->stderr_pipe, child->expected_stderr);
71       close (child->stderr_pipe);
72       g_free (child->expected_stderr);
73     }
74
75   g_slice_free (ChildData, child);
76 }
77
78 static void
79 spawn (const gchar *expected_stdout,
80        const gchar *expected_stderr,
81        const gchar *first_arg,
82        ...)
83 {
84   GError *error = NULL;
85   const gchar *arg;
86   GPtrArray *array;
87   ChildData *data;
88   gchar **args;
89   va_list ap;
90   GPid pid;
91   GPollFD fd;
92   gchar **env;
93
94   va_start (ap, first_arg);
95   array = g_ptr_array_new ();
96   g_ptr_array_add (array, g_test_build_filename (G_TEST_BUILT, "basic-application", NULL));
97   for (arg = first_arg; arg; arg = va_arg (ap, const gchar *))
98     g_ptr_array_add (array, g_strdup (arg));
99   g_ptr_array_add (array, NULL);
100   args = (gchar **) g_ptr_array_free (array, FALSE);
101   va_end (ap);
102
103   env = g_environ_setenv (g_get_environ (), "TEST", "1", TRUE);
104
105   data = g_slice_new (ChildData);
106   data->expected_stdout = g_strdup (expected_stdout);
107   data->expected_stderr = g_strdup (expected_stderr);
108
109   g_spawn_async_with_pipes (NULL, args, env,
110                             G_SPAWN_DO_NOT_REAP_CHILD,
111                             NULL, NULL, &pid, NULL,
112                             &data->stdout_pipe,
113                             expected_stderr ? &data->stderr_pipe : NULL,
114                             &error);
115   g_assert_no_error (error);
116
117   g_strfreev (env);
118
119   g_child_watch_add (pid, child_quit, data);
120   outstanding_watches++;
121
122   /* we block until the children write to stdout to make sure
123    * they have started, as they need to be executed in order;
124    * see https://bugzilla.gnome.org/show_bug.cgi?id=664627
125    */
126   fd.fd = data->stdout_pipe;
127   fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
128   g_poll (&fd, 1, -1);
129 }
130
131 static void
132 basic (void)
133 {
134   GDBusConnection *c;
135
136   g_assert (outstanding_watches == 0);
137
138   session_bus_up ();
139   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
140
141   main_loop = g_main_loop_new (NULL, 0);
142
143   /* spawn the master */
144   spawn ("activated\n"
145          "open file:///a file:///b\n"
146          "exit status: 0\n", NULL,
147          "./app", NULL);
148
149   /* send it some files */
150   spawn ("exit status: 0\n", NULL,
151          "./app", "/a", "/b", NULL);
152
153   g_main_loop_run (main_loop);
154
155   g_object_unref (c);
156   session_bus_down ();
157
158   g_main_loop_unref (main_loop);
159 }
160
161 static void
162 test_remote_command_line (void)
163 {
164   GDBusConnection *c;
165   GFile *file;
166   gchar *replies;
167   gchar *cwd;
168
169   g_assert (outstanding_watches == 0);
170
171   session_bus_up ();
172   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
173
174   main_loop = g_main_loop_new (NULL, 0);
175
176   file = g_file_new_for_commandline_arg ("foo");
177   cwd = g_get_current_dir ();
178
179   replies = g_strconcat ("got ./cmd 0\n",
180                          "got ./cmd 1\n",
181                          "cmdline ./cmd echo --abc -d\n",
182                          "environment TEST=1\n",
183                          "getenv TEST=1\n",
184                          "file ", g_file_get_path (file), "\n",
185                          "properties ok\n",
186                          "cwd ", cwd, "\n",
187                          "busy\n",
188                          "idle\n",
189                          "stdin ok\n",        
190                          "exit status: 0\n",
191                          NULL);
192   g_object_unref (file);
193
194   /* spawn the master */
195   spawn (replies, NULL,
196          "./cmd", NULL);
197
198   g_free (replies);
199
200   /* send it a few commandlines */
201   spawn ("exit status: 0\n", NULL,
202          "./cmd", NULL);
203
204   spawn ("exit status: 0\n", NULL,
205          "./cmd", "echo", "--abc", "-d", NULL);
206
207   spawn ("exit status: 0\n", NULL,
208          "./cmd", "env", NULL);
209
210   spawn ("exit status: 0\n", NULL,
211          "./cmd", "getenv", NULL);
212
213   spawn ("print test\n"
214          "exit status: 0\n", NULL,
215          "./cmd", "print", "test", NULL);
216
217   spawn ("exit status: 0\n", "printerr test\n",
218          "./cmd", "printerr", "test", NULL);
219
220   spawn ("exit status: 0\n", NULL,
221          "./cmd", "file", "foo", NULL);
222
223   spawn ("exit status: 0\n", NULL,
224          "./cmd", "properties", NULL);
225
226   spawn ("exit status: 0\n", NULL,
227          "./cmd", "cwd", NULL);
228
229   spawn ("exit status: 0\n", NULL,
230          "./cmd", "busy", NULL);
231
232   spawn ("exit status: 0\n", NULL,
233          "./cmd", "idle", NULL);
234
235   spawn ("exit status: 0\n", NULL,
236          "./cmd", "stdin", NULL);
237
238   g_main_loop_run (main_loop);
239
240   g_object_unref (c);
241   session_bus_down ();
242
243   g_main_loop_unref (main_loop);
244 }
245
246 static void
247 test_remote_actions (void)
248 {
249   GDBusConnection *c;
250
251   g_assert (outstanding_watches == 0);
252
253   session_bus_up ();
254   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
255
256   main_loop = g_main_loop_new (NULL, 0);
257
258   /* spawn the master */
259   spawn ("got ./cmd 0\n"
260          "activate action1\n"
261          "change action2 1\n"
262          "exit status: 0\n", NULL,
263          "./cmd", NULL);
264
265   spawn ("actions quit new action1 action2\n"
266          "exit status: 0\n", NULL,
267          "./actions", "list", NULL);
268
269   spawn ("exit status: 0\n", NULL,
270          "./actions", "activate", NULL);
271
272   spawn ("exit status: 0\n", NULL,
273          "./actions", "set-state", NULL);
274
275   g_main_loop_run (main_loop);
276
277   g_object_unref (c);
278   session_bus_down ();
279
280   g_main_loop_unref (main_loop);
281 }
282 #endif
283
284 #if 0
285 /* Now that we register non-unique apps on the bus we need to fix the
286  * following test not to assume that it's safe to create multiple instances
287  * of the same app in one process.
288  *
289  * See https://bugzilla.gnome.org/show_bug.cgi?id=647986 for the patch that
290  * introduced this problem.
291  */
292
293 static GApplication *recently_activated;
294 static GMainLoop *loop;
295
296 static void
297 nonunique_activate (GApplication *application)
298 {
299   recently_activated = application;
300
301   if (loop != NULL)
302     g_main_loop_quit (loop);
303 }
304
305 static GApplication *
306 make_app (gboolean non_unique)
307 {
308   GApplication *app;
309   gboolean ok;
310
311   app = g_application_new ("org.gtk.Test-Application",
312                            non_unique ? G_APPLICATION_NON_UNIQUE : 0);
313   g_signal_connect (app, "activate", G_CALLBACK (nonunique_activate), NULL);
314   ok = g_application_register (app, NULL, NULL);
315   if (!ok)
316     {
317       g_object_unref (app);
318       return NULL;
319     }
320
321   g_application_activate (app);
322
323   return app;
324 }
325
326 static void
327 test_nonunique (void)
328 {
329   GApplication *first, *second, *third, *fourth;
330
331   session_bus_up ();
332
333   first = make_app (TRUE);
334   /* non-remote because it is non-unique */
335   g_assert (!g_application_get_is_remote (first));
336   g_assert (recently_activated == first);
337   recently_activated = NULL;
338
339   second = make_app (FALSE);
340   /* non-remote because it is first */
341   g_assert (!g_application_get_is_remote (second));
342   g_assert (recently_activated == second);
343   recently_activated = NULL;
344
345   third = make_app (TRUE);
346   /* non-remote because it is non-unique */
347   g_assert (!g_application_get_is_remote (third));
348   g_assert (recently_activated == third);
349   recently_activated = NULL;
350
351   fourth = make_app (FALSE);
352   /* should have failed to register due to being
353    * unable to register the object paths
354    */
355   g_assert (fourth == NULL);
356   g_assert (recently_activated == NULL);
357
358   g_object_unref (first);
359   g_object_unref (second);
360   g_object_unref (third);
361
362   session_bus_down ();
363 }
364 #endif
365
366 static void
367 properties (void)
368 {
369   GDBusConnection *c;
370   GObject *app;
371   gchar *id;
372   GApplicationFlags flags;
373   gboolean registered;
374   guint timeout;
375   gboolean remote;
376   gboolean ret;
377   GError *error = NULL;
378
379   session_bus_up ();
380   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
381
382   app = g_object_new (G_TYPE_APPLICATION,
383                       "application-id", "org.gtk.TestApplication",
384                       NULL);
385
386   g_object_get (app,
387                 "application-id", &id,
388                 "flags", &flags,
389                 "is-registered", &registered,
390                 "inactivity-timeout", &timeout,
391                 NULL);
392
393   g_assert_cmpstr (id, ==, "org.gtk.TestApplication");
394   g_assert_cmpint (flags, ==, G_APPLICATION_FLAGS_NONE);
395   g_assert (!registered);
396   g_assert_cmpint (timeout, ==, 0);
397
398   ret = g_application_register (G_APPLICATION (app), NULL, &error);
399   g_assert (ret);
400   g_assert_no_error (error);
401
402   g_object_get (app,
403                 "is-registered", &registered,
404                 "is-remote", &remote,
405                 NULL);
406
407   g_assert (registered);
408   g_assert (!remote);
409
410   g_object_set (app,
411                 "inactivity-timeout", 1000,
412                 NULL);
413
414   g_application_quit (G_APPLICATION (app));
415
416   g_object_unref (c);
417   g_object_unref (app);
418   g_free (id);
419
420   session_bus_down ();
421 }
422
423 static void
424 appid (void)
425 {
426   gchar *id;
427
428   g_assert (!g_application_id_is_valid (""));
429   g_assert (!g_application_id_is_valid ("."));
430   g_assert (!g_application_id_is_valid ("a"));
431   g_assert (!g_application_id_is_valid ("abc"));
432   g_assert (!g_application_id_is_valid (".abc"));
433   g_assert (!g_application_id_is_valid ("abc."));
434   g_assert (!g_application_id_is_valid ("a..b"));
435   g_assert (!g_application_id_is_valid ("a/b"));
436   g_assert (!g_application_id_is_valid ("a\nb"));
437   g_assert (!g_application_id_is_valid ("a\nb"));
438   g_assert (!g_application_id_is_valid ("_a.b"));
439   g_assert (!g_application_id_is_valid ("-a.b"));
440   id = g_new0 (gchar, 261);
441   memset (id, 'a', 260);
442   id[1] = '.';
443   id[260] = 0;
444   g_assert (!g_application_id_is_valid (id));
445   g_free (id);
446
447   g_assert (g_application_id_is_valid ("a.b"));
448   g_assert (g_application_id_is_valid ("A.B"));
449   g_assert (g_application_id_is_valid ("A-.B"));
450   g_assert (g_application_id_is_valid ("a_b.c-d"));
451   g_assert (g_application_id_is_valid ("org.gnome.SessionManager"));
452 }
453
454 static gboolean nodbus_activated;
455
456 static gboolean
457 release_app (gpointer user_data)
458 {
459   g_application_release (user_data);
460   return G_SOURCE_REMOVE;
461 }
462
463 static void
464 nodbus_activate (GApplication *app)
465 {
466   nodbus_activated = TRUE;
467   g_application_hold (app);
468
469   g_assert (g_application_get_dbus_connection (app) == NULL);
470   g_assert (g_application_get_dbus_object_path (app) == NULL);
471
472   g_idle_add (release_app, app);
473 }
474
475 static void
476 test_nodbus (void)
477 {
478   char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
479   gchar *argv[] = { binpath, NULL };
480   GApplication *app;
481
482   app = g_application_new ("org.gtk.Unimportant", G_APPLICATION_FLAGS_NONE);
483   g_signal_connect (app, "activate", G_CALLBACK (nodbus_activate), NULL);
484   g_application_run (app, 1, argv);
485   g_object_unref (app);
486
487   g_assert (nodbus_activated);
488   g_free (binpath);
489 }
490
491 static gboolean noappid_activated;
492
493 static void
494 noappid_activate (GApplication *app)
495 {
496   noappid_activated = TRUE;
497   g_application_hold (app);
498
499   g_assert (g_application_get_flags (app) & G_APPLICATION_NON_UNIQUE);
500
501   g_idle_add (release_app, app);
502 }
503
504 /* test that no appid -> non-unique */
505 static void
506 test_noappid (void)
507 {
508   char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
509   gchar *argv[] = { binpath, NULL };
510   GApplication *app;
511
512   app = g_application_new (NULL, G_APPLICATION_FLAGS_NONE);
513   g_signal_connect (app, "activate", G_CALLBACK (noappid_activate), NULL);
514   g_application_run (app, 1, argv);
515   g_object_unref (app);
516
517   g_assert (noappid_activated);
518   g_free (binpath);
519 }
520
521 static gboolean activated;
522 static gboolean quitted;
523
524 static gboolean
525 quit_app (gpointer user_data)
526 {
527   quitted = TRUE;
528   g_application_quit (user_data);
529   return G_SOURCE_REMOVE;
530 }
531
532 static void
533 quit_activate (GApplication *app)
534 {
535   activated = TRUE;
536   g_application_hold (app);
537
538   g_assert (g_application_get_dbus_connection (app) != NULL);
539   g_assert (g_application_get_dbus_object_path (app) != NULL);
540
541   g_idle_add (quit_app, app);
542 }
543
544 static void
545 test_quit (void)
546 {
547   GDBusConnection *c;
548   char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
549   gchar *argv[] = { binpath, NULL };
550   GApplication *app;
551
552   session_bus_up ();
553   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
554
555   app = g_application_new ("org.gtk.Unimportant",
556                            G_APPLICATION_FLAGS_NONE);
557   activated = FALSE;
558   quitted = FALSE;
559   g_signal_connect (app, "activate", G_CALLBACK (quit_activate), NULL);
560   g_application_run (app, 1, argv);
561   g_object_unref (app);
562   g_object_unref (c);
563
564   g_assert (activated);
565   g_assert (quitted);
566
567   session_bus_down ();
568   g_free (binpath);
569 }
570
571 static void
572 on_activate (GApplication *app)
573 {
574   gchar **actions;
575   GAction *action;
576   GVariant *state;
577
578   g_assert (!g_application_get_is_remote (app));
579
580   actions = g_action_group_list_actions (G_ACTION_GROUP (app));
581   g_assert (g_strv_length (actions) == 0);
582   g_strfreev (actions);
583
584   action = (GAction*)g_simple_action_new_stateful ("test", G_VARIANT_TYPE_BOOLEAN, g_variant_new_boolean (FALSE));
585   g_action_map_add_action (G_ACTION_MAP (app), action);
586
587   actions = g_action_group_list_actions (G_ACTION_GROUP (app));
588   g_assert (g_strv_length (actions) == 1);
589   g_strfreev (actions);
590
591   g_action_group_change_action_state (G_ACTION_GROUP (app), "test", g_variant_new_boolean (TRUE));
592   state = g_action_group_get_action_state (G_ACTION_GROUP (app), "test");
593   g_assert (g_variant_get_boolean (state) == TRUE);
594
595   action = g_action_map_lookup_action (G_ACTION_MAP (app), "test");
596   g_assert (action != NULL);
597
598   g_action_map_remove_action (G_ACTION_MAP (app), "test");
599
600   actions = g_action_group_list_actions (G_ACTION_GROUP (app));
601   g_assert (g_strv_length (actions) == 0);
602   g_strfreev (actions);
603 }
604
605 static void
606 test_local_actions (void)
607 {
608   char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
609   gchar *argv[] = { binpath, NULL };
610   GApplication *app;
611
612   app = g_application_new ("org.gtk.Unimportant",
613                            G_APPLICATION_FLAGS_NONE);
614   g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
615   g_application_run (app, 1, argv);
616   g_object_unref (app);
617   g_free (binpath);
618 }
619
620 typedef GApplication TestLocCmdApp;
621 typedef GApplicationClass TestLocCmdAppClass;
622
623 static GType test_loc_cmd_app_get_type (void);
624 G_DEFINE_TYPE (TestLocCmdApp, test_loc_cmd_app, G_TYPE_APPLICATION)
625
626 static void
627 test_loc_cmd_app_init (TestLocCmdApp *app)
628 {
629 }
630
631 static void
632 test_loc_cmd_app_startup (GApplication *app)
633 {
634   g_assert_not_reached ();
635 }
636
637 static void
638 test_loc_cmd_app_shutdown (GApplication *app)
639 {
640   g_assert_not_reached ();
641 }
642
643 static gboolean
644 test_loc_cmd_app_local_command_line (GApplication   *application,
645                                      gchar        ***arguments,
646                                      gint           *exit_status)
647 {
648   return TRUE;
649 }
650
651 static void
652 test_loc_cmd_app_class_init (TestLocCmdAppClass *klass)
653 {
654   G_APPLICATION_CLASS (klass)->startup = test_loc_cmd_app_startup;
655   G_APPLICATION_CLASS (klass)->shutdown = test_loc_cmd_app_shutdown;
656   G_APPLICATION_CLASS (klass)->local_command_line = test_loc_cmd_app_local_command_line;
657 }
658
659 static void
660 test_local_command_line (void)
661 {
662   char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
663   gchar *argv[] = { binpath, "-invalid", NULL };
664   GApplication *app;
665
666   app = g_object_new (test_loc_cmd_app_get_type (),
667                       "application-id", "org.gtk.Unimportant",
668                       "flags", G_APPLICATION_FLAGS_NONE,
669                       NULL);
670   g_application_run (app, 1, argv);
671   g_object_unref (app);
672   g_free (binpath);
673 }
674
675 static void
676 test_resource_path (void)
677 {
678   GApplication *app;
679
680   app = g_application_new ("x.y.z", 0);
681   g_assert_cmpstr (g_application_get_resource_base_path (app), ==, "/x/y/z");
682
683   /* this should not change anything */
684   g_application_set_application_id (app, "a.b.c");
685   g_assert_cmpstr (g_application_get_resource_base_path (app), ==, "/x/y/z");
686
687   /* but this should... */
688   g_application_set_resource_base_path (app, "/x");
689   g_assert_cmpstr (g_application_get_resource_base_path (app), ==, "/x");
690
691   /* ... and this */
692   g_application_set_resource_base_path (app, NULL);
693   g_assert_cmpstr (g_application_get_resource_base_path (app), ==, NULL);
694
695   g_object_unref (app);
696
697   /* Make sure that overriding at construction time works properly */
698   app = g_object_new (G_TYPE_APPLICATION, "application-id", "x.y.z", "resource-base-path", "/a", NULL);
699   g_assert_cmpstr (g_application_get_resource_base_path (app), ==, "/a");
700   g_object_unref (app);
701
702   /* ... particularly if we override to NULL */
703   app = g_object_new (G_TYPE_APPLICATION, "application-id", "x.y.z", "resource-base-path", NULL, NULL);
704   g_assert_cmpstr (g_application_get_resource_base_path (app), ==, NULL);
705   g_object_unref (app);
706 }
707
708 int
709 main (int argc, char **argv)
710 {
711   g_test_init (&argc, &argv, NULL);
712
713   g_test_dbus_unset ();
714
715   g_test_add_func ("/gapplication/no-dbus", test_nodbus);
716 /*  g_test_add_func ("/gapplication/basic", basic); */
717   g_test_add_func ("/gapplication/no-appid", test_noappid);
718 /*  g_test_add_func ("/gapplication/non-unique", test_nonunique); */
719   g_test_add_func ("/gapplication/properties", properties);
720   g_test_add_func ("/gapplication/app-id", appid);
721   g_test_add_func ("/gapplication/quit", test_quit);
722   g_test_add_func ("/gapplication/local-actions", test_local_actions);
723 /*  g_test_add_func ("/gapplication/remote-actions", test_remote_actions); */
724   g_test_add_func ("/gapplication/local-command-line", test_local_command_line);
725 /*  g_test_add_func ("/gapplication/remote-command-line", test_remote_command_line); */
726   g_test_add_func ("/gapplication/resource-path", test_resource_path);
727
728   return g_test_run ();
729 }