6 #include "gdbus-tests.h"
7 #include "gdbus-sessionbus.h"
10 /* These tests are racy -- there is no guarantee about the order of data
11 * arriving over D-Bus.
13 * They're also a bit ridiculous -- GApplication was never meant to be
14 * abused in this way...
18 static gint outstanding_watches;
19 static GMainLoop *main_loop;
23 gchar *expected_stdout;
25 gchar *expected_stderr;
30 check_data (gint fd, const gchar *expected)
35 len = strlen (expected);
36 buffer = g_alloca (len + 100);
37 actual = read (fd, buffer, len + 100);
39 g_assert_cmpint (actual, >=, 0);
42 memcmp (buffer, expected, len) != 0)
44 buffer[MIN(len + 100, actual)] = '\0';
46 g_error ("\nExpected\n-----\n%s-----\nGot (%s)\n-----\n%s-----\n",
48 (actual > len) ? "truncated" : "full", buffer);
57 ChildData *child = data;
59 g_assert_cmpint (status, ==, 0);
61 if (--outstanding_watches == 0)
62 g_main_loop_quit (main_loop);
64 check_data (child->stdout_pipe, child->expected_stdout);
65 close (child->stdout_pipe);
66 g_free (child->expected_stdout);
68 if (child->expected_stderr)
70 check_data (child->stderr_pipe, child->expected_stderr);
71 close (child->stderr_pipe);
72 g_free (child->expected_stderr);
75 g_slice_free (ChildData, child);
79 spawn (const gchar *expected_stdout,
80 const gchar *expected_stderr,
81 const gchar *first_arg,
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);
103 env = g_environ_setenv (g_get_environ (), "TEST", "1", TRUE);
105 data = g_slice_new (ChildData);
106 data->expected_stdout = g_strdup (expected_stdout);
107 data->expected_stderr = g_strdup (expected_stderr);
109 g_spawn_async_with_pipes (NULL, args, env,
110 G_SPAWN_DO_NOT_REAP_CHILD,
111 NULL, NULL, &pid, NULL,
113 expected_stderr ? &data->stderr_pipe : NULL,
115 g_assert_no_error (error);
119 g_child_watch_add (pid, child_quit, data);
120 outstanding_watches++;
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
126 fd.fd = data->stdout_pipe;
127 fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
136 g_assert (outstanding_watches == 0);
139 c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
141 main_loop = g_main_loop_new (NULL, 0);
143 /* spawn the master */
145 "open file:///a file:///b\n"
146 "exit status: 0\n", NULL,
149 /* send it some files */
150 spawn ("exit status: 0\n", NULL,
151 "./app", "/a", "/b", NULL);
153 g_main_loop_run (main_loop);
158 g_main_loop_unref (main_loop);
162 test_remote_command_line (void)
169 g_assert (outstanding_watches == 0);
172 c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
174 main_loop = g_main_loop_new (NULL, 0);
176 file = g_file_new_for_commandline_arg ("foo");
177 cwd = g_get_current_dir ();
179 replies = g_strconcat ("got ./cmd 0\n",
181 "cmdline ./cmd echo --abc -d\n",
182 "environment TEST=1\n",
184 "file ", g_file_get_path (file), "\n",
192 g_object_unref (file);
194 /* spawn the master */
195 spawn (replies, NULL,
200 /* send it a few commandlines */
201 spawn ("exit status: 0\n", NULL,
204 spawn ("exit status: 0\n", NULL,
205 "./cmd", "echo", "--abc", "-d", NULL);
207 spawn ("exit status: 0\n", NULL,
208 "./cmd", "env", NULL);
210 spawn ("exit status: 0\n", NULL,
211 "./cmd", "getenv", NULL);
213 spawn ("print test\n"
214 "exit status: 0\n", NULL,
215 "./cmd", "print", "test", NULL);
217 spawn ("exit status: 0\n", "printerr test\n",
218 "./cmd", "printerr", "test", NULL);
220 spawn ("exit status: 0\n", NULL,
221 "./cmd", "file", "foo", NULL);
223 spawn ("exit status: 0\n", NULL,
224 "./cmd", "properties", NULL);
226 spawn ("exit status: 0\n", NULL,
227 "./cmd", "cwd", NULL);
229 spawn ("exit status: 0\n", NULL,
230 "./cmd", "busy", NULL);
232 spawn ("exit status: 0\n", NULL,
233 "./cmd", "idle", NULL);
235 spawn ("exit status: 0\n", NULL,
236 "./cmd", "stdin", NULL);
238 g_main_loop_run (main_loop);
243 g_main_loop_unref (main_loop);
247 test_remote_actions (void)
251 g_assert (outstanding_watches == 0);
254 c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
256 main_loop = g_main_loop_new (NULL, 0);
258 /* spawn the master */
259 spawn ("got ./cmd 0\n"
262 "exit status: 0\n", NULL,
265 spawn ("actions quit new action1 action2\n"
266 "exit status: 0\n", NULL,
267 "./actions", "list", NULL);
269 spawn ("exit status: 0\n", NULL,
270 "./actions", "activate", NULL);
272 spawn ("exit status: 0\n", NULL,
273 "./actions", "set-state", NULL);
275 g_main_loop_run (main_loop);
280 g_main_loop_unref (main_loop);
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.
289 * See https://bugzilla.gnome.org/show_bug.cgi?id=647986 for the patch that
290 * introduced this problem.
293 static GApplication *recently_activated;
294 static GMainLoop *loop;
297 nonunique_activate (GApplication *application)
299 recently_activated = application;
302 g_main_loop_quit (loop);
305 static GApplication *
306 make_app (gboolean non_unique)
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);
317 g_object_unref (app);
321 g_application_activate (app);
327 test_nonunique (void)
329 GApplication *first, *second, *third, *fourth;
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;
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;
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;
351 fourth = make_app (FALSE);
352 /* should have failed to register due to being
353 * unable to register the object paths
355 g_assert (fourth == NULL);
356 g_assert (recently_activated == NULL);
358 g_object_unref (first);
359 g_object_unref (second);
360 g_object_unref (third);
372 GApplicationFlags flags;
377 GError *error = NULL;
380 c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
382 app = g_object_new (G_TYPE_APPLICATION,
383 "application-id", "org.gtk.TestApplication",
387 "application-id", &id,
389 "is-registered", ®istered,
390 "inactivity-timeout", &timeout,
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);
398 ret = g_application_register (G_APPLICATION (app), NULL, &error);
400 g_assert_no_error (error);
403 "is-registered", ®istered,
404 "is-remote", &remote,
407 g_assert (registered);
411 "inactivity-timeout", 1000,
414 g_application_quit (G_APPLICATION (app));
417 g_object_unref (app);
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);
444 g_assert (!g_application_id_is_valid (id));
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"));
454 static gboolean nodbus_activated;
457 release_app (gpointer user_data)
459 g_application_release (user_data);
460 return G_SOURCE_REMOVE;
464 nodbus_activate (GApplication *app)
466 nodbus_activated = TRUE;
467 g_application_hold (app);
469 g_assert (g_application_get_dbus_connection (app) == NULL);
470 g_assert (g_application_get_dbus_object_path (app) == NULL);
472 g_idle_add (release_app, app);
478 char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
479 gchar *argv[] = { binpath, NULL };
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);
487 g_assert (nodbus_activated);
491 static gboolean noappid_activated;
494 noappid_activate (GApplication *app)
496 noappid_activated = TRUE;
497 g_application_hold (app);
499 g_assert (g_application_get_flags (app) & G_APPLICATION_NON_UNIQUE);
501 g_idle_add (release_app, app);
504 /* test that no appid -> non-unique */
508 char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
509 gchar *argv[] = { binpath, NULL };
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);
517 g_assert (noappid_activated);
521 static gboolean activated;
522 static gboolean quitted;
525 quit_app (gpointer user_data)
528 g_application_quit (user_data);
529 return G_SOURCE_REMOVE;
533 quit_activate (GApplication *app)
536 g_application_hold (app);
538 g_assert (g_application_get_dbus_connection (app) != NULL);
539 g_assert (g_application_get_dbus_object_path (app) != NULL);
541 g_idle_add (quit_app, app);
548 char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
549 gchar *argv[] = { binpath, NULL };
553 c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
555 app = g_application_new ("org.gtk.Unimportant",
556 G_APPLICATION_FLAGS_NONE);
559 g_signal_connect (app, "activate", G_CALLBACK (quit_activate), NULL);
560 g_application_run (app, 1, argv);
561 g_object_unref (app);
564 g_assert (activated);
572 on_activate (GApplication *app)
578 g_assert (!g_application_get_is_remote (app));
580 actions = g_action_group_list_actions (G_ACTION_GROUP (app));
581 g_assert (g_strv_length (actions) == 0);
582 g_strfreev (actions);
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);
587 actions = g_action_group_list_actions (G_ACTION_GROUP (app));
588 g_assert (g_strv_length (actions) == 1);
589 g_strfreev (actions);
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);
595 action = g_action_map_lookup_action (G_ACTION_MAP (app), "test");
596 g_assert (action != NULL);
598 g_action_map_remove_action (G_ACTION_MAP (app), "test");
600 actions = g_action_group_list_actions (G_ACTION_GROUP (app));
601 g_assert (g_strv_length (actions) == 0);
602 g_strfreev (actions);
606 test_local_actions (void)
608 char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
609 gchar *argv[] = { binpath, NULL };
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);
620 typedef GApplication TestLocCmdApp;
621 typedef GApplicationClass TestLocCmdAppClass;
623 static GType test_loc_cmd_app_get_type (void);
624 G_DEFINE_TYPE (TestLocCmdApp, test_loc_cmd_app, G_TYPE_APPLICATION)
627 test_loc_cmd_app_init (TestLocCmdApp *app)
632 test_loc_cmd_app_startup (GApplication *app)
634 g_assert_not_reached ();
638 test_loc_cmd_app_shutdown (GApplication *app)
640 g_assert_not_reached ();
644 test_loc_cmd_app_local_command_line (GApplication *application,
652 test_loc_cmd_app_class_init (TestLocCmdAppClass *klass)
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;
660 test_local_command_line (void)
662 char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
663 gchar *argv[] = { binpath, "-invalid", NULL };
666 app = g_object_new (test_loc_cmd_app_get_type (),
667 "application-id", "org.gtk.Unimportant",
668 "flags", G_APPLICATION_FLAGS_NONE,
670 g_application_run (app, 1, argv);
671 g_object_unref (app);
676 test_resource_path (void)
680 app = g_application_new ("x.y.z", 0);
681 g_assert_cmpstr (g_application_get_resource_base_path (app), ==, "/x/y/z");
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");
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");
692 g_application_set_resource_base_path (app, NULL);
693 g_assert_cmpstr (g_application_get_resource_base_path (app), ==, NULL);
695 g_object_unref (app);
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);
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);
709 test_help_command_line (GApplication *app,
710 GApplicationCommandLine *command_line,
713 gboolean *called = user_data;
720 /* Test whether --help is handled when HANDLES_COMMND_LINE is set and
721 * options have been added.
726 if (g_test_subprocess ())
728 char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL);
729 gchar *argv[] = { binpath, "--help", NULL };
731 gboolean called = FALSE;
734 app = g_application_new ("org.gtk.TestApplication", G_APPLICATION_HANDLES_COMMAND_LINE);
735 g_application_add_main_option (app, "foo", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, "", "");
736 g_signal_connect (app, "command-line", G_CALLBACK (test_help_command_line), &called);
738 status = g_application_run (app, G_N_ELEMENTS (argv) -1, argv);
739 g_assert (called == TRUE);
740 g_assert_cmpint (status, ==, 0);
742 g_object_unref (app);
747 g_test_trap_subprocess (NULL, 0, 0);
748 g_test_trap_assert_passed ();
749 g_test_trap_assert_stdout ("*Application options*");
753 main (int argc, char **argv)
755 g_test_init (&argc, &argv, NULL);
757 g_test_dbus_unset ();
759 g_test_add_func ("/gapplication/no-dbus", test_nodbus);
760 /* g_test_add_func ("/gapplication/basic", basic); */
761 g_test_add_func ("/gapplication/no-appid", test_noappid);
762 /* g_test_add_func ("/gapplication/non-unique", test_nonunique); */
763 g_test_add_func ("/gapplication/properties", properties);
764 g_test_add_func ("/gapplication/app-id", appid);
765 g_test_add_func ("/gapplication/quit", test_quit);
766 g_test_add_func ("/gapplication/local-actions", test_local_actions);
767 /* g_test_add_func ("/gapplication/remote-actions", test_remote_actions); */
768 g_test_add_func ("/gapplication/local-command-line", test_local_command_line);
769 /* g_test_add_func ("/gapplication/remote-command-line", test_remote_command_line); */
770 g_test_add_func ("/gapplication/resource-path", test_resource_path);
771 g_test_add_func ("/gapplication/test-help", test_help);
773 return g_test_run ();