Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2013 Canonical Limited
3 : : * Copyright © 2024 GNOME Foundation Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Authors: Ryan Lortie <desrt@desrt.ca>
21 : : * Julian Sparber <jsparber@gnome.org>
22 : : */
23 : :
24 : : #include <gio/gio.h>
25 : : #include <gio/gdesktopappinfo.h>
26 : :
27 : : #include "gdbus-sessionbus.h"
28 : : #include "fake-desktop-portal.h"
29 : : #include "fake-document-portal.h"
30 : :
31 : : static GDesktopAppInfo *appinfo;
32 : : static int current_state;
33 : : static gboolean saw_startup_id;
34 : : static gboolean requested_startup_id;
35 : :
36 : :
37 : : static GType test_app_launch_context_get_type (void);
38 : : typedef GAppLaunchContext TestAppLaunchContext;
39 : : typedef GAppLaunchContextClass TestAppLaunchContextClass;
40 : 10 : G_DEFINE_TYPE (TestAppLaunchContext, test_app_launch_context, G_TYPE_APP_LAUNCH_CONTEXT)
41 : :
42 : : static gchar *
43 : 8 : test_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
44 : : GAppInfo *info,
45 : : GList *uris)
46 : : {
47 : 8 : requested_startup_id = TRUE;
48 : 8 : return g_strdup ("expected startup id");
49 : : }
50 : :
51 : : static void
52 : 8 : test_app_launch_context_init (TestAppLaunchContext *ctx)
53 : : {
54 : 8 : }
55 : :
56 : : static void
57 : 1 : test_app_launch_context_class_init (GAppLaunchContextClass *class)
58 : : {
59 : 1 : class->get_startup_notify_id = test_app_launch_context_get_startup_notify_id;
60 : 1 : }
61 : :
62 : : static GType test_application_get_type (void);
63 : : typedef GApplication TestApplication;
64 : : typedef GApplicationClass TestApplicationClass;
65 : 3 : G_DEFINE_TYPE (TestApplication, test_application, G_TYPE_APPLICATION)
66 : :
67 : : static void
68 : 8 : saw_action (const gchar *action)
69 : : {
70 : : /* This is the main driver of the test. It's a bit of a state
71 : : * machine.
72 : : *
73 : : * Each time some event arrives on the app, it calls here to report
74 : : * which event it was. The initial activation of the app is what
75 : : * starts everything in motion (starting from state 0). At each
76 : : * state, we assert that we receive the expected event, send the next
77 : : * event, then update the current_state variable so we do the correct
78 : : * thing next time.
79 : : */
80 : :
81 : 8 : switch (current_state)
82 : : {
83 : 1 : case 0: g_assert_cmpstr (action, ==, "activate");
84 : :
85 : : /* Let's try another activation... */
86 : 1 : g_app_info_launch (G_APP_INFO (appinfo), NULL, NULL, NULL);
87 : 2 : current_state = 1; return; case 1: g_assert_cmpstr (action, ==, "activate");
88 : :
89 : :
90 : : /* Now let's try opening some files... */
91 : : {
92 : : GList *files;
93 : :
94 : 1 : files = g_list_prepend (NULL, g_file_new_for_uri ("file:///a/b"));
95 : 1 : files = g_list_append (files, g_file_new_for_uri ("file:///c/d"));
96 : 1 : g_app_info_launch (G_APP_INFO (appinfo), files, NULL, NULL);
97 : 1 : g_list_free_full (files, g_object_unref);
98 : : }
99 : 2 : current_state = 2; return; case 2: g_assert_cmpstr (action, ==, "open");
100 : :
101 : : /* Now action activations... */
102 : 1 : g_desktop_app_info_launch_action (appinfo, "frob", NULL);
103 : 2 : current_state = 3; return; case 3: g_assert_cmpstr (action, ==, "frob");
104 : :
105 : 1 : g_desktop_app_info_launch_action (appinfo, "tweak", NULL);
106 : 2 : current_state = 4; return; case 4: g_assert_cmpstr (action, ==, "tweak");
107 : :
108 : 1 : g_desktop_app_info_launch_action (appinfo, "twiddle", NULL);
109 : 2 : current_state = 5; return; case 5: g_assert_cmpstr (action, ==, "twiddle");
110 : :
111 : : /* Now launch the app with startup notification */
112 : : {
113 : : GAppLaunchContext *ctx;
114 : :
115 : 1 : g_assert (saw_startup_id == FALSE);
116 : 1 : ctx = g_object_new (test_app_launch_context_get_type (), NULL);
117 : 1 : g_app_info_launch (G_APP_INFO (appinfo), NULL, ctx, NULL);
118 : 1 : g_assert (requested_startup_id);
119 : 1 : requested_startup_id = FALSE;
120 : 1 : g_object_unref (ctx);
121 : : }
122 : 2 : current_state = 6; return; case 6: g_assert_cmpstr (action, ==, "activate"); g_assert (saw_startup_id);
123 : 1 : saw_startup_id = FALSE;
124 : :
125 : : /* Now do the same for an action */
126 : : {
127 : : GAppLaunchContext *ctx;
128 : :
129 : 1 : g_assert (saw_startup_id == FALSE);
130 : 1 : ctx = g_object_new (test_app_launch_context_get_type (), NULL);
131 : 1 : g_desktop_app_info_launch_action (appinfo, "frob", ctx);
132 : 1 : g_assert (requested_startup_id);
133 : 1 : requested_startup_id = FALSE;
134 : 1 : g_object_unref (ctx);
135 : : }
136 : 2 : current_state = 7; return; case 7: g_assert_cmpstr (action, ==, "frob"); g_assert (saw_startup_id);
137 : 1 : saw_startup_id = FALSE;
138 : :
139 : : /* Now quit... */
140 : 1 : g_desktop_app_info_launch_action (appinfo, "quit", NULL);
141 : : current_state = 8; return; case 8: g_assert_not_reached ();
142 : : }
143 : : }
144 : :
145 : : static void
146 : 2 : test_application_frob (GSimpleAction *action,
147 : : GVariant *parameter,
148 : : gpointer user_data)
149 : : {
150 : 2 : g_assert (parameter == NULL);
151 : 2 : saw_action ("frob");
152 : 2 : }
153 : :
154 : : static void
155 : 1 : test_application_tweak (GSimpleAction *action,
156 : : GVariant *parameter,
157 : : gpointer user_data)
158 : : {
159 : 1 : g_assert (parameter == NULL);
160 : 1 : saw_action ("tweak");
161 : 1 : }
162 : :
163 : : static void
164 : 1 : test_application_twiddle (GSimpleAction *action,
165 : : GVariant *parameter,
166 : : gpointer user_data)
167 : : {
168 : 1 : g_assert (parameter == NULL);
169 : 1 : saw_action ("twiddle");
170 : 1 : }
171 : :
172 : : static void
173 : 1 : test_application_quit (GSimpleAction *action,
174 : : GVariant *parameter,
175 : : gpointer user_data)
176 : : {
177 : 1 : GApplication *application = user_data;
178 : :
179 : 1 : g_application_quit (application);
180 : 1 : }
181 : :
182 : : static const GActionEntry app_actions[] = {
183 : : { "frob", test_application_frob, NULL, NULL, NULL, { 0 } },
184 : : { "tweak", test_application_tweak, NULL, NULL, NULL, { 0 } },
185 : : { "twiddle", test_application_twiddle, NULL, NULL, NULL, { 0 } },
186 : : { "quit", test_application_quit, NULL, NULL, NULL, { 0 } }
187 : : };
188 : :
189 : : static void
190 : 3 : test_application_activate (GApplication *application)
191 : : {
192 : : /* Unbalanced, but that's OK because we will quit() */
193 : 3 : g_application_hold (application);
194 : :
195 : 3 : saw_action ("activate");
196 : 3 : }
197 : :
198 : : static void
199 : 1 : test_application_open (GApplication *application,
200 : : GFile **files,
201 : : gint n_files,
202 : : const gchar *hint)
203 : : {
204 : : GFile *f;
205 : :
206 : 1 : g_assert_cmpstr (hint, ==, "");
207 : :
208 : 1 : g_assert_cmpint (n_files, ==, 2);
209 : 1 : f = g_file_new_for_uri ("file:///a/b");
210 : 1 : g_assert (g_file_equal (files[0], f));
211 : 1 : g_object_unref (f);
212 : 1 : f = g_file_new_for_uri ("file:///c/d");
213 : 1 : g_assert (g_file_equal (files[1], f));
214 : 1 : g_object_unref (f);
215 : :
216 : 1 : saw_action ("open");
217 : 1 : }
218 : :
219 : : static void
220 : 1 : test_application_startup (GApplication *application)
221 : : {
222 : 1 : G_APPLICATION_CLASS (test_application_parent_class)
223 : 1 : ->startup (application);
224 : :
225 : 1 : g_action_map_add_action_entries (G_ACTION_MAP (application), app_actions, G_N_ELEMENTS (app_actions), application);
226 : 1 : }
227 : :
228 : : static void
229 : 10 : test_application_before_emit (GApplication *application,
230 : : GVariant *platform_data)
231 : : {
232 : : const gchar *startup_id;
233 : : gsize i;
234 : :
235 : 10 : g_assert (!saw_startup_id);
236 : :
237 : 10 : const gchar *startup_id_keys[] = {
238 : : "desktop-startup-id",
239 : : "activation-token",
240 : : NULL,
241 : : };
242 : :
243 : 18 : for (i = 0; startup_id_keys[i] != NULL; i++)
244 : : {
245 : 14 : if (!g_variant_lookup (platform_data, startup_id_keys[i], "&s", &startup_id))
246 : 6 : return;
247 : :
248 : 8 : g_assert_cmpstr (startup_id, ==, "expected startup id");
249 : : }
250 : :
251 : 4 : saw_startup_id = TRUE;
252 : : }
253 : :
254 : : static void
255 : 1 : test_application_init (TestApplication *app)
256 : : {
257 : 1 : }
258 : :
259 : : static void
260 : 1 : test_application_class_init (GApplicationClass *class)
261 : : {
262 : 1 : class->before_emit = test_application_before_emit;
263 : 1 : class->startup = test_application_startup;
264 : 1 : class->activate = test_application_activate;
265 : 1 : class->open = test_application_open;
266 : 1 : }
267 : :
268 : : static void
269 : 1 : test_dbus_appinfo (void)
270 : : {
271 : 1 : const gchar *argv[] = { "myapp", NULL };
272 : : TestApplication *app;
273 : : int status;
274 : 1 : gchar *desktop_file = NULL;
275 : :
276 : 1 : desktop_file = g_test_build_filename (G_TEST_DIST,
277 : : "org.gtk.test.dbusappinfo.desktop",
278 : : NULL);
279 : 1 : appinfo = g_desktop_app_info_new_from_filename (desktop_file);
280 : 1 : g_assert (appinfo != NULL);
281 : 1 : g_free (desktop_file);
282 : :
283 : 1 : app = g_object_new (test_application_get_type (),
284 : : "application-id", "org.gtk.test.dbusappinfo",
285 : : "flags", G_APPLICATION_HANDLES_OPEN,
286 : : NULL);
287 : 1 : status = g_application_run (app, 1, (gchar **) argv);
288 : :
289 : 1 : g_assert_cmpint (status, ==, 0);
290 : 1 : g_assert_cmpint (current_state, ==, 8);
291 : :
292 : 1 : g_object_unref (appinfo);
293 : 1 : g_object_unref (app);
294 : 1 : }
295 : :
296 : : static GType test_flatpak_application_get_type (void);
297 : : typedef GApplication TestFlatpakApplication;
298 : : typedef GApplicationClass TestFlatpakApplicationClass;
299 : 4 : G_DEFINE_TYPE (TestFlatpakApplication, test_flatpak_application, G_TYPE_APPLICATION)
300 : :
301 : : static void
302 : 1 : on_flatpak_launch_uris_finish (GObject *object,
303 : : GAsyncResult *result,
304 : : gpointer user_data)
305 : : {
306 : 1 : GApplication *app = user_data;
307 : 1 : GError *error = NULL;
308 : :
309 : 1 : g_app_info_launch_uris_finish (G_APP_INFO (object), result, &error);
310 : 1 : g_assert_no_error (error);
311 : 1 : g_assert_true (requested_startup_id);
312 : 1 : g_assert_true (saw_startup_id);
313 : :
314 : 1 : g_application_release (app);
315 : 1 : }
316 : :
317 : : static void
318 : 1 : on_flatpak_activate (GApplication *app,
319 : : gpointer user_data)
320 : : {
321 : : GAppLaunchContext *ctx;
322 : 1 : GDesktopAppInfo *flatpak_appinfo = user_data;
323 : : char *uri;
324 : : GList *uris;
325 : :
326 : : /* The app will be released in on_flatpak_launch_uris_finish */
327 : 1 : g_application_hold (app);
328 : :
329 : 1 : uri = g_filename_to_uri (g_desktop_app_info_get_filename (flatpak_appinfo), NULL, NULL);
330 : 1 : g_assert_nonnull (uri);
331 : 1 : uris = g_list_prepend (NULL, uri);
332 : 1 : ctx = g_object_new (test_app_launch_context_get_type (), NULL);
333 : 1 : requested_startup_id = FALSE;
334 : 1 : saw_startup_id = FALSE;
335 : 1 : g_app_info_launch_uris_async (G_APP_INFO (flatpak_appinfo), uris, ctx,
336 : : NULL, on_flatpak_launch_uris_finish, app);
337 : 1 : g_object_unref (ctx);
338 : 1 : g_list_free (uris);
339 : 1 : g_free (uri);
340 : 1 : }
341 : :
342 : : static void
343 : 1 : on_flatpak_open (GApplication *app,
344 : : GFile **files,
345 : : gint n_files,
346 : : const char *hint)
347 : : {
348 : : GFile *f;
349 : :
350 : 1 : g_assert_cmpint (n_files, ==, 1);
351 : 1 : g_test_message ("on_flatpak_open received file '%s'", g_file_peek_path (files[0]));
352 : :
353 : : /* The file has been exported via the document portal */
354 : 1 : f = g_file_new_for_uri ("file:///document-portal/document-id/org.gtk.test.dbusappinfo.flatpak.desktop");
355 : 1 : g_assert_true (g_file_equal (files[0], f));
356 : 1 : g_object_unref (f);
357 : 1 : }
358 : :
359 : : static void
360 : 2 : test_flatpak_application_init (TestApplication *app)
361 : : {
362 : 2 : }
363 : :
364 : : static void
365 : 1 : test_flatpak_application_class_init (GApplicationClass *class)
366 : : {
367 : 1 : class->before_emit = test_application_before_emit;
368 : 1 : }
369 : :
370 : : static void
371 : 1 : test_flatpak_doc_export (void)
372 : : {
373 : 1 : const gchar *argv[] = { "myapp", NULL };
374 : 1 : gchar *desktop_file = NULL;
375 : : GDesktopAppInfo *flatpak_appinfo;
376 : : GApplication *app;
377 : : int status;
378 : 1 : GFakeDocumentPortalThread *thread = NULL;
379 : :
380 : 1 : g_test_summary ("Test that files launched via Flatpak apps are made available via the document portal.");
381 : :
382 : : /* Run a fake-document-portal */
383 : 1 : thread = g_fake_document_portal_thread_new (session_bus_get_address ());
384 : 1 : g_fake_document_portal_thread_run (thread);
385 : :
386 : 1 : desktop_file = g_test_build_filename (G_TEST_DIST,
387 : : "org.gtk.test.dbusappinfo.flatpak.desktop",
388 : : NULL);
389 : 1 : flatpak_appinfo = g_desktop_app_info_new_from_filename (desktop_file);
390 : 1 : g_assert_nonnull (flatpak_appinfo);
391 : 1 : g_free (desktop_file);
392 : :
393 : 1 : app = g_object_new (test_flatpak_application_get_type (),
394 : : "application-id", "org.gtk.test.dbusappinfo.flatpak",
395 : : "flags", G_APPLICATION_HANDLES_OPEN,
396 : : NULL);
397 : 1 : g_signal_connect (app, "activate", G_CALLBACK (on_flatpak_activate),
398 : : flatpak_appinfo);
399 : 1 : g_signal_connect (app, "open", G_CALLBACK (on_flatpak_open), NULL);
400 : :
401 : 1 : status = g_application_run (app, 1, (gchar **) argv);
402 : 1 : g_assert_cmpint (status, ==, 0);
403 : :
404 : 1 : g_object_unref (app);
405 : 1 : g_object_unref (flatpak_appinfo);
406 : 1 : g_fake_document_portal_thread_stop (thread);
407 : 1 : g_clear_object (&thread);
408 : 1 : }
409 : :
410 : : static void
411 : 1 : on_flatpak_launch_invalid_uri_finish (GObject *object,
412 : : GAsyncResult *result,
413 : : gpointer user_data)
414 : : {
415 : 1 : GApplication *app = user_data;
416 : 1 : GError *error = NULL;
417 : :
418 : 1 : g_app_info_launch_uris_finish (G_APP_INFO (object), result, &error);
419 : 1 : g_assert_no_error (error);
420 : 1 : g_assert_true (requested_startup_id);
421 : 1 : g_assert_true (saw_startup_id);
422 : :
423 : 1 : g_application_release (app);
424 : 1 : }
425 : :
426 : : static void
427 : 1 : on_flatpak_activate_invalid_uri (GApplication *app,
428 : : gpointer user_data)
429 : : {
430 : : GAppLaunchContext *ctx;
431 : 1 : GDesktopAppInfo *flatpak_appinfo = user_data;
432 : : GList *uris;
433 : :
434 : : /* The app will be released in on_flatpak_launch_uris_finish */
435 : 1 : g_application_hold (app);
436 : :
437 : 1 : uris = g_list_prepend (NULL, "file:///hopefully/an/invalid/path.desktop");
438 : 1 : ctx = g_object_new (test_app_launch_context_get_type (), NULL);
439 : 1 : requested_startup_id = FALSE;
440 : 1 : saw_startup_id = FALSE;
441 : 1 : g_app_info_launch_uris_async (G_APP_INFO (flatpak_appinfo), uris, ctx,
442 : : NULL, on_flatpak_launch_invalid_uri_finish, app);
443 : 1 : g_object_unref (ctx);
444 : 1 : g_list_free (uris);
445 : 1 : }
446 : :
447 : : static void
448 : 1 : on_flatpak_open_invalid_uri (GApplication *app,
449 : : GFile **files,
450 : : gint n_files,
451 : : const char *hint)
452 : : {
453 : : GFile *f;
454 : :
455 : 1 : g_assert_cmpint (n_files, ==, 1);
456 : 1 : g_test_message ("on_flatpak_open received file '%s'", g_file_peek_path (files[0]));
457 : :
458 : : /* The file has been exported via the document portal */
459 : 1 : f = g_file_new_for_uri ("file:///hopefully/an/invalid/path.desktop");
460 : 1 : g_assert_true (g_file_equal (files[0], f));
461 : 1 : g_object_unref (f);
462 : 1 : }
463 : :
464 : : static void
465 : 1 : test_flatpak_missing_doc_export (void)
466 : : {
467 : 1 : const gchar *argv[] = { "myapp", NULL };
468 : 1 : gchar *desktop_file = NULL;
469 : : GDesktopAppInfo *flatpak_appinfo;
470 : : GApplication *app;
471 : : int status;
472 : 1 : GFakeDocumentPortalThread *thread = NULL;
473 : :
474 : 1 : g_test_summary ("Test that files launched via Flatpak apps are made available via the document portal.");
475 : :
476 : : /* Run a fake-document-portal */
477 : 1 : thread = g_fake_document_portal_thread_new (session_bus_get_address ());
478 : 1 : g_fake_document_portal_thread_run (thread);
479 : :
480 : 1 : desktop_file = g_test_build_filename (G_TEST_DIST,
481 : : "org.gtk.test.dbusappinfo.flatpak.desktop",
482 : : NULL);
483 : 1 : flatpak_appinfo = g_desktop_app_info_new_from_filename (desktop_file);
484 : 1 : g_assert_nonnull (flatpak_appinfo);
485 : :
486 : 1 : app = g_object_new (test_flatpak_application_get_type (),
487 : : "application-id", "org.gtk.test.dbusappinfo.flatpak",
488 : : "flags", G_APPLICATION_HANDLES_OPEN,
489 : : NULL);
490 : 1 : g_signal_connect (app, "activate", G_CALLBACK (on_flatpak_activate_invalid_uri),
491 : : flatpak_appinfo);
492 : 1 : g_signal_connect (app, "open", G_CALLBACK (on_flatpak_open_invalid_uri), NULL);
493 : :
494 : 1 : status = g_application_run (app, 1, (gchar **) argv);
495 : 1 : g_assert_cmpint (status, ==, 0);
496 : :
497 : 1 : g_object_unref (app);
498 : 1 : g_object_unref (flatpak_appinfo);
499 : 1 : g_free (desktop_file);
500 : 1 : g_fake_document_portal_thread_stop (thread);
501 : 1 : g_clear_object (&thread);
502 : 1 : }
503 : :
504 : : static void
505 : 4 : check_portal_openuri_call (const char *expected_uri,
506 : : GFakeDesktopPortalThread *thread)
507 : : {
508 : 4 : const char *activation_token = NULL;
509 : 4 : GFile *expected_file = NULL;
510 : 4 : GFile *file = NULL;
511 : 4 : const char *uri = NULL;
512 : :
513 : 4 : activation_token = g_fake_desktop_portal_thread_get_last_request_activation_token (thread);
514 : 4 : uri = g_fake_desktop_portal_thread_get_last_request_uri (thread);
515 : :
516 : 4 : g_assert_cmpstr (activation_token, ==, "expected startup id");
517 : 4 : g_assert_nonnull (uri);
518 : :
519 : 4 : expected_file = g_file_new_for_uri (expected_uri);
520 : 4 : file = g_file_new_for_uri (uri);
521 : 4 : g_assert_true (g_file_equal (expected_file, file));
522 : :
523 : 4 : g_object_unref (file);
524 : 4 : g_object_unref (expected_file);
525 : 4 : }
526 : :
527 : : static void
528 : 1 : test_portal_open_file (void)
529 : : {
530 : : GAppLaunchContext *ctx;
531 : 1 : GError *error = NULL;
532 : : char *uri;
533 : 1 : GFakeDesktopPortalThread *thread = NULL;
534 : :
535 : : /* Run a fake-desktop-portal */
536 : 1 : thread = g_fake_desktop_portal_thread_new (session_bus_get_address ());
537 : 1 : g_fake_desktop_portal_thread_run (thread);
538 : :
539 : 1 : uri = g_filename_to_uri (g_test_get_filename (G_TEST_DIST,
540 : : "org.gtk.test.dbusappinfo.flatpak.desktop",
541 : : NULL),
542 : : NULL,
543 : : NULL);
544 : :
545 : 1 : ctx = g_object_new (test_app_launch_context_get_type (), NULL);
546 : :
547 : 1 : requested_startup_id = FALSE;
548 : :
549 : 1 : g_app_info_launch_default_for_uri (uri, ctx, &error);
550 : :
551 : 1 : g_assert_no_error (error);
552 : 1 : g_assert_true (requested_startup_id);
553 : :
554 : 1 : g_fake_desktop_portal_thread_stop (thread);
555 : 1 : check_portal_openuri_call (uri, thread);
556 : :
557 : 1 : g_clear_object (&ctx);
558 : 1 : g_clear_object (&thread);
559 : 1 : g_clear_pointer (&uri, g_free);
560 : 1 : }
561 : :
562 : : static void
563 : 1 : test_portal_open_uri (void)
564 : : {
565 : : GAppLaunchContext *ctx;
566 : 1 : GError *error = NULL;
567 : 1 : const char *uri = "http://example.com";
568 : 1 : GFakeDesktopPortalThread *thread = NULL;
569 : :
570 : : /* Run a fake-desktop-portal */
571 : 1 : thread = g_fake_desktop_portal_thread_new (session_bus_get_address ());
572 : 1 : g_fake_desktop_portal_thread_run (thread);
573 : :
574 : 1 : ctx = g_object_new (test_app_launch_context_get_type (), NULL);
575 : :
576 : 1 : requested_startup_id = FALSE;
577 : :
578 : 1 : g_app_info_launch_default_for_uri (uri, ctx, &error);
579 : :
580 : 1 : g_assert_no_error (error);
581 : 1 : g_assert_true (requested_startup_id);
582 : :
583 : 1 : g_fake_desktop_portal_thread_stop (thread);
584 : 1 : check_portal_openuri_call (uri, thread);
585 : :
586 : 1 : g_clear_object (&ctx);
587 : 1 : g_clear_object (&thread);
588 : 1 : }
589 : :
590 : : static void
591 : 2 : on_launch_default_for_uri_finished (GObject *object,
592 : : GAsyncResult *result,
593 : : gpointer user_data)
594 : : {
595 : 2 : GError *error = NULL;
596 : 2 : gboolean *called = user_data;
597 : :
598 : 2 : g_app_info_launch_default_for_uri_finish (result, &error);
599 : 2 : g_assert_no_error (error);
600 : :
601 : 2 : *called = TRUE;
602 : :
603 : 2 : g_main_context_wakeup (NULL);
604 : 2 : }
605 : :
606 : : static void
607 : 1 : test_portal_open_file_async (void)
608 : : {
609 : : GAppLaunchContext *ctx;
610 : 1 : gboolean called = FALSE;
611 : : char *uri;
612 : 1 : GFakeDesktopPortalThread *thread = NULL;
613 : :
614 : : /* Run a fake-desktop-portal */
615 : 1 : thread = g_fake_desktop_portal_thread_new (session_bus_get_address ());
616 : 1 : g_fake_desktop_portal_thread_run (thread);
617 : :
618 : 1 : uri = g_filename_to_uri (g_test_get_filename (G_TEST_DIST,
619 : : "org.gtk.test.dbusappinfo.flatpak.desktop",
620 : : NULL),
621 : : NULL,
622 : : NULL);
623 : :
624 : 1 : ctx = g_object_new (test_app_launch_context_get_type (), NULL);
625 : :
626 : 1 : requested_startup_id = FALSE;
627 : :
628 : 1 : g_app_info_launch_default_for_uri_async (uri, ctx,
629 : : NULL, on_launch_default_for_uri_finished, &called);
630 : :
631 : 8 : while (!called)
632 : 7 : g_main_context_iteration (NULL, TRUE);
633 : :
634 : 1 : g_assert_true (requested_startup_id);
635 : :
636 : 1 : g_fake_desktop_portal_thread_stop (thread);
637 : 1 : check_portal_openuri_call (uri, thread);
638 : :
639 : 1 : g_clear_pointer (&uri, g_free);
640 : 1 : g_clear_object (&ctx);
641 : 1 : g_clear_object (&thread);
642 : 1 : }
643 : :
644 : : static void
645 : 1 : test_portal_open_uri_async (void)
646 : : {
647 : : GAppLaunchContext *ctx;
648 : 1 : gboolean called = FALSE;
649 : 1 : const char *uri = "http://example.com";
650 : 1 : GFakeDesktopPortalThread *thread = NULL;
651 : :
652 : : /* Run a fake-desktop-portal */
653 : 1 : thread = g_fake_desktop_portal_thread_new (session_bus_get_address ());
654 : 1 : g_fake_desktop_portal_thread_run (thread);
655 : :
656 : 1 : ctx = g_object_new (test_app_launch_context_get_type (), NULL);
657 : :
658 : 1 : requested_startup_id = FALSE;
659 : :
660 : 1 : g_app_info_launch_default_for_uri_async (uri, ctx,
661 : : NULL, on_launch_default_for_uri_finished, &called);
662 : :
663 : 7 : while (!called)
664 : 6 : g_main_context_iteration (NULL, TRUE);
665 : :
666 : 1 : g_assert_true (requested_startup_id);
667 : :
668 : 1 : g_fake_desktop_portal_thread_stop (thread);
669 : 1 : check_portal_openuri_call (uri, thread);
670 : :
671 : 1 : g_clear_object (&ctx);
672 : 1 : g_clear_object (&thread);
673 : 1 : }
674 : :
675 : : int
676 : 1 : main (int argc, char **argv)
677 : : {
678 : 1 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
679 : :
680 : 1 : g_setenv ("GIO_USE_PORTALS", "1", TRUE);
681 : :
682 : 1 : g_test_add_func ("/appinfo/dbusappinfo", test_dbus_appinfo);
683 : 1 : g_test_add_func ("/appinfo/flatpak-doc-export", test_flatpak_doc_export);
684 : 1 : g_test_add_func ("/appinfo/flatpak-missing-doc-export", test_flatpak_missing_doc_export);
685 : 1 : g_test_add_func ("/appinfo/portal-open-file", test_portal_open_file);
686 : 1 : g_test_add_func ("/appinfo/portal-open-uri", test_portal_open_uri);
687 : 1 : g_test_add_func ("/appinfo/portal-open-file-async", test_portal_open_file_async);
688 : 1 : g_test_add_func ("/appinfo/portal-open-uri-async", test_portal_open_uri_async);
689 : :
690 : 1 : return session_bus_run ();
691 : : }
|