2 * Copyright © 2013 Canonical Limited
4 * SPDX-License-Identifier: LGPL-2.1-or-later
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Authors: Ryan Lortie <desrt@desrt.ca>
23 #include <gio/gdesktopappinfo.h>
25 #include "gdbus-sessionbus.h"
27 static GDesktopAppInfo *appinfo;
28 static int current_state;
29 static gboolean saw_startup_id;
30 static gboolean requested_startup_id;
33 static GType test_app_launch_context_get_type (void);
34 typedef GAppLaunchContext TestAppLaunchContext;
35 typedef GAppLaunchContextClass TestAppLaunchContextClass;
36 G_DEFINE_TYPE (TestAppLaunchContext, test_app_launch_context, G_TYPE_APP_LAUNCH_CONTEXT)
39 test_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
43 requested_startup_id = TRUE;
44 return g_strdup ("expected startup id");
48 test_app_launch_context_init (TestAppLaunchContext *ctx)
53 test_app_launch_context_class_init (GAppLaunchContextClass *class)
55 class->get_startup_notify_id = test_app_launch_context_get_startup_notify_id;
58 static GType test_application_get_type (void);
59 typedef GApplication TestApplication;
60 typedef GApplicationClass TestApplicationClass;
61 G_DEFINE_TYPE (TestApplication, test_application, G_TYPE_APPLICATION)
64 saw_action (const gchar *action)
66 /* This is the main driver of the test. It's a bit of a state
69 * Each time some event arrives on the app, it calls here to report
70 * which event it was. The initial activation of the app is what
71 * starts everything in motion (starting from state 0). At each
72 * state, we assert that we receive the expected event, send the next
73 * event, then update the current_state variable so we do the correct
77 switch (current_state)
79 case 0: g_assert_cmpstr (action, ==, "activate");
81 /* Let's try another activation... */
82 g_app_info_launch (G_APP_INFO (appinfo), NULL, NULL, NULL);
83 current_state = 1; return; case 1: g_assert_cmpstr (action, ==, "activate");
86 /* Now let's try opening some files... */
90 files = g_list_prepend (NULL, g_file_new_for_uri ("file:///a/b"));
91 files = g_list_append (files, g_file_new_for_uri ("file:///c/d"));
92 g_app_info_launch (G_APP_INFO (appinfo), files, NULL, NULL);
93 g_list_free_full (files, g_object_unref);
95 current_state = 2; return; case 2: g_assert_cmpstr (action, ==, "open");
97 /* Now action activations... */
98 g_desktop_app_info_launch_action (appinfo, "frob", NULL);
99 current_state = 3; return; case 3: g_assert_cmpstr (action, ==, "frob");
101 g_desktop_app_info_launch_action (appinfo, "tweak", NULL);
102 current_state = 4; return; case 4: g_assert_cmpstr (action, ==, "tweak");
104 g_desktop_app_info_launch_action (appinfo, "twiddle", NULL);
105 current_state = 5; return; case 5: g_assert_cmpstr (action, ==, "twiddle");
107 /* Now launch the app with startup notification */
109 GAppLaunchContext *ctx;
111 g_assert (saw_startup_id == FALSE);
112 ctx = g_object_new (test_app_launch_context_get_type (), NULL);
113 g_app_info_launch (G_APP_INFO (appinfo), NULL, ctx, NULL);
114 g_assert (requested_startup_id);
115 requested_startup_id = FALSE;
116 g_object_unref (ctx);
118 current_state = 6; return; case 6: g_assert_cmpstr (action, ==, "activate"); g_assert (saw_startup_id);
119 saw_startup_id = FALSE;
121 /* Now do the same for an action */
123 GAppLaunchContext *ctx;
125 g_assert (saw_startup_id == FALSE);
126 ctx = g_object_new (test_app_launch_context_get_type (), NULL);
127 g_desktop_app_info_launch_action (appinfo, "frob", ctx);
128 g_assert (requested_startup_id);
129 requested_startup_id = FALSE;
130 g_object_unref (ctx);
132 current_state = 7; return; case 7: g_assert_cmpstr (action, ==, "frob"); g_assert (saw_startup_id);
133 saw_startup_id = FALSE;
136 g_desktop_app_info_launch_action (appinfo, "quit", NULL);
137 current_state = 8; return; case 8: g_assert_not_reached ();
142 test_application_frob (GSimpleAction *action,
146 g_assert (parameter == NULL);
151 test_application_tweak (GSimpleAction *action,
155 g_assert (parameter == NULL);
156 saw_action ("tweak");
160 test_application_twiddle (GSimpleAction *action,
164 g_assert (parameter == NULL);
165 saw_action ("twiddle");
169 test_application_quit (GSimpleAction *action,
173 GApplication *application = user_data;
175 g_application_quit (application);
178 static const GActionEntry app_actions[] = {
179 { "frob", test_application_frob, NULL, NULL, NULL, { 0 } },
180 { "tweak", test_application_tweak, NULL, NULL, NULL, { 0 } },
181 { "twiddle", test_application_twiddle, NULL, NULL, NULL, { 0 } },
182 { "quit", test_application_quit, NULL, NULL, NULL, { 0 } }
186 test_application_activate (GApplication *application)
188 /* Unbalanced, but that's OK because we will quit() */
189 g_application_hold (application);
191 saw_action ("activate");
195 test_application_open (GApplication *application,
202 g_assert_cmpstr (hint, ==, "");
204 g_assert_cmpint (n_files, ==, 2);
205 f = g_file_new_for_uri ("file:///a/b");
206 g_assert (g_file_equal (files[0], f));
208 f = g_file_new_for_uri ("file:///c/d");
209 g_assert (g_file_equal (files[1], f));
216 test_application_startup (GApplication *application)
218 G_APPLICATION_CLASS (test_application_parent_class)
219 ->startup (application);
221 g_action_map_add_action_entries (G_ACTION_MAP (application), app_actions, G_N_ELEMENTS (app_actions), application);
225 test_application_before_emit (GApplication *application,
226 GVariant *platform_data)
228 const gchar *startup_id;
231 g_assert (!saw_startup_id);
233 const gchar *startup_id_keys[] = {
234 "desktop-startup-id",
239 for (i = 0; startup_id_keys[i] != NULL; i++)
241 if (!g_variant_lookup (platform_data, startup_id_keys[i], "&s", &startup_id))
244 g_assert_cmpstr (startup_id, ==, "expected startup id");
247 saw_startup_id = TRUE;
251 test_application_init (TestApplication *app)
256 test_application_class_init (GApplicationClass *class)
258 class->before_emit = test_application_before_emit;
259 class->startup = test_application_startup;
260 class->activate = test_application_activate;
261 class->open = test_application_open;
265 test_dbus_appinfo (void)
267 const gchar *argv[] = { "myapp", NULL };
268 TestApplication *app;
270 gchar *desktop_file = NULL;
272 desktop_file = g_test_build_filename (G_TEST_DIST,
273 "org.gtk.test.dbusappinfo.desktop",
275 appinfo = g_desktop_app_info_new_from_filename (desktop_file);
276 g_assert (appinfo != NULL);
277 g_free (desktop_file);
279 app = g_object_new (test_application_get_type (),
280 "application-id", "org.gtk.test.dbusappinfo",
281 "flags", G_APPLICATION_HANDLES_OPEN,
283 status = g_application_run (app, 1, (gchar **) argv);
285 g_assert_cmpint (status, ==, 0);
286 g_assert_cmpint (current_state, ==, 8);
288 g_object_unref (appinfo);
289 g_object_unref (app);
293 on_flatpak_launch_uris_finish (GObject *object,
294 GAsyncResult *result,
297 GApplication *app = user_data;
298 GError *error = NULL;
300 g_app_info_launch_uris_finish (G_APP_INFO (object), result, &error);
301 g_assert_no_error (error);
303 g_application_release (app);
307 on_flatpak_activate (GApplication *app,
310 GDesktopAppInfo *flatpak_appinfo = user_data;
314 /* The app will be released in on_flatpak_launch_uris_finish */
315 g_application_hold (app);
317 uri = g_filename_to_uri (g_desktop_app_info_get_filename (flatpak_appinfo), NULL, NULL);
318 g_assert_nonnull (uri);
319 uris = g_list_prepend (NULL, uri);
320 g_app_info_launch_uris_async (G_APP_INFO (flatpak_appinfo), uris, NULL,
321 NULL, on_flatpak_launch_uris_finish, app);
327 on_flatpak_open (GApplication *app,
334 g_assert_cmpint (n_files, ==, 1);
335 g_test_message ("on_flatpak_open received file '%s'", g_file_peek_path (files[0]));
337 /* The file has been exported via the document portal */
338 f = g_file_new_for_uri ("file:///document-portal/document-id/org.gtk.test.dbusappinfo.flatpak.desktop");
339 g_assert_true (g_file_equal (files[0], f));
344 test_flatpak_doc_export (void)
346 const gchar *argv[] = { "myapp", NULL };
347 gchar *desktop_file = NULL;
348 GDesktopAppInfo *flatpak_appinfo;
352 g_test_summary ("Test that files launched via Flatpak apps are made available via the document portal.");
354 desktop_file = g_test_build_filename (G_TEST_DIST,
355 "org.gtk.test.dbusappinfo.flatpak.desktop",
357 flatpak_appinfo = g_desktop_app_info_new_from_filename (desktop_file);
358 g_assert_nonnull (flatpak_appinfo);
359 g_free (desktop_file);
361 app = g_application_new ("org.gtk.test.dbusappinfo.flatpak",
362 G_APPLICATION_HANDLES_OPEN);
363 g_signal_connect (app, "activate", G_CALLBACK (on_flatpak_activate),
365 g_signal_connect (app, "open", G_CALLBACK (on_flatpak_open), NULL);
367 status = g_application_run (app, 1, (gchar **) argv);
368 g_assert_cmpint (status, ==, 0);
370 g_object_unref (app);
371 g_object_unref (flatpak_appinfo);
375 on_flatpak_launch_invalid_uri_finish (GObject *object,
376 GAsyncResult *result,
379 GApplication *app = user_data;
380 GError *error = NULL;
382 g_app_info_launch_uris_finish (G_APP_INFO (object), result, &error);
383 g_assert_no_error (error);
385 g_application_release (app);
389 on_flatpak_activate_invalid_uri (GApplication *app,
392 GDesktopAppInfo *flatpak_appinfo = user_data;
395 /* The app will be released in on_flatpak_launch_uris_finish */
396 g_application_hold (app);
398 uris = g_list_prepend (NULL, "file:///hopefully/an/invalid/path.desktop");
399 g_app_info_launch_uris_async (G_APP_INFO (flatpak_appinfo), uris, NULL,
400 NULL, on_flatpak_launch_invalid_uri_finish, app);
405 on_flatpak_open_invalid_uri (GApplication *app,
412 g_assert_cmpint (n_files, ==, 1);
413 g_test_message ("on_flatpak_open received file '%s'", g_file_peek_path (files[0]));
415 /* The file has been exported via the document portal */
416 f = g_file_new_for_uri ("file:///hopefully/an/invalid/path.desktop");
417 g_assert_true (g_file_equal (files[0], f));
422 test_flatpak_missing_doc_export (void)
424 const gchar *argv[] = { "myapp", NULL };
425 gchar *desktop_file = NULL;
426 GDesktopAppInfo *flatpak_appinfo;
430 g_test_summary ("Test that files launched via Flatpak apps are made available via the document portal.");
432 desktop_file = g_test_build_filename (G_TEST_DIST,
433 "org.gtk.test.dbusappinfo.flatpak.desktop",
435 flatpak_appinfo = g_desktop_app_info_new_from_filename (desktop_file);
436 g_assert_nonnull (flatpak_appinfo);
438 app = g_application_new ("org.gtk.test.dbusappinfo.flatpak",
439 G_APPLICATION_HANDLES_OPEN);
440 g_signal_connect (app, "activate", G_CALLBACK (on_flatpak_activate_invalid_uri),
442 g_signal_connect (app, "open", G_CALLBACK (on_flatpak_open_invalid_uri), NULL);
444 status = g_application_run (app, 1, (gchar **) argv);
445 g_assert_cmpint (status, ==, 0);
447 g_object_unref (app);
448 g_object_unref (flatpak_appinfo);
449 g_free (desktop_file);
453 main (int argc, char **argv)
455 g_test_init (&argc, &argv, NULL);
457 g_test_add_func ("/appinfo/dbusappinfo", test_dbus_appinfo);
458 g_test_add_func ("/appinfo/flatpak-doc-export", test_flatpak_doc_export);
459 g_test_add_func ("/appinfo/flatpak-missing-doc-export", test_flatpak_missing_doc_export);
461 return session_bus_run ();