Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2008 Red Hat, Inc
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
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.
10 : : *
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.
15 : : *
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/>.
18 : : *
19 : : * Author: Matthias Clasen
20 : : */
21 : :
22 : : #include <locale.h>
23 : :
24 : : #include <glib/glib.h>
25 : : #include <glib/gstdio.h>
26 : : #include <gio/gio.h>
27 : : #include <gio/gdesktopappinfo.h>
28 : : #include <gio/gunixinputstream.h>
29 : : #include <glib-unix.h>
30 : : #include <stdlib.h>
31 : : #include <string.h>
32 : : #include <unistd.h>
33 : : #include <sys/types.h>
34 : : #include <sys/stat.h>
35 : :
36 [ - + + - : 51 : G_DECLARE_FINAL_TYPE (TestLaunchContext, test_launch_context, TEST,
+ - ]
37 : : LAUNCH_CONTEXT, GAppLaunchContext);
38 : :
39 : : struct _TestLaunchContext {
40 : : GAppLaunchContext parent;
41 : :
42 : : char *overriden_startup_notify_id;
43 : : };
44 : :
45 : : struct _TestLaunchContextClass {
46 : : GAppLaunchContextClass parent;
47 : : };
48 : :
49 [ + + + - : 92 : G_DEFINE_FINAL_TYPE (TestLaunchContext, test_launch_context,
+ + ]
50 : : G_TYPE_APP_LAUNCH_CONTEXT);
51 : :
52 : : static void
53 : 39 : test_launch_context_init (TestLaunchContext *test_context)
54 : : {
55 : 39 : }
56 : :
57 : : static char *
58 : 8 : test_launch_context_get_startup_notify_id (GAppLaunchContext *context,
59 : : GAppInfo *app_info,
60 : : GList *files)
61 : : {
62 : 8 : TestLaunchContext *test_context = TEST_LAUNCH_CONTEXT (context);
63 : :
64 [ - + ]: 8 : if (test_context->overriden_startup_notify_id)
65 : 0 : return g_strdup (test_context->overriden_startup_notify_id);
66 : :
67 [ + + ]: 8 : if (g_app_info_get_id (app_info))
68 : 12 : return g_strdup (g_app_info_get_id (app_info));
69 : :
70 [ + - ]: 2 : if (g_app_info_get_display_name (app_info))
71 : 4 : return g_strdup (g_app_info_get_display_name (app_info));
72 : :
73 : 0 : return g_strdup (g_app_info_get_commandline (app_info));
74 : : }
75 : :
76 : : static void
77 : 39 : test_launch_context_get_startup_notify_dispose (GObject *object)
78 : : {
79 : 39 : TestLaunchContext *test_context = TEST_LAUNCH_CONTEXT (object);
80 : :
81 : 39 : g_clear_pointer (&test_context->overriden_startup_notify_id, g_free);
82 : 39 : G_OBJECT_CLASS (test_launch_context_parent_class)->dispose (object);
83 : 39 : }
84 : :
85 : : static void
86 : 1 : test_launch_context_class_init (TestLaunchContextClass *klass)
87 : : {
88 : 1 : G_APP_LAUNCH_CONTEXT_CLASS (klass)->get_startup_notify_id = test_launch_context_get_startup_notify_id;
89 : 1 : G_OBJECT_CLASS (klass)->dispose = test_launch_context_get_startup_notify_dispose;
90 : 1 : }
91 : :
92 : : static GAppInfo *
93 : 13 : create_command_line_app_info (const char *name,
94 : : const char *command_line,
95 : : const char *default_for_type)
96 : : {
97 : : GAppInfo *info;
98 : 13 : GError *error = NULL;
99 : :
100 : 13 : info = g_app_info_create_from_commandline (command_line,
101 : : name,
102 : : G_APP_INFO_CREATE_NONE,
103 : : &error);
104 : 13 : g_assert_no_error (error);
105 : :
106 : 13 : g_app_info_set_as_default_for_type (info, default_for_type, &error);
107 : 13 : g_assert_no_error (error);
108 : :
109 : 13 : return g_steal_pointer (&info);
110 : : }
111 : :
112 : : static GAppInfo *
113 : 11 : create_app_info (const char *name)
114 : : {
115 : 11 : GError *error = NULL;
116 : : GAppInfo *info;
117 : :
118 : 11 : info = create_command_line_app_info (name, "true blah", "application/x-blah");
119 : :
120 : : /* this is necessary to ensure that the info is saved */
121 : 11 : g_app_info_remove_supports_type (info, "application/x-blah", &error);
122 : 11 : g_assert_no_error (error);
123 : 11 : g_app_info_reset_type_associations ("application/x-blah");
124 : :
125 : 11 : return info;
126 : : }
127 : :
128 : : static void
129 : 1 : test_delete (void)
130 : : {
131 : : GAppInfo *info;
132 : :
133 : : const char *id;
134 : : char *filename;
135 : : gboolean res;
136 : :
137 : 1 : info = create_app_info ("Blah");
138 : :
139 : 1 : id = g_app_info_get_id (info);
140 : 1 : g_assert_nonnull (id);
141 : :
142 : 1 : filename = g_build_filename (g_get_user_data_dir (), "applications", id, NULL);
143 : :
144 : 1 : res = g_file_test (filename, G_FILE_TEST_EXISTS);
145 : 1 : g_assert_true (res);
146 : :
147 : 1 : res = g_app_info_can_delete (info);
148 : 1 : g_assert_true (res);
149 : :
150 : 1 : res = g_app_info_delete (info);
151 : 1 : g_assert_true (res);
152 : :
153 : 1 : res = g_file_test (filename, G_FILE_TEST_EXISTS);
154 : 1 : g_assert_false (res);
155 : :
156 : 1 : g_object_unref (info);
157 : :
158 [ - + ]: 1 : if (g_file_test ("/usr/share/applications/gedit.desktop", G_FILE_TEST_EXISTS))
159 : : {
160 : 0 : info = (GAppInfo*)g_desktop_app_info_new_from_filename ("/usr/share/applications/gedit.desktop");
161 : 0 : g_assert_nonnull (info);
162 : :
163 : 0 : res = g_app_info_can_delete (info);
164 : 0 : g_assert_false (res);
165 : :
166 : 0 : res = g_app_info_delete (info);
167 : 0 : g_assert_false (res);
168 : : }
169 : :
170 : 1 : g_free (filename);
171 : 1 : }
172 : :
173 : : static void
174 : 1 : test_default (void)
175 : : {
176 : : GAppInfo *info, *info1, *info2, *info3;
177 : : GList *list;
178 : 1 : GError *error = NULL;
179 : :
180 : 1 : info1 = create_app_info ("Blah1");
181 : 1 : info2 = create_app_info ("Blah2");
182 : 1 : info3 = create_app_info ("Blah3");
183 : :
184 : 1 : g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
185 : 1 : g_assert_no_error (error);
186 : :
187 : 1 : g_app_info_set_as_default_for_type (info2, "application/x-test", &error);
188 : 1 : g_assert_no_error (error);
189 : :
190 : 1 : info = g_app_info_get_default_for_type ("application/x-test", FALSE);
191 : 1 : g_assert_nonnull (info);
192 : 1 : g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
193 : 1 : g_object_unref (info);
194 : :
195 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
196 : : "*assertion*uri_scheme*failed*");
197 : 1 : g_assert_null (g_app_info_get_default_for_uri_scheme (NULL));
198 : 1 : g_test_assert_expected_messages ();
199 : :
200 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
201 : : "*assertion*uri_scheme*failed*");
202 : 1 : g_assert_null (g_app_info_get_default_for_uri_scheme (""));
203 : 1 : g_test_assert_expected_messages ();
204 : :
205 : 1 : g_app_info_set_as_default_for_type (info3, "x-scheme-handler/glib", &error);
206 : 1 : g_assert_no_error (error);
207 : 1 : info = g_app_info_get_default_for_uri_scheme ("glib");
208 : 1 : g_assert_nonnull (info);
209 : 1 : g_assert_true (g_app_info_equal (info, info3));
210 : 1 : g_object_unref (info);
211 : :
212 : : /* now try adding something, but not setting as default */
213 : 1 : g_app_info_add_supports_type (info3, "application/x-test", &error);
214 : 1 : g_assert_no_error (error);
215 : :
216 : : /* check that info2 is still default */
217 : 1 : info = g_app_info_get_default_for_type ("application/x-test", FALSE);
218 : 1 : g_assert_nonnull (info);
219 : 1 : g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
220 : 1 : g_object_unref (info);
221 : :
222 : : /* now remove info1 again */
223 : 1 : g_app_info_remove_supports_type (info1, "application/x-test", &error);
224 : 1 : g_assert_no_error (error);
225 : :
226 : : /* and make sure info2 is still default */
227 : 1 : info = g_app_info_get_default_for_type ("application/x-test", FALSE);
228 : 1 : g_assert_nonnull (info);
229 : 1 : g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
230 : 1 : g_object_unref (info);
231 : :
232 : : /* now clean it all up */
233 : 1 : g_app_info_reset_type_associations ("application/x-test");
234 : 1 : g_app_info_reset_type_associations ("x-scheme-handler/glib");
235 : :
236 : 1 : list = g_app_info_get_all_for_type ("application/x-test");
237 : 1 : g_assert_null (list);
238 : :
239 : 1 : list = g_app_info_get_all_for_type ("x-scheme-handler/glib");
240 : 1 : g_assert_null (list);
241 : :
242 : 1 : g_app_info_delete (info1);
243 : 1 : g_app_info_delete (info2);
244 : 1 : g_app_info_delete (info3);
245 : :
246 : 1 : g_object_unref (info1);
247 : 1 : g_object_unref (info2);
248 : 1 : g_object_unref (info3);
249 : 1 : }
250 : :
251 : : typedef struct
252 : : {
253 : : GAppInfo *expected_info;
254 : : GMainLoop *loop;
255 : : } DefaultForTypeData;
256 : :
257 : : static void
258 : 6 : ensure_default_type_result (GAppInfo *info,
259 : : DefaultForTypeData *data,
260 : : GError *error)
261 : : {
262 [ + + ]: 6 : if (data->expected_info)
263 : : {
264 : 4 : g_assert_nonnull (info);
265 : 4 : g_assert_no_error (error);
266 : 4 : g_assert_true (g_app_info_equal (info, data->expected_info));
267 : : }
268 : : else
269 : : {
270 : 2 : g_assert_null (info);
271 : 2 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
272 : : }
273 : :
274 : 6 : g_main_loop_quit (data->loop);
275 : 6 : g_clear_object (&info);
276 : 6 : g_clear_error (&error);
277 : 6 : }
278 : :
279 : : static void
280 : 4 : on_default_for_type_cb (GObject *object,
281 : : GAsyncResult *result,
282 : : gpointer user_data)
283 : : {
284 : : GAppInfo *info;
285 : 4 : GError *error = NULL;
286 : 4 : DefaultForTypeData *data = user_data;
287 : :
288 : 4 : g_assert_null (object);
289 : :
290 : 4 : info = g_app_info_get_default_for_type_finish (result, &error);
291 : :
292 : 4 : ensure_default_type_result (info, data, error);
293 : 4 : }
294 : :
295 : : static void
296 : 2 : on_default_for_uri_cb (GObject *object,
297 : : GAsyncResult *result,
298 : : gpointer user_data)
299 : : {
300 : : GAppInfo *info;
301 : 2 : GError *error = NULL;
302 : 2 : DefaultForTypeData *data = user_data;
303 : :
304 : 2 : g_assert_null (object);
305 : :
306 : 2 : info = g_app_info_get_default_for_uri_scheme_finish (result, &error);
307 : :
308 : 2 : ensure_default_type_result (info, data, error);
309 : 2 : }
310 : :
311 : : static void
312 : 1 : test_default_async (void)
313 : : {
314 : : DefaultForTypeData data;
315 : : GAppInfo *info1, *info2, *info3;
316 : : GList *list;
317 : 1 : GError *error = NULL;
318 : :
319 : 1 : data.loop = g_main_loop_new (NULL, TRUE);
320 : :
321 : 1 : info1 = create_app_info ("Blah1");
322 : 1 : info2 = create_app_info ("Blah2");
323 : 1 : info3 = create_app_info ("Blah3");
324 : :
325 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
326 : : "*assertion*content_type*failed*");
327 : 1 : g_app_info_get_default_for_type_async (NULL, FALSE, NULL, NULL, NULL);
328 : 1 : g_test_assert_expected_messages ();
329 : :
330 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
331 : : "*assertion*content_type*failed*");
332 : 1 : g_app_info_get_default_for_type_async ("", FALSE, NULL, NULL, NULL);
333 : 1 : g_test_assert_expected_messages ();
334 : :
335 : 1 : g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
336 : 1 : g_assert_no_error (error);
337 : :
338 : 1 : g_app_info_set_as_default_for_type (info2, "application/x-test", &error);
339 : 1 : g_assert_no_error (error);
340 : :
341 : 1 : data.expected_info = info2;
342 : 1 : g_app_info_get_default_for_type_async ("application/x-test", FALSE,
343 : : NULL, on_default_for_type_cb, &data);
344 : 1 : g_main_loop_run (data.loop);
345 : :
346 : : /* now try adding something, but not setting as default */
347 : 1 : g_app_info_add_supports_type (info3, "application/x-test", &error);
348 : 1 : g_assert_no_error (error);
349 : :
350 : : /* check that info2 is still default */
351 : 1 : data.expected_info = info2;
352 : 1 : g_app_info_get_default_for_type_async ("application/x-test", FALSE,
353 : : NULL, on_default_for_type_cb, &data);
354 : 1 : g_main_loop_run (data.loop);
355 : :
356 : : /* now remove info1 again */
357 : 1 : g_app_info_remove_supports_type (info1, "application/x-test", &error);
358 : 1 : g_assert_no_error (error);
359 : :
360 : : /* and make sure info2 is still default */
361 : 1 : data.expected_info = info2;
362 : 1 : g_app_info_get_default_for_type_async ("application/x-test", FALSE,
363 : : NULL, on_default_for_type_cb, &data);
364 : 1 : g_main_loop_run (data.loop);
365 : :
366 : 1 : g_app_info_set_as_default_for_type (info3, "x-scheme-handler/glib-async", &error);
367 : 1 : g_assert_no_error (error);
368 : :
369 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
370 : : "*assertion*uri_scheme*failed*");
371 : 1 : g_assert_null (g_app_info_get_default_for_uri_scheme (NULL));
372 : 1 : g_test_assert_expected_messages ();
373 : :
374 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
375 : : "*assertion*uri_scheme*failed*");
376 : 1 : g_assert_null (g_app_info_get_default_for_uri_scheme (""));
377 : 1 : g_test_assert_expected_messages ();
378 : :
379 : 1 : data.expected_info = info3;
380 : 1 : g_app_info_get_default_for_uri_scheme_async ("glib-async", NULL,
381 : : on_default_for_uri_cb, &data);
382 : 1 : g_main_loop_run (data.loop);
383 : :
384 : : /* now clean it all up */
385 : 1 : g_app_info_reset_type_associations ("application/x-test");
386 : :
387 : 1 : data.expected_info = NULL;
388 : 1 : g_app_info_get_default_for_type_async ("application/x-test", FALSE,
389 : : NULL, on_default_for_type_cb, &data);
390 : 1 : g_main_loop_run (data.loop);
391 : :
392 : 1 : g_app_info_reset_type_associations ("x-scheme-handler/glib-async");
393 : :
394 : 1 : data.expected_info = NULL;
395 : 1 : g_app_info_get_default_for_uri_scheme_async ("glib-async", NULL,
396 : : on_default_for_uri_cb, &data);
397 : 1 : g_main_loop_run (data.loop);
398 : :
399 : 1 : list = g_app_info_get_all_for_type ("application/x-test");
400 : 1 : g_assert_null (list);
401 : :
402 : 1 : g_app_info_delete (info1);
403 : 1 : g_app_info_delete (info2);
404 : 1 : g_app_info_delete (info3);
405 : :
406 : 1 : g_object_unref (info1);
407 : 1 : g_object_unref (info2);
408 : 1 : g_object_unref (info3);
409 : :
410 : 1 : g_main_loop_unref (data.loop);
411 : 1 : }
412 : :
413 : : static void
414 : 1 : test_fallback (void)
415 : : {
416 : 1 : GAppInfo *info1, *info2, *app = NULL;
417 : : GList *apps, *recomm, *fallback, *list, *l, *m;
418 : 1 : GError *error = NULL;
419 : : gint old_length;
420 : :
421 : 1 : info1 = create_app_info ("Test1");
422 : 1 : info2 = create_app_info ("Test2");
423 : :
424 : 1 : g_assert_true (g_content_type_is_a ("text/x-python", "text/plain"));
425 : :
426 : 1 : apps = g_app_info_get_all_for_type ("text/x-python");
427 : 1 : old_length = g_list_length (apps);
428 : 1 : g_list_free_full (apps, g_object_unref);
429 : :
430 : 1 : g_app_info_add_supports_type (info1, "text/x-python", &error);
431 : 1 : g_assert_no_error (error);
432 : :
433 : 1 : g_app_info_add_supports_type (info2, "text/plain", &error);
434 : 1 : g_assert_no_error (error);
435 : :
436 : : /* check that both apps are registered */
437 : 1 : apps = g_app_info_get_all_for_type ("text/x-python");
438 : 1 : g_assert_cmpint (g_list_length (apps), ==, old_length + 2);
439 : :
440 : : /* check that Test1 is among the recommended apps */
441 : 1 : recomm = g_app_info_get_recommended_for_type ("text/x-python");
442 : 1 : g_assert_nonnull (recomm);
443 [ + - ]: 1 : for (l = recomm; l; l = l->next)
444 : : {
445 : 1 : app = l->data;
446 [ + - ]: 1 : if (g_app_info_equal (info1, app))
447 : 1 : break;
448 : : }
449 : 1 : g_assert_nonnull (app);
450 : 1 : g_assert_true (g_app_info_equal (info1, app));
451 : :
452 : : /* and that Test2 is among the fallback apps */
453 : 1 : fallback = g_app_info_get_fallback_for_type ("text/x-python");
454 : 1 : g_assert_nonnull (fallback);
455 [ + - ]: 1 : for (l = fallback; l; l = l->next)
456 : : {
457 : 1 : app = l->data;
458 [ + - ]: 1 : if (g_app_info_equal (info2, app))
459 : 1 : break;
460 : : }
461 : 1 : g_assert_cmpstr (g_app_info_get_name (app), ==, "Test2");
462 : :
463 : : /* check that recomm + fallback = all applications */
464 : 1 : list = g_list_concat (g_list_copy (recomm), g_list_copy (fallback));
465 : 1 : g_assert_cmpuint (g_list_length (list), ==, g_list_length (apps));
466 : :
467 [ + + + - ]: 3 : for (l = list, m = apps; l != NULL && m != NULL; l = l->next, m = m->next)
468 : : {
469 : 2 : g_assert_true (g_app_info_equal (l->data, m->data));
470 : : }
471 : :
472 : 1 : g_list_free (list);
473 : :
474 : 1 : g_list_free_full (apps, g_object_unref);
475 : 1 : g_list_free_full (recomm, g_object_unref);
476 : 1 : g_list_free_full (fallback, g_object_unref);
477 : :
478 : 1 : g_app_info_reset_type_associations ("text/x-python");
479 : 1 : g_app_info_reset_type_associations ("text/plain");
480 : :
481 : 1 : g_app_info_delete (info1);
482 : 1 : g_app_info_delete (info2);
483 : :
484 : 1 : g_object_unref (info1);
485 : 1 : g_object_unref (info2);
486 : 1 : }
487 : :
488 : : static void
489 : 1 : test_last_used (void)
490 : : {
491 : : GList *applications;
492 : : GAppInfo *info1, *info2, *default_app;
493 : 1 : GError *error = NULL;
494 : :
495 : 1 : info1 = create_app_info ("Test1");
496 : 1 : info2 = create_app_info ("Test2");
497 : :
498 : 1 : g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
499 : 1 : g_assert_no_error (error);
500 : :
501 : 1 : g_app_info_add_supports_type (info2, "application/x-test", &error);
502 : 1 : g_assert_no_error (error);
503 : :
504 : 1 : applications = g_app_info_get_recommended_for_type ("application/x-test");
505 : 1 : g_assert_cmpuint (g_list_length (applications), ==, 2);
506 : :
507 : : /* the first should be the default app now */
508 : 1 : g_assert_true (g_app_info_equal (g_list_nth_data (applications, 0), info1));
509 : 1 : g_assert_true (g_app_info_equal (g_list_nth_data (applications, 1), info2));
510 : :
511 : 1 : g_list_free_full (applications, g_object_unref);
512 : :
513 : 1 : g_app_info_set_as_last_used_for_type (info2, "application/x-test", &error);
514 : 1 : g_assert_no_error (error);
515 : :
516 : 1 : applications = g_app_info_get_recommended_for_type ("application/x-test");
517 : 1 : g_assert_cmpuint (g_list_length (applications), ==, 2);
518 : :
519 : 1 : default_app = g_app_info_get_default_for_type ("application/x-test", FALSE);
520 : 1 : g_assert_true (g_app_info_equal (default_app, info1));
521 : :
522 : : /* the first should be the other app now */
523 : 1 : g_assert_true (g_app_info_equal (g_list_nth_data (applications, 0), info2));
524 : 1 : g_assert_true (g_app_info_equal (g_list_nth_data (applications, 1), info1));
525 : :
526 : 1 : g_list_free_full (applications, g_object_unref);
527 : :
528 : 1 : g_app_info_reset_type_associations ("application/x-test");
529 : :
530 : 1 : g_app_info_delete (info1);
531 : 1 : g_app_info_delete (info2);
532 : :
533 : 1 : g_object_unref (info1);
534 : 1 : g_object_unref (info2);
535 : 1 : g_object_unref (default_app);
536 : 1 : }
537 : :
538 : : static void
539 : 1 : test_extra_getters (void)
540 : : {
541 : : GDesktopAppInfo *appinfo;
542 : : const gchar *lang;
543 : : gchar *s;
544 : : gboolean b;
545 : :
546 : 1 : lang = setlocale (LC_ALL, NULL);
547 : 1 : g_setenv ("LANGUAGE", "de_DE.UTF8", TRUE);
548 : 1 : setlocale (LC_ALL, "");
549 : :
550 : 1 : appinfo = g_desktop_app_info_new_from_filename (g_test_get_filename (G_TEST_DIST, "appinfo-test-static.desktop", NULL));
551 : 1 : g_assert_nonnull (appinfo);
552 : :
553 : 1 : g_assert_true (g_desktop_app_info_has_key (appinfo, "Terminal"));
554 : 1 : g_assert_false (g_desktop_app_info_has_key (appinfo, "Bratwurst"));
555 : :
556 : 1 : s = g_desktop_app_info_get_string (appinfo, "StartupWMClass");
557 : 1 : g_assert_cmpstr (s, ==, "appinfo-class");
558 : 1 : g_free (s);
559 : :
560 : 1 : s = g_desktop_app_info_get_locale_string (appinfo, "X-JunkFood");
561 : 1 : g_assert_cmpstr (s, ==, "Bratwurst");
562 : 1 : g_free (s);
563 : :
564 : 1 : g_setenv ("LANGUAGE", "sv_SE.UTF8", TRUE);
565 : 1 : setlocale (LC_ALL, "");
566 : :
567 : 1 : s = g_desktop_app_info_get_locale_string (appinfo, "X-JunkFood");
568 : 1 : g_assert_cmpstr (s, ==, "Burger"); /* fallback */
569 : 1 : g_free (s);
570 : :
571 : 1 : b = g_desktop_app_info_get_boolean (appinfo, "Terminal");
572 : 1 : g_assert_true (b);
573 : :
574 : 1 : g_object_unref (appinfo);
575 : :
576 : 1 : g_setenv ("LANGUAGE", lang, TRUE);
577 : 1 : setlocale (LC_ALL, "");
578 : 1 : }
579 : :
580 : : static void
581 : 3 : wait_for_file (const gchar *want_this,
582 : : const gchar *but_not_this,
583 : : const gchar *or_this)
584 : : {
585 [ + + ]: 6 : while (access (want_this, F_OK) != 0)
586 : 3 : g_usleep (100000); /* 100ms */
587 : :
588 : 3 : g_assert_cmpuint (access (but_not_this, F_OK), !=, 0);
589 : 3 : g_assert_cmpuint (access (or_this, F_OK), !=, 0);
590 : :
591 : 3 : unlink (want_this);
592 : 3 : unlink (but_not_this);
593 : 3 : unlink (or_this);
594 : 3 : }
595 : :
596 : : static void
597 : 1 : test_actions (void)
598 : : {
599 : 1 : GTestDBus *bus = NULL;
600 : 1 : const char *expected[] = { "frob", "tweak", "twiddle", "broken", NULL };
601 : : const gchar * const *actions;
602 : : GDesktopAppInfo *appinfo;
603 : : const gchar *tmpdir;
604 : : gchar *name;
605 : : gchar *frob_path;
606 : : gchar *tweak_path;
607 : : gchar *twiddle_path;
608 : :
609 : : /* Set up a test session bus to keep D-Bus traffic off the real session bus. */
610 : 1 : bus = g_test_dbus_new (G_TEST_DBUS_NONE);
611 : 1 : g_test_dbus_up (bus);
612 : :
613 : 1 : appinfo = g_desktop_app_info_new_from_filename (g_test_get_filename (G_TEST_DIST, "appinfo-test-actions.desktop", NULL));
614 : 1 : g_assert_nonnull (appinfo);
615 : :
616 : 1 : actions = g_desktop_app_info_list_actions (appinfo);
617 : 5 : g_assert_cmpstrv (actions, expected);
618 : :
619 : 1 : name = g_desktop_app_info_get_action_name (appinfo, "frob");
620 : 1 : g_assert_cmpstr (name, ==, "Frobnicate");
621 : 1 : g_free (name);
622 : :
623 : 1 : name = g_desktop_app_info_get_action_name (appinfo, "tweak");
624 : 1 : g_assert_cmpstr (name, ==, "Tweak");
625 : 1 : g_free (name);
626 : :
627 : 1 : name = g_desktop_app_info_get_action_name (appinfo, "twiddle");
628 : 1 : g_assert_cmpstr (name, ==, "Twiddle");
629 : 1 : g_free (name);
630 : :
631 : 1 : name = g_desktop_app_info_get_action_name (appinfo, "broken");
632 : 1 : g_assert_nonnull (name);
633 : 1 : g_assert_true (g_utf8_validate (name, -1, NULL));
634 : 1 : g_free (name);
635 : :
636 : 1 : tmpdir = g_getenv ("G_TEST_TMPDIR");
637 : 1 : g_assert_nonnull (tmpdir);
638 : 1 : frob_path = g_build_filename (tmpdir, "frob", NULL);
639 : 1 : tweak_path = g_build_filename (tmpdir, "tweak", NULL);
640 : 1 : twiddle_path = g_build_filename (tmpdir, "twiddle", NULL);
641 : :
642 : 1 : g_assert_false (g_file_test (frob_path, G_FILE_TEST_EXISTS));
643 : 1 : g_assert_false (g_file_test (tweak_path, G_FILE_TEST_EXISTS));
644 : 1 : g_assert_false (g_file_test (twiddle_path, G_FILE_TEST_EXISTS));
645 : :
646 : 1 : g_desktop_app_info_launch_action (appinfo, "frob", NULL);
647 : 1 : wait_for_file (frob_path, tweak_path, twiddle_path);
648 : :
649 : 1 : g_desktop_app_info_launch_action (appinfo, "tweak", NULL);
650 : 1 : wait_for_file (tweak_path, frob_path, twiddle_path);
651 : :
652 : 1 : g_desktop_app_info_launch_action (appinfo, "twiddle", NULL);
653 : 1 : wait_for_file (twiddle_path, frob_path, tweak_path);
654 : :
655 : 1 : g_free (frob_path);
656 : 1 : g_free (tweak_path);
657 : 1 : g_free (twiddle_path);
658 : 1 : g_object_unref (appinfo);
659 : :
660 : 1 : g_test_dbus_down (bus);
661 : 1 : g_clear_object (&bus);
662 : 1 : }
663 : :
664 : : static gchar *
665 : 48 : run_apps (const gchar *command,
666 : : const gchar *arg,
667 : : gboolean with_usr,
668 : : gboolean with_home,
669 : : const gchar *locale_name,
670 : : const gchar *language,
671 : : const gchar *xdg_current_desktop)
672 : : {
673 : : gboolean success;
674 : : gchar **envp;
675 : : gchar **argv;
676 : : gint status;
677 : : gchar *out;
678 : 48 : gchar *argv_str = NULL;
679 : :
680 : 48 : argv = g_new (gchar *, 4);
681 : 48 : argv[0] = g_test_build_filename (G_TEST_BUILT, "apps", NULL);
682 : 48 : argv[1] = g_strdup (command);
683 : 48 : argv[2] = g_strdup (arg);
684 : 48 : argv[3] = NULL;
685 : :
686 : 48 : g_assert_true (g_file_test (argv[0], G_FILE_TEST_IS_EXECUTABLE));
687 : 48 : envp = g_get_environ ();
688 : :
689 [ + + ]: 48 : if (with_usr)
690 : : {
691 : 39 : gchar *tmp = g_test_build_filename (G_TEST_DIST, "desktop-files", "usr", NULL);
692 : 39 : envp = g_environ_setenv (envp, "XDG_DATA_DIRS", tmp, TRUE);
693 : 39 : g_free (tmp);
694 : : }
695 : : else
696 : 9 : envp = g_environ_setenv (envp, "XDG_DATA_DIRS", "/does-not-exist", TRUE);
697 : :
698 [ + + ]: 48 : if (with_home)
699 : : {
700 : 32 : gchar *tmp = g_test_build_filename (G_TEST_DIST, "desktop-files", "home", NULL);
701 : 32 : envp = g_environ_setenv (envp, "XDG_DATA_HOME", tmp, TRUE);
702 : 32 : g_free (tmp);
703 : : }
704 : : else
705 : 16 : envp = g_environ_setenv (envp, "XDG_DATA_HOME", "/does-not-exist", TRUE);
706 : :
707 [ + + ]: 48 : if (locale_name)
708 : 2 : envp = g_environ_setenv (envp, "LC_ALL", locale_name, TRUE);
709 : : else
710 : 46 : envp = g_environ_setenv (envp, "LC_ALL", "C", TRUE);
711 : :
712 [ + + ]: 48 : if (language)
713 : 2 : envp = g_environ_setenv (envp, "LANGUAGE", language, TRUE);
714 : : else
715 : 46 : envp = g_environ_unsetenv (envp, "LANGUAGE");
716 : :
717 [ + + ]: 48 : if (xdg_current_desktop)
718 : 10 : envp = g_environ_setenv (envp, "XDG_CURRENT_DESKTOP", xdg_current_desktop, TRUE);
719 : : else
720 : 38 : envp = g_environ_unsetenv (envp, "XDG_CURRENT_DESKTOP");
721 : :
722 : 48 : envp = g_environ_setenv (envp, "G_MESSAGES_DEBUG", "", TRUE);
723 : :
724 : 48 : success = g_spawn_sync (NULL, argv, envp, 0, NULL, NULL, &out, NULL, &status, NULL);
725 : 48 : g_assert_true (success);
726 : 48 : g_assert_cmpuint (status, ==, 0);
727 : :
728 : 48 : argv_str = g_strjoinv (" ", argv);
729 : 48 : g_test_message ("%s: `%s` returned: %s", G_STRFUNC, argv_str, out);
730 : 48 : g_free (argv_str);
731 : :
732 : 48 : g_strfreev (envp);
733 : 48 : g_strfreev (argv);
734 : :
735 : 48 : return out;
736 : : }
737 : :
738 : : static void
739 : 50 : assert_strings_equivalent (const gchar *expected,
740 : : const gchar *result)
741 : 90 : {
742 : : gchar **expected_words;
743 : : gchar **result_words;
744 : : gint i, j;
745 : :
746 : 50 : expected_words = g_strsplit (expected, " ", 0);
747 : 50 : result_words = g_strsplit_set (result, " \n", 0);
748 : :
749 [ + + ]: 140 : for (i = 0; expected_words[i]; i++)
750 : : {
751 [ + - ]: 880 : for (j = 0; result_words[j]; j++)
752 [ + + ]: 880 : if (g_str_equal (expected_words[i], result_words[j]))
753 : 90 : goto got_it;
754 : :
755 : 0 : g_test_fail_printf ("Unable to find expected string '%s' in result '%s'", expected_words[i], result);
756 : :
757 : 90 : got_it:
758 : 90 : continue;
759 : : }
760 : :
761 : 50 : g_assert_cmpint (g_strv_length (expected_words), ==, g_strv_length (result_words));
762 : 50 : g_strfreev (expected_words);
763 : 50 : g_strfreev (result_words);
764 : 50 : }
765 : :
766 : : static void
767 : 4 : assert_list (const gchar *expected,
768 : : gboolean with_usr,
769 : : gboolean with_home,
770 : : const gchar *locale_name,
771 : : const gchar *language)
772 : : {
773 : : gchar *result;
774 : :
775 : 4 : result = run_apps ("list", NULL, with_usr, with_home, locale_name, language, NULL);
776 : 4 : g_strchomp (result);
777 : 4 : assert_strings_equivalent (expected, result);
778 : 4 : g_free (result);
779 : 4 : }
780 : :
781 : : static void
782 : 2 : assert_info (const gchar *desktop_id,
783 : : const gchar *expected,
784 : : gboolean with_usr,
785 : : gboolean with_home,
786 : : const gchar *locale_name,
787 : : const gchar *language)
788 : : {
789 : : gchar *result;
790 : :
791 : 2 : result = run_apps ("show-info", desktop_id, with_usr, with_home, locale_name, language, NULL);
792 : 2 : g_assert_cmpstr (result, ==, expected);
793 : 2 : g_free (result);
794 : 2 : }
795 : :
796 : : static void
797 : 26 : assert_search (const gchar *search_string,
798 : : const gchar *expected,
799 : : gboolean with_usr,
800 : : gboolean with_home,
801 : : const gchar *locale_name,
802 : : const gchar *language)
803 : : {
804 : : gchar **expected_lines;
805 : : gchar **result_lines;
806 : : gchar *result;
807 : : gint i;
808 : :
809 : 26 : expected_lines = g_strsplit (expected, "\n", -1);
810 : 26 : result = run_apps ("search", search_string, with_usr, with_home, locale_name, language, NULL);
811 : 26 : result_lines = g_strsplit (result, "\n", -1);
812 : 26 : g_assert_cmpint (g_strv_length (expected_lines), ==, g_strv_length (result_lines));
813 [ + + ]: 68 : for (i = 0; expected_lines[i]; i++)
814 : 42 : assert_strings_equivalent (expected_lines[i], result_lines[i]);
815 : 26 : g_strfreev (expected_lines);
816 : 26 : g_strfreev (result_lines);
817 : 26 : g_free (result);
818 : 26 : }
819 : :
820 : : static void
821 : 4 : assert_implementations (const gchar *interface,
822 : : const gchar *expected,
823 : : gboolean with_usr,
824 : : gboolean with_home)
825 : : {
826 : : gchar *result;
827 : :
828 : 4 : result = run_apps ("implementations", interface, with_usr, with_home, NULL, NULL, NULL);
829 : 4 : g_strchomp (result);
830 : 4 : assert_strings_equivalent (expected, result);
831 : 4 : g_free (result);
832 : 4 : }
833 : :
834 : : #define ALL_USR_APPS "evince-previewer.desktop nautilus-classic.desktop gnome-font-viewer.desktop " \
835 : : "baobab.desktop yelp.desktop eog.desktop cheese.desktop org.gnome.clocks.desktop " \
836 : : "gnome-contacts.desktop kde4-kate.desktop gcr-prompter.desktop totem.desktop " \
837 : : "gnome-terminal.desktop nautilus-autorun-software.desktop gcr-viewer.desktop " \
838 : : "nautilus-connect-server.desktop kde4-dolphin.desktop gnome-music.desktop " \
839 : : "kde4-konqbrowser.desktop gucharmap.desktop kde4-okular.desktop nautilus.desktop " \
840 : : "gedit.desktop evince.desktop file-roller.desktop dconf-editor.desktop glade.desktop " \
841 : : "invalid-desktop.desktop"
842 : : #define HOME_APPS "epiphany-weather-for-toronto-island-9c6a4e022b17686306243dada811d550d25eb1fb.desktop"
843 : : #define ALL_HOME_APPS HOME_APPS " eog.desktop"
844 : :
845 : : static void
846 : 1 : test_search (void)
847 : : {
848 : 1 : assert_list ("", FALSE, FALSE, NULL, NULL);
849 : 1 : assert_list (ALL_USR_APPS, TRUE, FALSE, NULL, NULL);
850 : 1 : assert_list (ALL_HOME_APPS, FALSE, TRUE, NULL, NULL);
851 : 1 : assert_list (ALL_USR_APPS " " HOME_APPS, TRUE, TRUE, NULL, NULL);
852 : :
853 : : /* The user has "installed" their own version of eog.desktop which
854 : : * calls it "Eye of GNOME". Do some testing based on that.
855 : : *
856 : : * We should always find "Pictures" keyword no matter where we look.
857 : : */
858 : 1 : assert_search ("Picture", "eog.desktop\n", TRUE, TRUE, NULL, NULL);
859 : 1 : assert_search ("Picture", "eog.desktop\n", TRUE, FALSE, NULL, NULL);
860 : 1 : assert_search ("Picture", "eog.desktop\n", FALSE, TRUE, NULL, NULL);
861 : 1 : assert_search ("Picture", "", FALSE, FALSE, NULL, NULL);
862 : :
863 : : /* We should only find it called "eye of gnome" when using the user's
864 : : * directory.
865 : : */
866 : 1 : assert_search ("eye gnome", "", TRUE, FALSE, NULL, NULL);
867 : 1 : assert_search ("eye gnome", "eog.desktop\n", FALSE, TRUE, NULL, NULL);
868 : 1 : assert_search ("eye gnome", "eog.desktop\n", TRUE, TRUE, NULL, NULL);
869 : :
870 : : /* We should only find it called "image viewer" when _not_ using the
871 : : * user's directory.
872 : : */
873 : 1 : assert_search ("image viewer", "eog.desktop\n", TRUE, FALSE, NULL, NULL);
874 : 1 : assert_search ("image viewer", "", FALSE, TRUE, NULL, NULL);
875 : 1 : assert_search ("image viewer", "", TRUE, TRUE, NULL, NULL);
876 : :
877 : : /* There're "flatpak" apps (clocks) installed as well - they should *not*
878 : : * match the prefix command ("/bin/sh") in the Exec= line though. Then with
879 : : * substring matching, Image Viewer (eog) should be in next group because it
880 : : * contains "Slideshow" in its keywords.
881 : : */
882 : 1 : assert_search ("sh", "gnome-terminal.desktop\n"
883 : : "eog.desktop\n", TRUE, FALSE, NULL, NULL);
884 : :
885 : : /* "frobnicator.desktop" is ignored by get_all() because the binary is
886 : : * missing, but search should still find it (to avoid either stale results
887 : : * from the cache or expensive stat() calls for each potential result)
888 : : */
889 : 1 : assert_search ("frobni", "frobnicator.desktop\n", TRUE, FALSE, NULL, NULL);
890 : :
891 : : /* Obvious multi-word search */
892 : 1 : assert_search ("doc hel", "yelp.desktop\n", TRUE, TRUE, NULL, NULL);
893 : :
894 : : /* Repeated search terms should do nothing... */
895 : 1 : assert_search ("files file fil fi f", "nautilus.desktop\n", TRUE, TRUE, NULL, NULL);
896 : :
897 : : /* "con" will match "connect" and "contacts" on name with prefix match in
898 : : * first group, then second group is a Keyword prefix match for "configuration" in dconf-editor.desktop
899 : : * and third group is a substring match for "Desktop Icons" in Name of nautilus-classic.desktop.
900 : : */
901 : 1 : assert_search ("con", "gnome-contacts.desktop nautilus-connect-server.desktop\n"
902 : : "dconf-editor.desktop\n"
903 : : "nautilus-classic.desktop\n", TRUE, TRUE, NULL, NULL);
904 : :
905 : : /* "gnome" will match "eye of gnome" from the user's directory, plus
906 : : * matching "GNOME Clocks" X-GNOME-FullName.
907 : : */
908 : 1 : assert_search ("gnome", "eog.desktop\n"
909 : : "org.gnome.clocks.desktop\n", TRUE, TRUE, NULL, NULL);
910 : :
911 : : /* eog has exec name 'false' in usr only */
912 : 1 : assert_search ("false", "eog.desktop\n", TRUE, FALSE, NULL, NULL);
913 : 1 : assert_search ("false", "", FALSE, TRUE, NULL, NULL);
914 : 1 : assert_search ("false", "", TRUE, TRUE, NULL, NULL);
915 : 1 : assert_search ("false", "", FALSE, FALSE, NULL, NULL);
916 : :
917 : : /* make sure we only search the first component */
918 : 1 : assert_search ("nonsearchable", "", TRUE, FALSE, NULL, NULL);
919 : :
920 : : /* "gnome con" will match only gnome contacts; via the name for
921 : : * "contacts" and keywords for "friend"
922 : : */
923 : 1 : assert_search ("friend con", "gnome-contacts.desktop\n", TRUE, TRUE, NULL, NULL);
924 : :
925 : : /* make sure we get the correct kde4- prefix on the application IDs
926 : : * from subdirectories
927 : : */
928 : 1 : assert_search ("konq", "kde4-konqbrowser.desktop\n", TRUE, TRUE, NULL, NULL);
929 : 1 : assert_search ("kate", "kde4-kate.desktop\n", TRUE, TRUE, NULL, NULL);
930 : :
931 : : /* make sure we can look up apps by name properly */
932 : 1 : assert_info ("kde4-kate.desktop",
933 : : "kde4-kate.desktop\n"
934 : : "Kate\n"
935 : : "Kate\n"
936 : : "nil\n", TRUE, TRUE, NULL, NULL);
937 : :
938 : 1 : assert_info ("nautilus.desktop",
939 : : "nautilus.desktop\n"
940 : : "Files\n"
941 : : "Files\n"
942 : : "Access and organize files\n", TRUE, TRUE, NULL, NULL);
943 : :
944 : : /* make sure localised searching works properly */
945 : 1 : assert_search ("foliumi", "nautilus.desktop\n"
946 : : "kde4-konqbrowser.desktop\n", TRUE, FALSE, "en_US.UTF-8", "eo");
947 : : /* the user's eog.desktop has no translations... */
948 : 1 : assert_search ("foliumi", "nautilus.desktop\n"
949 : : "kde4-konqbrowser.desktop\n", TRUE, TRUE, "en_US.UTF-8", "eo");
950 : 1 : }
951 : :
952 : : static void
953 : 1 : test_implements (void)
954 : : {
955 : : /* Make sure we can find our search providers... */
956 : 1 : assert_implementations ("org.gnome.Shell.SearchProvider2",
957 : : "gnome-music.desktop gnome-contacts.desktop eog.desktop",
958 : : TRUE, FALSE);
959 : :
960 : : /* And our image acquisition possibilities... */
961 : 1 : assert_implementations ("org.freedesktop.ImageProvider",
962 : : "cheese.desktop",
963 : : TRUE, FALSE);
964 : :
965 : : /* Make sure the user's eog is properly masking the system one */
966 : 1 : assert_implementations ("org.gnome.Shell.SearchProvider2",
967 : : "gnome-music.desktop gnome-contacts.desktop",
968 : : TRUE, TRUE);
969 : :
970 : : /* Make sure we get nothing if we have nothing */
971 : 1 : assert_implementations ("org.gnome.Shell.SearchProvider2", "", FALSE, FALSE);
972 : 1 : }
973 : :
974 : : static void
975 : 11 : assert_shown (const gchar *desktop_id,
976 : : gboolean expected,
977 : : const gchar *xdg_current_desktop)
978 : : {
979 : : gchar *result;
980 : :
981 : 11 : result = run_apps ("should-show", desktop_id, TRUE, TRUE, NULL, NULL, xdg_current_desktop);
982 : 11 : g_assert_cmpstr (result, ==, expected ? "true\n" : "false\n");
983 : 11 : g_free (result);
984 : 11 : }
985 : :
986 : : static void
987 : 1 : test_show_in (void)
988 : : {
989 : 1 : assert_shown ("gcr-prompter.desktop", FALSE, NULL);
990 : 1 : assert_shown ("gcr-prompter.desktop", FALSE, "GNOME");
991 : 1 : assert_shown ("gcr-prompter.desktop", FALSE, "KDE");
992 : 1 : assert_shown ("gcr-prompter.desktop", FALSE, "GNOME:GNOME-Classic");
993 : 1 : assert_shown ("gcr-prompter.desktop", TRUE, "GNOME-Classic:GNOME");
994 : 1 : assert_shown ("gcr-prompter.desktop", TRUE, "GNOME-Classic");
995 : 1 : assert_shown ("gcr-prompter.desktop", TRUE, "GNOME-Classic:KDE");
996 : 1 : assert_shown ("gcr-prompter.desktop", TRUE, "KDE:GNOME-Classic");
997 : 1 : assert_shown ("invalid-desktop.desktop", TRUE, "GNOME");
998 : 1 : assert_shown ("invalid-desktop.desktop", FALSE, "../invalid/desktop");
999 : 1 : assert_shown ("invalid-desktop.desktop", FALSE, "../invalid/desktop:../invalid/desktop");
1000 : 1 : }
1001 : :
1002 : : static void
1003 : 4 : on_launch_started (GAppLaunchContext *context, GAppInfo *info, GVariant *platform_data, gpointer data)
1004 : : {
1005 : 4 : gboolean *invoked = data;
1006 : :
1007 : 4 : g_assert_true (G_IS_APP_LAUNCH_CONTEXT (context));
1008 : :
1009 [ + - ]: 4 : if (TEST_IS_LAUNCH_CONTEXT (context))
1010 : : {
1011 : : GVariantDict dict;
1012 : : const char *sni;
1013 : : char *expected_sni;
1014 : :
1015 : 4 : g_assert_nonnull (platform_data);
1016 : 4 : g_variant_dict_init (&dict, platform_data);
1017 : 4 : g_assert_true (
1018 : : g_variant_dict_lookup (&dict, "startup-notification-id", "&s", &sni));
1019 : 4 : expected_sni = g_app_launch_context_get_startup_notify_id (context, info, NULL);
1020 : 4 : g_assert_cmpstr (sni, ==, expected_sni);
1021 : :
1022 : 4 : g_free (expected_sni);
1023 : 4 : g_variant_dict_clear (&dict);
1024 : : }
1025 : : else
1026 : : {
1027 : : /* Our default context doesn't fill in any platform data */
1028 : 0 : g_assert_null (platform_data);
1029 : : }
1030 : :
1031 : 4 : g_assert_false (*invoked);
1032 : 4 : *invoked = TRUE;
1033 : 4 : }
1034 : :
1035 : : static void
1036 : 2 : on_launched (GAppLaunchContext *context, GAppInfo *info, GVariant *platform_data, gpointer data)
1037 : : {
1038 : 2 : gboolean *launched = data;
1039 : : GVariantDict dict;
1040 : : int pid;
1041 : :
1042 : 2 : g_assert_true (G_IS_APP_LAUNCH_CONTEXT (context));
1043 : 2 : g_assert_true (G_IS_APP_INFO (info));
1044 : 2 : g_assert_nonnull (platform_data);
1045 : 2 : g_variant_dict_init (&dict, platform_data);
1046 : 2 : g_assert_true (g_variant_dict_lookup (&dict, "pid", "i", &pid, NULL));
1047 : 2 : g_assert_cmpint (pid, >, 1);
1048 : :
1049 : 2 : g_assert_false (*launched);
1050 : 2 : *launched = TRUE;
1051 : :
1052 : 2 : g_variant_dict_clear (&dict);
1053 : 2 : }
1054 : :
1055 : : static void
1056 : 2 : on_launch_failed (GAppLaunchContext *context, const char *startup_notify_id, gpointer data)
1057 : : {
1058 : 2 : gboolean *invoked = data;
1059 : :
1060 : 2 : g_assert_true (G_IS_APP_LAUNCH_CONTEXT (context));
1061 : 2 : g_assert_nonnull (startup_notify_id);
1062 : 2 : g_test_message ("Application launch failed: %s", startup_notify_id);
1063 : :
1064 : 2 : g_assert_false (*invoked);
1065 : 2 : *invoked = TRUE;
1066 : 2 : }
1067 : :
1068 : : /* Test g_desktop_app_info_launch_uris_as_manager() and
1069 : : * g_desktop_app_info_launch_uris_as_manager_with_fds()
1070 : : */
1071 : : static void
1072 : 1 : test_launch_as_manager (void)
1073 : : {
1074 : : GDesktopAppInfo *appinfo;
1075 : 1 : GError *error = NULL;
1076 : : gboolean retval;
1077 : : const gchar *path;
1078 : 1 : gboolean invoked = FALSE;
1079 : 1 : gboolean launched = FALSE;
1080 : 1 : gboolean failed = FALSE;
1081 : : GAppLaunchContext *context;
1082 : :
1083 : 1 : path = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
1084 : 1 : appinfo = g_desktop_app_info_new_from_filename (path);
1085 : 1 : g_assert_true (G_IS_APP_INFO (appinfo));
1086 : :
1087 : 1 : context = g_object_new (test_launch_context_get_type (), NULL);
1088 : 1 : g_signal_connect (context, "launch-started",
1089 : : G_CALLBACK (on_launch_started),
1090 : : &invoked);
1091 : 1 : g_signal_connect (context, "launched",
1092 : : G_CALLBACK (on_launched),
1093 : : &launched);
1094 : 1 : g_signal_connect (context, "launch-failed",
1095 : : G_CALLBACK (on_launch_failed),
1096 : : &failed);
1097 : 1 : retval = g_desktop_app_info_launch_uris_as_manager (appinfo, NULL, context, 0,
1098 : : NULL, NULL,
1099 : : NULL, NULL,
1100 : : &error);
1101 : 1 : g_assert_no_error (error);
1102 : 1 : g_assert_true (retval);
1103 : 1 : g_assert_true (invoked);
1104 : 1 : g_assert_true (launched);
1105 : 1 : g_assert_false (failed);
1106 : :
1107 : 1 : invoked = FALSE;
1108 : 1 : launched = FALSE;
1109 : 1 : failed = FALSE;
1110 : 1 : retval = g_desktop_app_info_launch_uris_as_manager_with_fds (appinfo,
1111 : : NULL, context, 0,
1112 : : NULL, NULL,
1113 : : NULL, NULL,
1114 : : -1, -1, -1,
1115 : : &error);
1116 : 1 : g_assert_no_error (error);
1117 : 1 : g_assert_true (retval);
1118 : 1 : g_assert_true (invoked);
1119 : 1 : g_assert_true (launched);
1120 : 1 : g_assert_false (failed);
1121 : :
1122 : 1 : g_object_unref (appinfo);
1123 : 1 : g_assert_finalize_object (context);
1124 : 1 : }
1125 : :
1126 : : static void
1127 : 1 : test_launch_as_manager_fail (void)
1128 : : {
1129 : : GAppLaunchContext *context;
1130 : : GDesktopAppInfo *appinfo;
1131 : 1 : GError *error = NULL;
1132 : : gboolean retval;
1133 : : const gchar *path;
1134 : 1 : gboolean launch_started = FALSE;
1135 : 1 : gboolean launched = FALSE;
1136 : 1 : gboolean failed = FALSE;
1137 : :
1138 : 1 : g_test_summary ("Tests that launch-errors are properly handled, we force " \
1139 : : "this by using invalid FD's values when launching as manager");
1140 : :
1141 : 1 : path = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
1142 : 1 : appinfo = g_desktop_app_info_new_from_filename (path);
1143 : 1 : g_assert_true (G_IS_APP_INFO (appinfo));
1144 : :
1145 : 1 : context = g_object_new (test_launch_context_get_type (), NULL);
1146 : 1 : g_signal_connect (context, "launch-started",
1147 : : G_CALLBACK (on_launch_started),
1148 : : &launch_started);
1149 : 1 : g_signal_connect (context, "launched",
1150 : : G_CALLBACK (on_launched),
1151 : : &launched);
1152 : 1 : g_signal_connect (context, "launch-failed",
1153 : : G_CALLBACK (on_launch_failed),
1154 : : &failed);
1155 : :
1156 : 1 : retval = g_desktop_app_info_launch_uris_as_manager_with_fds (appinfo,
1157 : : NULL, context, 0,
1158 : : NULL, NULL,
1159 : : NULL, NULL,
1160 : : 3000, 3001, 3002,
1161 : : &error);
1162 : 1 : g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED);
1163 : 1 : g_assert_false (retval);
1164 : 1 : g_assert_true (launch_started);
1165 : 1 : g_assert_false (launched);
1166 : 1 : g_assert_true (failed);
1167 : :
1168 : 1 : g_clear_error (&error);
1169 : 1 : g_object_unref (appinfo);
1170 : 1 : g_assert_finalize_object (context);
1171 : 1 : }
1172 : :
1173 : : static GAppInfo *
1174 : 2 : create_app_info_toucher (const char *name,
1175 : : const char *touched_file_name,
1176 : : const char *handled_type,
1177 : : char **out_file_path)
1178 : : {
1179 : 2 : GError *error = NULL;
1180 : : GAppInfo *info;
1181 : : gchar *command_line;
1182 : : gchar *file_path;
1183 : : gchar *tmpdir;
1184 : :
1185 : 2 : g_assert_nonnull (out_file_path);
1186 : :
1187 : 2 : tmpdir = g_dir_make_tmp ("desktop-app-info-launch-XXXXXX", &error);
1188 : 2 : g_assert_no_error (error);
1189 : :
1190 : 2 : file_path = g_build_filename (tmpdir, touched_file_name, NULL);
1191 : 2 : command_line = g_strdup_printf ("touch %s", file_path);
1192 : :
1193 : 2 : info = create_command_line_app_info (name, command_line, handled_type);
1194 : 2 : *out_file_path = g_steal_pointer (&file_path);
1195 : :
1196 : 2 : g_free (tmpdir);
1197 : 2 : g_free (command_line);
1198 : :
1199 : 2 : return info;
1200 : : }
1201 : :
1202 : : static void
1203 : 1 : test_default_uri_handler (void)
1204 : : {
1205 : 1 : GError *error = NULL;
1206 : 1 : gchar *file_path = NULL;
1207 : : GAppInfo *info;
1208 : :
1209 : 1 : info = create_app_info_toucher ("Touch Handled", "handled",
1210 : : "x-scheme-handler/glib-touch",
1211 : : &file_path);
1212 : 1 : g_assert_true (G_IS_APP_INFO (info));
1213 : 1 : g_assert_nonnull (file_path);
1214 : :
1215 : 1 : g_assert_true (g_app_info_launch_default_for_uri ("glib-touch://touch-me",
1216 : : NULL, &error));
1217 : 1 : g_assert_no_error (error);
1218 : :
1219 [ + + ]: 1096 : while (!g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
1220 : 1 : g_assert_true (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
1221 : :
1222 : 1 : g_assert_false (g_app_info_launch_default_for_uri ("glib-INVALID-touch://touch-me",
1223 : : NULL, &error));
1224 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1225 : 1 : g_clear_error (&error);
1226 : :
1227 : 1 : g_object_unref (info);
1228 : 1 : g_free (file_path);
1229 : 1 : }
1230 : :
1231 : : static void
1232 : 1 : on_launch_default_for_uri_success_cb (GObject *object,
1233 : : GAsyncResult *result,
1234 : : gpointer user_data)
1235 : : {
1236 : 1 : GError *error = NULL;
1237 : 1 : gboolean *called = user_data;
1238 : :
1239 : 1 : g_assert_true (g_app_info_launch_default_for_uri_finish (result, &error));
1240 : 1 : g_assert_no_error (error);
1241 : :
1242 : 1 : *called = TRUE;
1243 : 1 : }
1244 : :
1245 : : static void
1246 : 1 : on_launch_default_for_uri_not_found_cb (GObject *object,
1247 : : GAsyncResult *result,
1248 : : gpointer user_data)
1249 : : {
1250 : 1 : GError *error = NULL;
1251 : 1 : GMainLoop *loop = user_data;
1252 : :
1253 : 1 : g_assert_false (g_app_info_launch_default_for_uri_finish (result, &error));
1254 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1255 : 1 : g_clear_error (&error);
1256 : :
1257 : 1 : g_main_loop_quit (loop);
1258 : 1 : }
1259 : :
1260 : : static void
1261 : 1 : on_launch_default_for_uri_cancelled_cb (GObject *object,
1262 : : GAsyncResult *result,
1263 : : gpointer user_data)
1264 : : {
1265 : 1 : GError *error = NULL;
1266 : 1 : GMainLoop *loop = user_data;
1267 : :
1268 : 1 : g_assert_false (g_app_info_launch_default_for_uri_finish (result, &error));
1269 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1270 : 1 : g_clear_error (&error);
1271 : :
1272 : 1 : g_main_loop_quit (loop);
1273 : 1 : }
1274 : :
1275 : : static void
1276 : 1 : test_default_uri_handler_async (void)
1277 : : {
1278 : : GCancellable *cancellable;
1279 : 1 : gchar *file_path = NULL;
1280 : : GAppInfo *info;
1281 : : GMainLoop *loop;
1282 : 1 : gboolean called = FALSE;
1283 : : gint64 start_time, touch_time;
1284 : :
1285 : 1 : loop = g_main_loop_new (NULL, FALSE);
1286 : 1 : info = create_app_info_toucher ("Touch Handled", "handled-async",
1287 : : "x-scheme-handler/glib-async-touch",
1288 : : &file_path);
1289 : 1 : g_assert_true (G_IS_APP_INFO (info));
1290 : 1 : g_assert_nonnull (file_path);
1291 : :
1292 : 1 : start_time = g_get_real_time ();
1293 : 1 : g_app_info_launch_default_for_uri_async ("glib-async-touch://touch-me", NULL,
1294 : : NULL,
1295 : : on_launch_default_for_uri_success_cb,
1296 : : &called);
1297 : :
1298 [ + + - + ]: 443 : while (!g_file_test (file_path, G_FILE_TEST_IS_REGULAR) || !called)
1299 : 442 : g_main_context_iteration (NULL, FALSE);
1300 : :
1301 : 1 : touch_time = g_get_real_time () - start_time;
1302 : 1 : g_assert_true (called);
1303 : 1 : g_assert_true (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
1304 : :
1305 : 1 : g_unlink (file_path);
1306 : 1 : g_assert_false (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
1307 : :
1308 : 1 : g_app_info_launch_default_for_uri_async ("glib-async-INVALID-touch://touch-me",
1309 : : NULL, NULL,
1310 : : on_launch_default_for_uri_not_found_cb,
1311 : : loop);
1312 : 1 : g_main_loop_run (loop);
1313 : :
1314 : 1 : cancellable = g_cancellable_new ();
1315 : 1 : g_app_info_launch_default_for_uri_async ("glib-async-touch://touch-me", NULL,
1316 : : cancellable,
1317 : : on_launch_default_for_uri_cancelled_cb,
1318 : : loop);
1319 : 1 : g_cancellable_cancel (cancellable);
1320 : 1 : g_main_loop_run (loop);
1321 : :
1322 : : /* If started, our touch app would take some time to actually write the
1323 : : * file to disk, so let's wait a bit here to ensure that the file isn't
1324 : : * inadvertently getting created when a launch operation is canceled up
1325 : : * front. Give it 3× as long as the successful case took, to allow for
1326 : : * some variance.
1327 : : */
1328 : 1 : g_usleep (touch_time * 3);
1329 : 1 : g_assert_false (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
1330 : :
1331 : 1 : g_object_unref (info);
1332 : 1 : g_main_loop_unref (loop);
1333 : 1 : g_free (file_path);
1334 : 1 : }
1335 : :
1336 : : /* Test if Desktop-File Id is correctly formed */
1337 : : static void
1338 : 1 : test_id (void)
1339 : : {
1340 : : gchar *result;
1341 : :
1342 : 1 : result = run_apps ("default-for-type", "application/vnd.kde.okular-archive",
1343 : : TRUE, FALSE, NULL, NULL, NULL);
1344 : 1 : g_assert_cmpstr (result, ==, "kde4-okular.desktop\n");
1345 : 1 : g_free (result);
1346 : 1 : }
1347 : :
1348 : : static const char *
1349 : 102 : get_terminal_divider (const char *terminal_name)
1350 : : {
1351 [ + + ]: 102 : if (g_str_equal (terminal_name, "xdg-terminal-exec"))
1352 : 3 : return NULL;
1353 [ + + ]: 99 : if (g_str_equal (terminal_name, "kgx"))
1354 : 9 : return "-e";
1355 [ + + ]: 90 : if (g_str_equal (terminal_name, "gnome-terminal"))
1356 : 9 : return "--";
1357 [ + + ]: 81 : if (g_str_equal (terminal_name, "tilix"))
1358 : 9 : return "-e";
1359 [ + + ]: 72 : if (g_str_equal (terminal_name, "konsole"))
1360 : 9 : return "-e";
1361 [ + + ]: 63 : if (g_str_equal (terminal_name, "nxterm"))
1362 : 9 : return "-e";
1363 [ + + ]: 54 : if (g_str_equal (terminal_name, "color-xterm"))
1364 : 9 : return "-e";
1365 [ + + ]: 45 : if (g_str_equal (terminal_name, "rxvt"))
1366 : 9 : return "-e";
1367 [ + + ]: 36 : if (g_str_equal (terminal_name, "dtterm"))
1368 : 9 : return "-e";
1369 [ + + ]: 27 : if (g_str_equal (terminal_name, "xterm"))
1370 : 9 : return "-e";
1371 [ + + ]: 18 : if (g_str_equal (terminal_name, "mate-terminal"))
1372 : 9 : return "-x";
1373 [ + - ]: 9 : if (g_str_equal (terminal_name, "xfce4-terminal"))
1374 : 9 : return "-x";
1375 : :
1376 : : g_return_val_if_reached (NULL);
1377 : : }
1378 : :
1379 : : typedef enum {
1380 : : TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE,
1381 : : TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT,
1382 : : TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH,
1383 : : } TerminalLaunchType;
1384 : :
1385 : : typedef struct {
1386 : : const char *exec;
1387 : : TerminalLaunchType type;
1388 : : } TerminalLaunchData;
1389 : :
1390 : : static TerminalLaunchData *
1391 : 36 : terminal_launch_data_new (const char *exec, TerminalLaunchType type)
1392 : : {
1393 : 36 : TerminalLaunchData *d = NULL;
1394 : :
1395 : 36 : d = g_new0 (TerminalLaunchData, 1);
1396 : 36 : d->exec = exec;
1397 : 36 : d->type = type;
1398 : :
1399 : 36 : return d;
1400 : : }
1401 : :
1402 : : static void
1403 : 36 : test_launch_uris_with_terminal (gconstpointer data)
1404 : : {
1405 : : int fd;
1406 : : int ret;
1407 : : int flags;
1408 : : int terminal_divider_arg_length;
1409 : 36 : const TerminalLaunchData *launch_data = data;
1410 : 36 : const char *terminal_exec = launch_data->exec;
1411 : 36 : char *old_path = NULL;
1412 : : char *command_line;
1413 : : char *bin_path;
1414 : : char *terminal_path;
1415 : : char *output_fd_path;
1416 : : char *script_contents;
1417 : 36 : char *output_contents = NULL;
1418 : : char *sh;
1419 : : GAppInfo *app_info;
1420 : : GList *uris;
1421 : : GList *paths;
1422 : : GStrv output_args;
1423 : 36 : GError *error = NULL;
1424 : : GInputStream *input_stream;
1425 : : GDataInputStream *data_input_stream;
1426 : : GAppLaunchContext *launch_context;
1427 : :
1428 : 36 : sh = g_find_program_in_path ("sh");
1429 : 36 : g_assert_nonnull (sh);
1430 : :
1431 : 36 : bin_path = g_dir_make_tmp ("bin-path-XXXXXX", &error);
1432 : 36 : g_assert_no_error (error);
1433 : :
1434 : 36 : launch_context = g_object_new (test_launch_context_get_type (), NULL);
1435 : :
1436 [ + + + - ]: 36 : switch (launch_data->type)
1437 : : {
1438 : 12 : case TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE:
1439 : 12 : old_path = g_strdup (g_getenv ("PATH"));
1440 : 12 : g_assert_true (g_setenv ("PATH", bin_path, TRUE));
1441 : 12 : break;
1442 : :
1443 : 12 : case TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT:
1444 : 12 : g_app_launch_context_setenv (launch_context, "PATH", bin_path);
1445 : 12 : break;
1446 : :
1447 : 12 : case TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH:
1448 : 12 : g_app_launch_context_setenv (launch_context, "PATH", "/not/valid");
1449 : 12 : break;
1450 : :
1451 : 0 : default:
1452 : : g_assert_not_reached ();
1453 : : }
1454 : :
1455 : 36 : terminal_path = g_build_filename (bin_path, terminal_exec, NULL);
1456 : 36 : output_fd_path = g_build_filename (bin_path, "fifo", NULL);
1457 : :
1458 : 36 : ret = mkfifo (output_fd_path, 0600);
1459 : 36 : g_assert_cmpint (ret, ==, 0);
1460 : :
1461 : 36 : fd = g_open (output_fd_path, O_RDONLY | O_CLOEXEC | O_NONBLOCK, 0);
1462 : 36 : g_assert_cmpint (fd, >=, 0);
1463 : :
1464 : 36 : flags = fcntl (fd, F_GETFL);
1465 : 36 : g_assert_cmpint (flags, >=, 0);
1466 : :
1467 : 36 : ret = fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
1468 : 36 : g_assert_cmpint (ret, ==, 0);
1469 : :
1470 : 36 : input_stream = g_unix_input_stream_new (fd, TRUE);
1471 : 36 : data_input_stream = g_data_input_stream_new (input_stream);
1472 : 36 : script_contents = g_strdup_printf ("#!%s\n" \
1473 : : "out='%s'\n"
1474 : : "printf '%%s\\n' \"$*\" > \"$out\"\n",
1475 : : sh,
1476 : : output_fd_path);
1477 : 36 : g_file_set_contents (terminal_path, script_contents, -1, &error);
1478 : 36 : g_assert_no_error (error);
1479 : 36 : g_assert_cmpint (g_chmod (terminal_path, 0500), ==, 0);
1480 : :
1481 : 36 : g_test_message ("Fake '%s' terminal created as: %s", terminal_exec, terminal_path);
1482 : :
1483 : 36 : command_line = g_strdup_printf ("true %s-argument", terminal_exec);
1484 : :
1485 [ + + ]: 36 : if (launch_data->type == TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH)
1486 : : {
1487 : : GKeyFile *key_file;
1488 : : char *key_file_contents;
1489 : 12 : const char base_file[] =
1490 : : "[Desktop Entry]\n"
1491 : : "Type=Application\n"
1492 : : "Name=terminal launched app\n"
1493 : : "Terminal=true\n"
1494 : : "Path=%s\n"
1495 : : "Exec=%s\n";
1496 : :
1497 : 12 : key_file = g_key_file_new ();
1498 : 12 : key_file_contents = g_strdup_printf (base_file, bin_path, command_line);
1499 : :
1500 : 12 : g_assert_true (
1501 : : g_key_file_load_from_data (key_file, key_file_contents, -1,
1502 : : G_KEY_FILE_NONE, NULL));
1503 : :
1504 : 12 : app_info = (GAppInfo*) g_desktop_app_info_new_from_keyfile (key_file);
1505 : 12 : g_assert_true (G_IS_DESKTOP_APP_INFO (app_info));
1506 : 12 : g_assert_true (
1507 : : g_desktop_app_info_get_boolean (G_DESKTOP_APP_INFO (app_info), "Terminal"));
1508 : :
1509 : 12 : g_key_file_unref (key_file);
1510 : 12 : g_free (key_file_contents);
1511 : : }
1512 : : else
1513 : : {
1514 : 24 : app_info = g_app_info_create_from_commandline (command_line,
1515 : : "Test App on Terminal",
1516 : : G_APP_INFO_CREATE_NEEDS_TERMINAL |
1517 : : G_APP_INFO_CREATE_SUPPORTS_URIS,
1518 : : &error);
1519 : 24 : g_assert_no_error (error);
1520 : : }
1521 : :
1522 : 36 : paths = g_list_prepend (NULL, bin_path);
1523 : 36 : uris = g_list_prepend (NULL, g_filename_to_uri (bin_path, NULL, &error));
1524 : 36 : g_assert_no_error (error);
1525 : :
1526 : 36 : paths = g_list_prepend (paths, (gpointer) g_get_user_data_dir ());
1527 : 36 : uris = g_list_append (uris, g_filename_to_uri (g_get_user_data_dir (), NULL, &error));
1528 : 36 : g_assert_no_error (error);
1529 : :
1530 : 36 : g_assert_cmpint (g_list_length (paths), ==, 2);
1531 : 36 : g_app_info_launch_uris (app_info, uris, launch_context, &error);
1532 : 36 : g_assert_no_error (error);
1533 : :
1534 [ + + ]: 108 : while (output_contents == NULL)
1535 : : {
1536 : 36 : output_contents =
1537 : 36 : g_data_input_stream_read_upto (data_input_stream, "\n", 1, NULL, NULL, &error);
1538 : 36 : g_assert_no_error (error);
1539 : :
1540 [ - + ]: 36 : if (output_contents == NULL)
1541 : 0 : g_usleep (G_USEC_PER_SEC / 10);
1542 : : }
1543 : 36 : g_test_message ("'%s' called with arguments: '%s'", terminal_exec, output_contents);
1544 : :
1545 : 36 : g_data_input_stream_read_byte (data_input_stream, NULL, &error);
1546 : 36 : g_assert_no_error (error);
1547 : :
1548 : 36 : output_args = g_strsplit (output_contents, " ", -1);
1549 : 36 : g_clear_pointer (&output_contents, g_free);
1550 : :
1551 : 36 : terminal_divider_arg_length = (get_terminal_divider (terminal_exec) != NULL) ? 1 : 0;
1552 : 36 : g_assert_cmpuint (g_strv_length (output_args), ==, 3 + terminal_divider_arg_length);
1553 [ + + ]: 36 : if (terminal_divider_arg_length == 1)
1554 : : {
1555 : 33 : g_assert_cmpstr (output_args[0], ==, get_terminal_divider (terminal_exec));
1556 : 33 : g_assert_cmpstr (output_args[1], ==, "true");
1557 : 33 : g_assert_cmpstr (output_args[2], ==, command_line + 5);
1558 : : }
1559 : : else
1560 : : {
1561 : 3 : g_assert_cmpstr (output_args[0], ==, "true");
1562 : 3 : g_assert_cmpstr (output_args[1], ==, command_line + 5);
1563 : : }
1564 : 36 : paths = g_list_delete_link (paths,
1565 : 36 : g_list_find_custom (paths, output_args[2 + terminal_divider_arg_length], g_str_equal));
1566 : 36 : g_assert_cmpint (g_list_length (paths), ==, 1);
1567 : 36 : g_clear_pointer (&output_args, g_strfreev);
1568 : :
1569 [ + + ]: 144 : while (output_contents == NULL)
1570 : : {
1571 : 72 : output_contents =
1572 : 72 : g_data_input_stream_read_upto (data_input_stream, "\n", 1, NULL, NULL, &error);
1573 : 72 : g_assert_no_error (error);
1574 : :
1575 [ + + ]: 72 : if (output_contents == NULL)
1576 : 36 : g_usleep (G_USEC_PER_SEC / 10);
1577 : : }
1578 : 36 : g_test_message ("'%s' called with arguments: '%s'", terminal_exec, output_contents);
1579 : :
1580 : 36 : g_data_input_stream_read_byte (data_input_stream, NULL, &error);
1581 : 36 : g_assert_no_error (error);
1582 : :
1583 : 36 : output_args = g_strsplit (output_contents, " ", -1);
1584 : 36 : g_clear_pointer (&output_contents, g_free);
1585 : 36 : g_assert_cmpuint (g_strv_length (output_args), ==, 3 + terminal_divider_arg_length);
1586 [ + + ]: 36 : if (terminal_divider_arg_length > 0)
1587 : : {
1588 : 33 : g_assert_cmpstr (output_args[0], ==, get_terminal_divider (terminal_exec));
1589 : 33 : g_assert_cmpstr (output_args[1], ==, "true");
1590 : 33 : g_assert_cmpstr (output_args[2], ==, command_line + 5);
1591 : : }
1592 : : else
1593 : : {
1594 : 3 : g_assert_cmpstr (output_args[0], ==, "true");
1595 : 3 : g_assert_cmpstr (output_args[1], ==, command_line + 5);
1596 : : }
1597 : 36 : paths = g_list_delete_link (paths,
1598 : 36 : g_list_find_custom (paths, output_args[2 + terminal_divider_arg_length], g_str_equal));
1599 : 36 : g_assert_cmpint (g_list_length (paths), ==, 0);
1600 : 36 : g_clear_pointer (&output_args, g_strfreev);
1601 : :
1602 : 36 : g_assert_null (paths);
1603 : :
1604 [ + + ]: 36 : if (launch_data->type == TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE)
1605 : 12 : g_assert_true (g_setenv ("PATH", old_path, TRUE));
1606 : :
1607 : 36 : g_close (fd, &error);
1608 : 36 : g_assert_no_error (error);
1609 : :
1610 : 36 : g_free (sh);
1611 : 36 : g_free (command_line);
1612 : 36 : g_free (bin_path);
1613 : 36 : g_free (terminal_path);
1614 : 36 : g_free (output_fd_path);
1615 : 36 : g_free (script_contents);
1616 : 36 : g_free (old_path);
1617 : 36 : g_clear_pointer (&output_args, g_strfreev);
1618 : 36 : g_clear_pointer (&output_contents, g_free);
1619 : 36 : g_clear_object (&data_input_stream);
1620 : 36 : g_clear_object (&input_stream);
1621 : 36 : g_clear_object (&app_info);
1622 : 36 : g_clear_object (&launch_context);
1623 : 36 : g_clear_error (&error);
1624 : 36 : g_clear_list (&paths, NULL);
1625 : 36 : g_clear_list (&uris, g_free);
1626 : 36 : }
1627 : :
1628 : : static void
1629 : 1 : test_launch_uris_with_invalid_terminal (void)
1630 : : {
1631 : : char *old_path;
1632 : : char *bin_path;
1633 : : GAppInfo *app_info;
1634 : 1 : GError *error = NULL;
1635 : :
1636 : 1 : bin_path = g_dir_make_tmp ("bin-path-XXXXXX", &error);
1637 : 1 : g_assert_no_error (error);
1638 : :
1639 : 1 : old_path = g_strdup (g_getenv ("PATH"));
1640 : 1 : g_assert_true (g_setenv ("PATH", bin_path, TRUE));
1641 : :
1642 : 1 : app_info = g_app_info_create_from_commandline ("true invalid-glib-terminal",
1643 : : "Test App on Invalid Terminal",
1644 : : G_APP_INFO_CREATE_NEEDS_TERMINAL |
1645 : : G_APP_INFO_CREATE_SUPPORTS_URIS,
1646 : : &error);
1647 : 1 : g_assert_no_error (error);
1648 : :
1649 : 1 : g_app_info_launch_uris (app_info, NULL, NULL, &error);
1650 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
1651 : 1 : g_clear_error (&error);
1652 : :
1653 : 1 : g_assert_true (g_setenv ("PATH", old_path, TRUE));
1654 : :
1655 : 1 : g_clear_object (&app_info);
1656 : 1 : g_clear_error (&error);
1657 : 1 : g_free (bin_path);
1658 : 1 : g_free (old_path);
1659 : 1 : }
1660 : :
1661 : : static void
1662 : 1 : test_app_path (void)
1663 : : {
1664 : : GDesktopAppInfo *appinfo;
1665 : : const char *desktop_path;
1666 : :
1667 : 1 : desktop_path = g_test_get_filename (G_TEST_BUILT, "appinfo-test-path.desktop", NULL);
1668 : 1 : appinfo = g_desktop_app_info_new_from_filename (desktop_path);
1669 : :
1670 : 1 : g_assert_true (G_IS_DESKTOP_APP_INFO (appinfo));
1671 : :
1672 : 1 : g_clear_object (&appinfo);
1673 : 1 : }
1674 : :
1675 : : static void
1676 : 1 : test_app_path_wrong (void)
1677 : : {
1678 : : GKeyFile *key_file;
1679 : : GDesktopAppInfo *appinfo;
1680 : 1 : const gchar bad_try_exec_file_contents[] =
1681 : : "[Desktop Entry]\n"
1682 : : "Type=Application\n"
1683 : : "Name=appinfo-test\n"
1684 : : "TryExec=appinfo-test\n"
1685 : : "Path=this-must-not-exist‼\n"
1686 : : "Exec=true\n";
1687 : 1 : const gchar bad_exec_file_contents[] =
1688 : : "[Desktop Entry]\n"
1689 : : "Type=Application\n"
1690 : : "Name=appinfo-test\n"
1691 : : "TryExec=true\n"
1692 : : "Path=this-must-not-exist‼\n"
1693 : : "Exec=appinfo-test\n";
1694 : :
1695 : 1 : g_assert_true (
1696 : : g_file_test (g_test_get_filename (G_TEST_BUILT, "appinfo-test", NULL),
1697 : : G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE));
1698 : :
1699 : 1 : key_file = g_key_file_new ();
1700 : :
1701 : 1 : g_assert_true (
1702 : : g_key_file_load_from_data (key_file, bad_try_exec_file_contents, -1,
1703 : : G_KEY_FILE_NONE, NULL));
1704 : :
1705 : 1 : appinfo = g_desktop_app_info_new_from_keyfile (key_file);
1706 : 1 : g_assert_false (G_IS_DESKTOP_APP_INFO (appinfo));
1707 : :
1708 : 1 : g_assert_true (
1709 : : g_key_file_load_from_data (key_file, bad_exec_file_contents, -1,
1710 : : G_KEY_FILE_NONE, NULL));
1711 : :
1712 : 1 : appinfo = g_desktop_app_info_new_from_keyfile (key_file);
1713 : 1 : g_assert_false (G_IS_DESKTOP_APP_INFO (appinfo));
1714 : :
1715 : 1 : g_clear_pointer (&key_file, g_key_file_unref);
1716 : 1 : g_clear_object (&appinfo);
1717 : 1 : }
1718 : :
1719 : : static void
1720 : 1 : test_launch_startup_notify_fail (void)
1721 : : {
1722 : : GAppInfo *app_info;
1723 : : GAppLaunchContext *context;
1724 : 1 : GError *error = NULL;
1725 : : gboolean launch_started;
1726 : : gboolean launch_failed;
1727 : : gboolean launched;
1728 : : GList *uris;
1729 : :
1730 : 1 : app_info = g_app_info_create_from_commandline ("this-must-not-exist‼",
1731 : : "failing app",
1732 : : G_APP_INFO_CREATE_NONE |
1733 : : G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION,
1734 : : &error);
1735 : 1 : g_assert_no_error (error);
1736 : :
1737 : 1 : context = g_object_new (test_launch_context_get_type (), NULL);
1738 : 1 : g_signal_connect (context, "launch-started",
1739 : : G_CALLBACK (on_launch_started),
1740 : : &launch_started);
1741 : 1 : g_signal_connect (context, "launched",
1742 : : G_CALLBACK (on_launch_started),
1743 : : &launched);
1744 : 1 : g_signal_connect (context, "launch-failed",
1745 : : G_CALLBACK (on_launch_failed),
1746 : : &launch_failed);
1747 : :
1748 : 1 : launch_started = FALSE;
1749 : 1 : launch_failed = FALSE;
1750 : 1 : launched = FALSE;
1751 : 1 : uris = g_list_prepend (NULL, g_file_new_for_uri ("foo://bar"));
1752 : 1 : uris = g_list_prepend (uris, g_file_new_for_uri ("bar://foo"));
1753 : 1 : g_assert_false (g_app_info_launch (app_info, uris, context, &error));
1754 : 1 : g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
1755 : 1 : g_assert_true (launch_started);
1756 : 1 : g_assert_true (launch_failed);
1757 : 1 : g_assert_false (launched);
1758 : :
1759 : 1 : g_clear_error (&error);
1760 : 1 : g_clear_object (&app_info);
1761 : 1 : g_clear_object (&context);
1762 : 1 : g_clear_list (&uris, g_object_unref);
1763 : 1 : }
1764 : :
1765 : : static void
1766 : 1 : test_launch_fail (void)
1767 : : {
1768 : : GAppInfo *app_info;
1769 : 1 : GError *error = NULL;
1770 : :
1771 : 1 : app_info = g_app_info_create_from_commandline ("this-must-not-exist‼",
1772 : : "failing app",
1773 : : G_APP_INFO_CREATE_NONE,
1774 : : &error);
1775 : 1 : g_assert_no_error (error);
1776 : :
1777 : 1 : g_assert_false (g_app_info_launch (app_info, NULL, NULL, &error));
1778 : 1 : g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
1779 : :
1780 : 1 : g_clear_error (&error);
1781 : 1 : g_clear_object (&app_info);
1782 : 1 : }
1783 : :
1784 : : static void
1785 : 1 : test_launch_fail_absolute_path (void)
1786 : : {
1787 : : GAppInfo *app_info;
1788 : 1 : GError *error = NULL;
1789 : :
1790 : 1 : app_info = g_app_info_create_from_commandline ("/nothing/of/this-must-exist‼",
1791 : : NULL,
1792 : : G_APP_INFO_CREATE_NONE,
1793 : : &error);
1794 : 1 : g_assert_no_error (error);
1795 : :
1796 : 1 : g_assert_false (g_app_info_launch (app_info, NULL, NULL, &error));
1797 : 1 : g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
1798 : :
1799 : 1 : g_clear_error (&error);
1800 : 1 : g_clear_object (&app_info);
1801 : :
1802 : 1 : app_info = g_app_info_create_from_commandline ("/",
1803 : : NULL,
1804 : : G_APP_INFO_CREATE_NONE,
1805 : : &error);
1806 : 1 : g_assert_no_error (error);
1807 : :
1808 : 1 : g_assert_false (g_app_info_launch (app_info, NULL, NULL, &error));
1809 : 1 : g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
1810 : :
1811 : 1 : g_clear_error (&error);
1812 : 1 : g_clear_object (&app_info);
1813 : 1 : }
1814 : :
1815 : : static void
1816 : 1 : async_result_cb (GObject *source_object,
1817 : : GAsyncResult *result,
1818 : : gpointer user_data)
1819 : : {
1820 : 1 : GAsyncResult **result_out = user_data;
1821 : :
1822 : 1 : g_assert (*result_out == NULL);
1823 : 1 : *result_out = g_object_ref (result);
1824 : 1 : g_main_context_wakeup (g_main_context_get_thread_default ());
1825 : 1 : }
1826 : :
1827 : : static void
1828 : 1 : test_launch_fail_dbus (void)
1829 : : {
1830 : 1 : GTestDBus *bus = NULL;
1831 : 1 : GDesktopAppInfo *app_info = NULL;
1832 : 1 : GAppLaunchContext *context = NULL;
1833 : 1 : GAsyncResult *result = NULL;
1834 : 1 : GError *error = NULL;
1835 : :
1836 : : /* Set up a test session bus to ensure that launching the app happens using
1837 : : * D-Bus rather than spawning. */
1838 : 1 : bus = g_test_dbus_new (G_TEST_DBUS_NONE);
1839 : 1 : g_test_dbus_up (bus);
1840 : :
1841 : 1 : app_info = g_desktop_app_info_new_from_filename (g_test_get_filename (G_TEST_DIST, "org.gtk.test.dbusappinfo.desktop", NULL));
1842 : 1 : g_assert_nonnull (app_info);
1843 : :
1844 : 1 : g_assert_true (g_desktop_app_info_has_key (app_info, "DBusActivatable"));
1845 : :
1846 : 1 : context = g_app_launch_context_new ();
1847 : :
1848 : 1 : g_app_info_launch_uris_async (G_APP_INFO (app_info), NULL, context, NULL, async_result_cb, &result);
1849 : :
1850 [ + + ]: 4 : while (result == NULL)
1851 : 3 : g_main_context_iteration (NULL, TRUE);
1852 : :
1853 : 1 : g_assert_false (g_app_info_launch_uris_finish (G_APP_INFO (app_info), result, &error));
1854 : 1 : g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN);
1855 : :
1856 : 1 : g_test_dbus_down (bus);
1857 : 1 : g_clear_object (&bus);
1858 : :
1859 : 1 : g_clear_error (&error);
1860 : 1 : g_clear_object (&result);
1861 : 1 : g_clear_object (&context);
1862 : 1 : g_clear_object (&app_info);
1863 : 1 : }
1864 : :
1865 : : int
1866 : 1 : main (int argc,
1867 : : char *argv[])
1868 : : {
1869 : : guint i;
1870 : 1 : const gchar *supported_terminals[] = {
1871 : : "xdg-terminal-exec",
1872 : : "kgx",
1873 : : "gnome-terminal",
1874 : : "mate-terminal",
1875 : : "xfce4-terminal",
1876 : : "tilix",
1877 : : "konsole",
1878 : : "nxterm",
1879 : : "color-xterm",
1880 : : "rxvt",
1881 : : "dtterm",
1882 : : "xterm",
1883 : : };
1884 : :
1885 : : /* While we use %G_TEST_OPTION_ISOLATE_DIRS to create temporary directories
1886 : : * for each of the tests, we want to use the system MIME registry, assuming
1887 : : * that it exists and correctly has shared-mime-info installed. */
1888 : 1 : g_content_type_set_mime_dirs (NULL);
1889 : :
1890 : 1 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1891 : :
1892 : 1 : g_test_add_func ("/desktop-app-info/delete", test_delete);
1893 : 1 : g_test_add_func ("/desktop-app-info/default", test_default);
1894 : 1 : g_test_add_func ("/desktop-app-info/default-async", test_default_async);
1895 : 1 : g_test_add_func ("/desktop-app-info/fallback", test_fallback);
1896 : 1 : g_test_add_func ("/desktop-app-info/lastused", test_last_used);
1897 : 1 : g_test_add_func ("/desktop-app-info/extra-getters", test_extra_getters);
1898 : 1 : g_test_add_func ("/desktop-app-info/actions", test_actions);
1899 : 1 : g_test_add_func ("/desktop-app-info/search", test_search);
1900 : 1 : g_test_add_func ("/desktop-app-info/implements", test_implements);
1901 : 1 : g_test_add_func ("/desktop-app-info/show-in", test_show_in);
1902 : 1 : g_test_add_func ("/desktop-app-info/app-path", test_app_path);
1903 : 1 : g_test_add_func ("/desktop-app-info/app-path/wrong", test_app_path_wrong);
1904 : 1 : g_test_add_func ("/desktop-app-info/launch/fail", test_launch_fail);
1905 : 1 : g_test_add_func ("/desktop-app-info/launch/fail-absolute-path", test_launch_fail_absolute_path);
1906 : 1 : g_test_add_func ("/desktop-app-info/launch/fail-startup-notify", test_launch_startup_notify_fail);
1907 : 1 : g_test_add_func ("/desktop-app-info/launch/fail-dbus", test_launch_fail_dbus);
1908 : 1 : g_test_add_func ("/desktop-app-info/launch-as-manager", test_launch_as_manager);
1909 : 1 : g_test_add_func ("/desktop-app-info/launch-as-manager/fail", test_launch_as_manager_fail);
1910 : 1 : g_test_add_func ("/desktop-app-info/launch-default-uri-handler", test_default_uri_handler);
1911 : 1 : g_test_add_func ("/desktop-app-info/launch-default-uri-handler-async", test_default_uri_handler_async);
1912 : 1 : g_test_add_func ("/desktop-app-info/id", test_id);
1913 : :
1914 [ + + ]: 13 : for (i = 0; i < G_N_ELEMENTS (supported_terminals); i++)
1915 : : {
1916 : : char *path;
1917 : :
1918 : 12 : path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-path/%s",
1919 : : supported_terminals[i]);
1920 : 12 : g_test_add_data_func_full (path,
1921 : 12 : terminal_launch_data_new (supported_terminals[i],
1922 : : TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE),
1923 : : test_launch_uris_with_terminal, g_free);
1924 : 12 : g_clear_pointer (&path, g_free);
1925 : :
1926 : 12 : path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-context/%s",
1927 : : supported_terminals[i]);
1928 : 12 : g_test_add_data_func_full (path,
1929 : 12 : terminal_launch_data_new (supported_terminals[i],
1930 : : TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT),
1931 : : test_launch_uris_with_terminal, g_free);
1932 : 12 : g_clear_pointer (&path, g_free);
1933 : :
1934 : 12 : path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-desktop-path/%s",
1935 : : supported_terminals[i]);
1936 : 12 : g_test_add_data_func_full (path,
1937 : 12 : terminal_launch_data_new (supported_terminals[i],
1938 : : TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH),
1939 : : test_launch_uris_with_terminal, g_free);
1940 : 12 : g_clear_pointer (&path, g_free);
1941 : : }
1942 : :
1943 : 1 : g_test_add_func ("/desktop-app-info/launch-uris-with-terminal/invalid-glib-terminal",
1944 : : test_launch_uris_with_invalid_terminal);
1945 : :
1946 : 1 : return g_test_run ();
1947 : : }
|