mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 07:56:14 +01:00
794b18df34
The Comment field provides a user-visible description of the app, which usually contains generic words ("and", "or", "not", "is", ...) that add noise when used for search. It made some sense to match against the field as a fallback for Keywords, before that key was well established. However that key has been around for years now, so hopefully every app where additional terms are helpful uses it by now. With that, the downside of added noise outweighs the benefit, so it's time to stop matching on comments.
1940 lines
62 KiB
C
1940 lines
62 KiB
C
/*
|
||
* Copyright (C) 2008 Red Hat, Inc
|
||
*
|
||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public
|
||
* License as published by the Free Software Foundation; either
|
||
* version 2.1 of the License, or (at your option) any later version.
|
||
*
|
||
* This library is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
* Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General
|
||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||
*
|
||
* Author: Matthias Clasen
|
||
*/
|
||
|
||
#include <locale.h>
|
||
|
||
#include <glib/glib.h>
|
||
#include <glib/gstdio.h>
|
||
#include <gio/gio.h>
|
||
#include <gio/gdesktopappinfo.h>
|
||
#include <gio/gunixinputstream.h>
|
||
#include <glib-unix.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
|
||
G_DECLARE_FINAL_TYPE (TestLaunchContext, test_launch_context, TEST,
|
||
LAUNCH_CONTEXT, GAppLaunchContext);
|
||
|
||
struct _TestLaunchContext {
|
||
GAppLaunchContext parent;
|
||
|
||
char *overriden_startup_notify_id;
|
||
};
|
||
|
||
struct _TestLaunchContextClass {
|
||
GAppLaunchContextClass parent;
|
||
};
|
||
|
||
G_DEFINE_FINAL_TYPE (TestLaunchContext, test_launch_context,
|
||
G_TYPE_APP_LAUNCH_CONTEXT);
|
||
|
||
static void
|
||
test_launch_context_init (TestLaunchContext *test_context)
|
||
{
|
||
}
|
||
|
||
static char *
|
||
test_launch_context_get_startup_notify_id (GAppLaunchContext *context,
|
||
GAppInfo *app_info,
|
||
GList *files)
|
||
{
|
||
TestLaunchContext *test_context = TEST_LAUNCH_CONTEXT (context);
|
||
|
||
if (test_context->overriden_startup_notify_id)
|
||
return g_strdup (test_context->overriden_startup_notify_id);
|
||
|
||
if (g_app_info_get_id (app_info))
|
||
return g_strdup (g_app_info_get_id (app_info));
|
||
|
||
if (g_app_info_get_display_name (app_info))
|
||
return g_strdup (g_app_info_get_display_name (app_info));
|
||
|
||
return g_strdup (g_app_info_get_commandline (app_info));
|
||
}
|
||
|
||
static void
|
||
test_launch_context_get_startup_notify_dispose (GObject *object)
|
||
{
|
||
TestLaunchContext *test_context = TEST_LAUNCH_CONTEXT (object);
|
||
|
||
g_clear_pointer (&test_context->overriden_startup_notify_id, g_free);
|
||
G_OBJECT_CLASS (test_launch_context_parent_class)->dispose (object);
|
||
}
|
||
|
||
static void
|
||
test_launch_context_class_init (TestLaunchContextClass *klass)
|
||
{
|
||
G_APP_LAUNCH_CONTEXT_CLASS (klass)->get_startup_notify_id = test_launch_context_get_startup_notify_id;
|
||
G_OBJECT_CLASS (klass)->dispose = test_launch_context_get_startup_notify_dispose;
|
||
}
|
||
|
||
static GAppInfo *
|
||
create_command_line_app_info (const char *name,
|
||
const char *command_line,
|
||
const char *default_for_type)
|
||
{
|
||
GAppInfo *info;
|
||
GError *error = NULL;
|
||
|
||
info = g_app_info_create_from_commandline (command_line,
|
||
name,
|
||
G_APP_INFO_CREATE_NONE,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
|
||
g_app_info_set_as_default_for_type (info, default_for_type, &error);
|
||
g_assert_no_error (error);
|
||
|
||
return g_steal_pointer (&info);
|
||
}
|
||
|
||
static GAppInfo *
|
||
create_app_info (const char *name)
|
||
{
|
||
GError *error = NULL;
|
||
GAppInfo *info;
|
||
|
||
info = create_command_line_app_info (name, "true blah", "application/x-blah");
|
||
|
||
/* this is necessary to ensure that the info is saved */
|
||
g_app_info_remove_supports_type (info, "application/x-blah", &error);
|
||
g_assert_no_error (error);
|
||
g_app_info_reset_type_associations ("application/x-blah");
|
||
|
||
return info;
|
||
}
|
||
|
||
static void
|
||
test_delete (void)
|
||
{
|
||
GAppInfo *info;
|
||
|
||
const char *id;
|
||
char *filename;
|
||
gboolean res;
|
||
|
||
info = create_app_info ("Blah");
|
||
|
||
id = g_app_info_get_id (info);
|
||
g_assert_nonnull (id);
|
||
|
||
filename = g_build_filename (g_get_user_data_dir (), "applications", id, NULL);
|
||
|
||
res = g_file_test (filename, G_FILE_TEST_EXISTS);
|
||
g_assert_true (res);
|
||
|
||
res = g_app_info_can_delete (info);
|
||
g_assert_true (res);
|
||
|
||
res = g_app_info_delete (info);
|
||
g_assert_true (res);
|
||
|
||
res = g_file_test (filename, G_FILE_TEST_EXISTS);
|
||
g_assert_false (res);
|
||
|
||
g_object_unref (info);
|
||
|
||
if (g_file_test ("/usr/share/applications/gedit.desktop", G_FILE_TEST_EXISTS))
|
||
{
|
||
info = (GAppInfo*)g_desktop_app_info_new_from_filename ("/usr/share/applications/gedit.desktop");
|
||
g_assert_nonnull (info);
|
||
|
||
res = g_app_info_can_delete (info);
|
||
g_assert_false (res);
|
||
|
||
res = g_app_info_delete (info);
|
||
g_assert_false (res);
|
||
}
|
||
|
||
g_free (filename);
|
||
}
|
||
|
||
static void
|
||
test_default (void)
|
||
{
|
||
GAppInfo *info, *info1, *info2, *info3;
|
||
GList *list;
|
||
GError *error = NULL;
|
||
|
||
info1 = create_app_info ("Blah1");
|
||
info2 = create_app_info ("Blah2");
|
||
info3 = create_app_info ("Blah3");
|
||
|
||
g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
g_app_info_set_as_default_for_type (info2, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
info = g_app_info_get_default_for_type ("application/x-test", FALSE);
|
||
g_assert_nonnull (info);
|
||
g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
|
||
g_object_unref (info);
|
||
|
||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||
"*assertion*uri_scheme*failed*");
|
||
g_assert_null (g_app_info_get_default_for_uri_scheme (NULL));
|
||
g_test_assert_expected_messages ();
|
||
|
||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||
"*assertion*uri_scheme*failed*");
|
||
g_assert_null (g_app_info_get_default_for_uri_scheme (""));
|
||
g_test_assert_expected_messages ();
|
||
|
||
g_app_info_set_as_default_for_type (info3, "x-scheme-handler/glib", &error);
|
||
g_assert_no_error (error);
|
||
info = g_app_info_get_default_for_uri_scheme ("glib");
|
||
g_assert_nonnull (info);
|
||
g_assert_true (g_app_info_equal (info, info3));
|
||
g_object_unref (info);
|
||
|
||
/* now try adding something, but not setting as default */
|
||
g_app_info_add_supports_type (info3, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
/* check that info2 is still default */
|
||
info = g_app_info_get_default_for_type ("application/x-test", FALSE);
|
||
g_assert_nonnull (info);
|
||
g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
|
||
g_object_unref (info);
|
||
|
||
/* now remove info1 again */
|
||
g_app_info_remove_supports_type (info1, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
/* and make sure info2 is still default */
|
||
info = g_app_info_get_default_for_type ("application/x-test", FALSE);
|
||
g_assert_nonnull (info);
|
||
g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
|
||
g_object_unref (info);
|
||
|
||
/* now clean it all up */
|
||
g_app_info_reset_type_associations ("application/x-test");
|
||
g_app_info_reset_type_associations ("x-scheme-handler/glib");
|
||
|
||
list = g_app_info_get_all_for_type ("application/x-test");
|
||
g_assert_null (list);
|
||
|
||
list = g_app_info_get_all_for_type ("x-scheme-handler/glib");
|
||
g_assert_null (list);
|
||
|
||
g_app_info_delete (info1);
|
||
g_app_info_delete (info2);
|
||
g_app_info_delete (info3);
|
||
|
||
g_object_unref (info1);
|
||
g_object_unref (info2);
|
||
g_object_unref (info3);
|
||
}
|
||
|
||
typedef struct
|
||
{
|
||
GAppInfo *expected_info;
|
||
GMainLoop *loop;
|
||
} DefaultForTypeData;
|
||
|
||
static void
|
||
ensure_default_type_result (GAppInfo *info,
|
||
DefaultForTypeData *data,
|
||
GError *error)
|
||
{
|
||
if (data->expected_info)
|
||
{
|
||
g_assert_nonnull (info);
|
||
g_assert_no_error (error);
|
||
g_assert_true (g_app_info_equal (info, data->expected_info));
|
||
}
|
||
else
|
||
{
|
||
g_assert_null (info);
|
||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
|
||
}
|
||
|
||
g_main_loop_quit (data->loop);
|
||
g_clear_object (&info);
|
||
g_clear_error (&error);
|
||
}
|
||
|
||
static void
|
||
on_default_for_type_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
GAppInfo *info;
|
||
GError *error = NULL;
|
||
DefaultForTypeData *data = user_data;
|
||
|
||
g_assert_null (object);
|
||
|
||
info = g_app_info_get_default_for_type_finish (result, &error);
|
||
|
||
ensure_default_type_result (info, data, error);
|
||
}
|
||
|
||
static void
|
||
on_default_for_uri_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
GAppInfo *info;
|
||
GError *error = NULL;
|
||
DefaultForTypeData *data = user_data;
|
||
|
||
g_assert_null (object);
|
||
|
||
info = g_app_info_get_default_for_uri_scheme_finish (result, &error);
|
||
|
||
ensure_default_type_result (info, data, error);
|
||
}
|
||
|
||
static void
|
||
test_default_async (void)
|
||
{
|
||
DefaultForTypeData data;
|
||
GAppInfo *info1, *info2, *info3;
|
||
GList *list;
|
||
GError *error = NULL;
|
||
|
||
data.loop = g_main_loop_new (NULL, TRUE);
|
||
|
||
info1 = create_app_info ("Blah1");
|
||
info2 = create_app_info ("Blah2");
|
||
info3 = create_app_info ("Blah3");
|
||
|
||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||
"*assertion*content_type*failed*");
|
||
g_app_info_get_default_for_type_async (NULL, FALSE, NULL, NULL, NULL);
|
||
g_test_assert_expected_messages ();
|
||
|
||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||
"*assertion*content_type*failed*");
|
||
g_app_info_get_default_for_type_async ("", FALSE, NULL, NULL, NULL);
|
||
g_test_assert_expected_messages ();
|
||
|
||
g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
g_app_info_set_as_default_for_type (info2, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
data.expected_info = info2;
|
||
g_app_info_get_default_for_type_async ("application/x-test", FALSE,
|
||
NULL, on_default_for_type_cb, &data);
|
||
g_main_loop_run (data.loop);
|
||
|
||
/* now try adding something, but not setting as default */
|
||
g_app_info_add_supports_type (info3, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
/* check that info2 is still default */
|
||
data.expected_info = info2;
|
||
g_app_info_get_default_for_type_async ("application/x-test", FALSE,
|
||
NULL, on_default_for_type_cb, &data);
|
||
g_main_loop_run (data.loop);
|
||
|
||
/* now remove info1 again */
|
||
g_app_info_remove_supports_type (info1, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
/* and make sure info2 is still default */
|
||
data.expected_info = info2;
|
||
g_app_info_get_default_for_type_async ("application/x-test", FALSE,
|
||
NULL, on_default_for_type_cb, &data);
|
||
g_main_loop_run (data.loop);
|
||
|
||
g_app_info_set_as_default_for_type (info3, "x-scheme-handler/glib-async", &error);
|
||
g_assert_no_error (error);
|
||
|
||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||
"*assertion*uri_scheme*failed*");
|
||
g_assert_null (g_app_info_get_default_for_uri_scheme (NULL));
|
||
g_test_assert_expected_messages ();
|
||
|
||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||
"*assertion*uri_scheme*failed*");
|
||
g_assert_null (g_app_info_get_default_for_uri_scheme (""));
|
||
g_test_assert_expected_messages ();
|
||
|
||
data.expected_info = info3;
|
||
g_app_info_get_default_for_uri_scheme_async ("glib-async", NULL,
|
||
on_default_for_uri_cb, &data);
|
||
g_main_loop_run (data.loop);
|
||
|
||
/* now clean it all up */
|
||
g_app_info_reset_type_associations ("application/x-test");
|
||
|
||
data.expected_info = NULL;
|
||
g_app_info_get_default_for_type_async ("application/x-test", FALSE,
|
||
NULL, on_default_for_type_cb, &data);
|
||
g_main_loop_run (data.loop);
|
||
|
||
g_app_info_reset_type_associations ("x-scheme-handler/glib-async");
|
||
|
||
data.expected_info = NULL;
|
||
g_app_info_get_default_for_uri_scheme_async ("glib-async", NULL,
|
||
on_default_for_uri_cb, &data);
|
||
g_main_loop_run (data.loop);
|
||
|
||
list = g_app_info_get_all_for_type ("application/x-test");
|
||
g_assert_null (list);
|
||
|
||
g_app_info_delete (info1);
|
||
g_app_info_delete (info2);
|
||
g_app_info_delete (info3);
|
||
|
||
g_object_unref (info1);
|
||
g_object_unref (info2);
|
||
g_object_unref (info3);
|
||
|
||
g_main_loop_unref (data.loop);
|
||
}
|
||
|
||
static void
|
||
test_fallback (void)
|
||
{
|
||
GAppInfo *info1, *info2, *app = NULL;
|
||
GList *apps, *recomm, *fallback, *list, *l, *m;
|
||
GError *error = NULL;
|
||
gint old_length;
|
||
|
||
info1 = create_app_info ("Test1");
|
||
info2 = create_app_info ("Test2");
|
||
|
||
g_assert_true (g_content_type_is_a ("text/x-python", "text/plain"));
|
||
|
||
apps = g_app_info_get_all_for_type ("text/x-python");
|
||
old_length = g_list_length (apps);
|
||
g_list_free_full (apps, g_object_unref);
|
||
|
||
g_app_info_add_supports_type (info1, "text/x-python", &error);
|
||
g_assert_no_error (error);
|
||
|
||
g_app_info_add_supports_type (info2, "text/plain", &error);
|
||
g_assert_no_error (error);
|
||
|
||
/* check that both apps are registered */
|
||
apps = g_app_info_get_all_for_type ("text/x-python");
|
||
g_assert_cmpint (g_list_length (apps), ==, old_length + 2);
|
||
|
||
/* check that Test1 is among the recommended apps */
|
||
recomm = g_app_info_get_recommended_for_type ("text/x-python");
|
||
g_assert_nonnull (recomm);
|
||
for (l = recomm; l; l = l->next)
|
||
{
|
||
app = l->data;
|
||
if (g_app_info_equal (info1, app))
|
||
break;
|
||
}
|
||
g_assert_nonnull (app);
|
||
g_assert_true (g_app_info_equal (info1, app));
|
||
|
||
/* and that Test2 is among the fallback apps */
|
||
fallback = g_app_info_get_fallback_for_type ("text/x-python");
|
||
g_assert_nonnull (fallback);
|
||
for (l = fallback; l; l = l->next)
|
||
{
|
||
app = l->data;
|
||
if (g_app_info_equal (info2, app))
|
||
break;
|
||
}
|
||
g_assert_cmpstr (g_app_info_get_name (app), ==, "Test2");
|
||
|
||
/* check that recomm + fallback = all applications */
|
||
list = g_list_concat (g_list_copy (recomm), g_list_copy (fallback));
|
||
g_assert_cmpuint (g_list_length (list), ==, g_list_length (apps));
|
||
|
||
for (l = list, m = apps; l != NULL && m != NULL; l = l->next, m = m->next)
|
||
{
|
||
g_assert_true (g_app_info_equal (l->data, m->data));
|
||
}
|
||
|
||
g_list_free (list);
|
||
|
||
g_list_free_full (apps, g_object_unref);
|
||
g_list_free_full (recomm, g_object_unref);
|
||
g_list_free_full (fallback, g_object_unref);
|
||
|
||
g_app_info_reset_type_associations ("text/x-python");
|
||
g_app_info_reset_type_associations ("text/plain");
|
||
|
||
g_app_info_delete (info1);
|
||
g_app_info_delete (info2);
|
||
|
||
g_object_unref (info1);
|
||
g_object_unref (info2);
|
||
}
|
||
|
||
static void
|
||
test_last_used (void)
|
||
{
|
||
GList *applications;
|
||
GAppInfo *info1, *info2, *default_app;
|
||
GError *error = NULL;
|
||
|
||
info1 = create_app_info ("Test1");
|
||
info2 = create_app_info ("Test2");
|
||
|
||
g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
g_app_info_add_supports_type (info2, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
applications = g_app_info_get_recommended_for_type ("application/x-test");
|
||
g_assert_cmpuint (g_list_length (applications), ==, 2);
|
||
|
||
/* the first should be the default app now */
|
||
g_assert_true (g_app_info_equal (g_list_nth_data (applications, 0), info1));
|
||
g_assert_true (g_app_info_equal (g_list_nth_data (applications, 1), info2));
|
||
|
||
g_list_free_full (applications, g_object_unref);
|
||
|
||
g_app_info_set_as_last_used_for_type (info2, "application/x-test", &error);
|
||
g_assert_no_error (error);
|
||
|
||
applications = g_app_info_get_recommended_for_type ("application/x-test");
|
||
g_assert_cmpuint (g_list_length (applications), ==, 2);
|
||
|
||
default_app = g_app_info_get_default_for_type ("application/x-test", FALSE);
|
||
g_assert_true (g_app_info_equal (default_app, info1));
|
||
|
||
/* the first should be the other app now */
|
||
g_assert_true (g_app_info_equal (g_list_nth_data (applications, 0), info2));
|
||
g_assert_true (g_app_info_equal (g_list_nth_data (applications, 1), info1));
|
||
|
||
g_list_free_full (applications, g_object_unref);
|
||
|
||
g_app_info_reset_type_associations ("application/x-test");
|
||
|
||
g_app_info_delete (info1);
|
||
g_app_info_delete (info2);
|
||
|
||
g_object_unref (info1);
|
||
g_object_unref (info2);
|
||
g_object_unref (default_app);
|
||
}
|
||
|
||
static void
|
||
test_extra_getters (void)
|
||
{
|
||
GDesktopAppInfo *appinfo;
|
||
const gchar *lang;
|
||
gchar *s;
|
||
gboolean b;
|
||
|
||
lang = setlocale (LC_ALL, NULL);
|
||
g_setenv ("LANGUAGE", "de_DE.UTF8", TRUE);
|
||
setlocale (LC_ALL, "");
|
||
|
||
appinfo = g_desktop_app_info_new_from_filename (g_test_get_filename (G_TEST_DIST, "appinfo-test-static.desktop", NULL));
|
||
g_assert_nonnull (appinfo);
|
||
|
||
g_assert_true (g_desktop_app_info_has_key (appinfo, "Terminal"));
|
||
g_assert_false (g_desktop_app_info_has_key (appinfo, "Bratwurst"));
|
||
|
||
s = g_desktop_app_info_get_string (appinfo, "StartupWMClass");
|
||
g_assert_cmpstr (s, ==, "appinfo-class");
|
||
g_free (s);
|
||
|
||
s = g_desktop_app_info_get_locale_string (appinfo, "X-JunkFood");
|
||
g_assert_cmpstr (s, ==, "Bratwurst");
|
||
g_free (s);
|
||
|
||
g_setenv ("LANGUAGE", "sv_SE.UTF8", TRUE);
|
||
setlocale (LC_ALL, "");
|
||
|
||
s = g_desktop_app_info_get_locale_string (appinfo, "X-JunkFood");
|
||
g_assert_cmpstr (s, ==, "Burger"); /* fallback */
|
||
g_free (s);
|
||
|
||
b = g_desktop_app_info_get_boolean (appinfo, "Terminal");
|
||
g_assert_true (b);
|
||
|
||
g_object_unref (appinfo);
|
||
|
||
g_setenv ("LANGUAGE", lang, TRUE);
|
||
setlocale (LC_ALL, "");
|
||
}
|
||
|
||
static void
|
||
wait_for_file (const gchar *want_this,
|
||
const gchar *but_not_this,
|
||
const gchar *or_this)
|
||
{
|
||
while (access (want_this, F_OK) != 0)
|
||
g_usleep (100000); /* 100ms */
|
||
|
||
g_assert_cmpuint (access (but_not_this, F_OK), !=, 0);
|
||
g_assert_cmpuint (access (or_this, F_OK), !=, 0);
|
||
|
||
unlink (want_this);
|
||
unlink (but_not_this);
|
||
unlink (or_this);
|
||
}
|
||
|
||
static void
|
||
test_actions (void)
|
||
{
|
||
const char *expected[] = { "frob", "tweak", "twiddle", "broken", NULL };
|
||
const gchar * const *actions;
|
||
GDesktopAppInfo *appinfo;
|
||
const gchar *tmpdir;
|
||
gchar *name;
|
||
gchar *frob_path;
|
||
gchar *tweak_path;
|
||
gchar *twiddle_path;
|
||
|
||
appinfo = g_desktop_app_info_new_from_filename (g_test_get_filename (G_TEST_DIST, "appinfo-test-actions.desktop", NULL));
|
||
g_assert_nonnull (appinfo);
|
||
|
||
actions = g_desktop_app_info_list_actions (appinfo);
|
||
g_assert_cmpstrv (actions, expected);
|
||
|
||
name = g_desktop_app_info_get_action_name (appinfo, "frob");
|
||
g_assert_cmpstr (name, ==, "Frobnicate");
|
||
g_free (name);
|
||
|
||
name = g_desktop_app_info_get_action_name (appinfo, "tweak");
|
||
g_assert_cmpstr (name, ==, "Tweak");
|
||
g_free (name);
|
||
|
||
name = g_desktop_app_info_get_action_name (appinfo, "twiddle");
|
||
g_assert_cmpstr (name, ==, "Twiddle");
|
||
g_free (name);
|
||
|
||
name = g_desktop_app_info_get_action_name (appinfo, "broken");
|
||
g_assert_nonnull (name);
|
||
g_assert_true (g_utf8_validate (name, -1, NULL));
|
||
g_free (name);
|
||
|
||
tmpdir = g_getenv ("G_TEST_TMPDIR");
|
||
g_assert_nonnull (tmpdir);
|
||
frob_path = g_build_filename (tmpdir, "frob", NULL);
|
||
tweak_path = g_build_filename (tmpdir, "tweak", NULL);
|
||
twiddle_path = g_build_filename (tmpdir, "twiddle", NULL);
|
||
|
||
g_assert_false (g_file_test (frob_path, G_FILE_TEST_EXISTS));
|
||
g_assert_false (g_file_test (tweak_path, G_FILE_TEST_EXISTS));
|
||
g_assert_false (g_file_test (twiddle_path, G_FILE_TEST_EXISTS));
|
||
|
||
g_desktop_app_info_launch_action (appinfo, "frob", NULL);
|
||
wait_for_file (frob_path, tweak_path, twiddle_path);
|
||
|
||
g_desktop_app_info_launch_action (appinfo, "tweak", NULL);
|
||
wait_for_file (tweak_path, frob_path, twiddle_path);
|
||
|
||
g_desktop_app_info_launch_action (appinfo, "twiddle", NULL);
|
||
wait_for_file (twiddle_path, frob_path, tweak_path);
|
||
|
||
g_free (frob_path);
|
||
g_free (tweak_path);
|
||
g_free (twiddle_path);
|
||
g_object_unref (appinfo);
|
||
}
|
||
|
||
static gchar *
|
||
run_apps (const gchar *command,
|
||
const gchar *arg,
|
||
gboolean with_usr,
|
||
gboolean with_home,
|
||
const gchar *locale_name,
|
||
const gchar *language,
|
||
const gchar *xdg_current_desktop)
|
||
{
|
||
gboolean success;
|
||
gchar **envp;
|
||
gchar **argv;
|
||
gint status;
|
||
gchar *out;
|
||
gchar *argv_str = NULL;
|
||
|
||
argv = g_new (gchar *, 4);
|
||
argv[0] = g_test_build_filename (G_TEST_BUILT, "apps", NULL);
|
||
argv[1] = g_strdup (command);
|
||
argv[2] = g_strdup (arg);
|
||
argv[3] = NULL;
|
||
|
||
g_assert_true (g_file_test (argv[0], G_FILE_TEST_IS_EXECUTABLE));
|
||
envp = g_get_environ ();
|
||
|
||
if (with_usr)
|
||
{
|
||
gchar *tmp = g_test_build_filename (G_TEST_DIST, "desktop-files", "usr", NULL);
|
||
envp = g_environ_setenv (envp, "XDG_DATA_DIRS", tmp, TRUE);
|
||
g_free (tmp);
|
||
}
|
||
else
|
||
envp = g_environ_setenv (envp, "XDG_DATA_DIRS", "/does-not-exist", TRUE);
|
||
|
||
if (with_home)
|
||
{
|
||
gchar *tmp = g_test_build_filename (G_TEST_DIST, "desktop-files", "home", NULL);
|
||
envp = g_environ_setenv (envp, "XDG_DATA_HOME", tmp, TRUE);
|
||
g_free (tmp);
|
||
}
|
||
else
|
||
envp = g_environ_setenv (envp, "XDG_DATA_HOME", "/does-not-exist", TRUE);
|
||
|
||
if (locale_name)
|
||
envp = g_environ_setenv (envp, "LC_ALL", locale_name, TRUE);
|
||
else
|
||
envp = g_environ_setenv (envp, "LC_ALL", "C", TRUE);
|
||
|
||
if (language)
|
||
envp = g_environ_setenv (envp, "LANGUAGE", language, TRUE);
|
||
else
|
||
envp = g_environ_unsetenv (envp, "LANGUAGE");
|
||
|
||
if (xdg_current_desktop)
|
||
envp = g_environ_setenv (envp, "XDG_CURRENT_DESKTOP", xdg_current_desktop, TRUE);
|
||
else
|
||
envp = g_environ_unsetenv (envp, "XDG_CURRENT_DESKTOP");
|
||
|
||
envp = g_environ_setenv (envp, "G_MESSAGES_DEBUG", "", TRUE);
|
||
|
||
success = g_spawn_sync (NULL, argv, envp, 0, NULL, NULL, &out, NULL, &status, NULL);
|
||
g_assert_true (success);
|
||
g_assert_cmpuint (status, ==, 0);
|
||
|
||
argv_str = g_strjoinv (" ", argv);
|
||
g_test_message ("%s: `%s` returned: %s", G_STRFUNC, argv_str, out);
|
||
g_free (argv_str);
|
||
|
||
g_strfreev (envp);
|
||
g_strfreev (argv);
|
||
|
||
return out;
|
||
}
|
||
|
||
static void
|
||
assert_strings_equivalent (const gchar *expected,
|
||
const gchar *result)
|
||
{
|
||
gchar **expected_words;
|
||
gchar **result_words;
|
||
gint i, j;
|
||
|
||
expected_words = g_strsplit (expected, " ", 0);
|
||
result_words = g_strsplit_set (result, " \n", 0);
|
||
|
||
for (i = 0; expected_words[i]; i++)
|
||
{
|
||
for (j = 0; result_words[j]; j++)
|
||
if (g_str_equal (expected_words[i], result_words[j]))
|
||
goto got_it;
|
||
|
||
g_test_fail_printf ("Unable to find expected string '%s' in result '%s'", expected_words[i], result);
|
||
|
||
got_it:
|
||
continue;
|
||
}
|
||
|
||
g_assert_cmpint (g_strv_length (expected_words), ==, g_strv_length (result_words));
|
||
g_strfreev (expected_words);
|
||
g_strfreev (result_words);
|
||
}
|
||
|
||
static void
|
||
assert_list (const gchar *expected,
|
||
gboolean with_usr,
|
||
gboolean with_home,
|
||
const gchar *locale_name,
|
||
const gchar *language)
|
||
{
|
||
gchar *result;
|
||
|
||
result = run_apps ("list", NULL, with_usr, with_home, locale_name, language, NULL);
|
||
g_strchomp (result);
|
||
assert_strings_equivalent (expected, result);
|
||
g_free (result);
|
||
}
|
||
|
||
static void
|
||
assert_info (const gchar *desktop_id,
|
||
const gchar *expected,
|
||
gboolean with_usr,
|
||
gboolean with_home,
|
||
const gchar *locale_name,
|
||
const gchar *language)
|
||
{
|
||
gchar *result;
|
||
|
||
result = run_apps ("show-info", desktop_id, with_usr, with_home, locale_name, language, NULL);
|
||
g_assert_cmpstr (result, ==, expected);
|
||
g_free (result);
|
||
}
|
||
|
||
static void
|
||
assert_search (const gchar *search_string,
|
||
const gchar *expected,
|
||
gboolean with_usr,
|
||
gboolean with_home,
|
||
const gchar *locale_name,
|
||
const gchar *language)
|
||
{
|
||
gchar **expected_lines;
|
||
gchar **result_lines;
|
||
gchar *result;
|
||
gint i;
|
||
|
||
expected_lines = g_strsplit (expected, "\n", -1);
|
||
result = run_apps ("search", search_string, with_usr, with_home, locale_name, language, NULL);
|
||
result_lines = g_strsplit (result, "\n", -1);
|
||
g_assert_cmpint (g_strv_length (expected_lines), ==, g_strv_length (result_lines));
|
||
for (i = 0; expected_lines[i]; i++)
|
||
assert_strings_equivalent (expected_lines[i], result_lines[i]);
|
||
g_strfreev (expected_lines);
|
||
g_strfreev (result_lines);
|
||
g_free (result);
|
||
}
|
||
|
||
static void
|
||
assert_implementations (const gchar *interface,
|
||
const gchar *expected,
|
||
gboolean with_usr,
|
||
gboolean with_home)
|
||
{
|
||
gchar *result;
|
||
|
||
result = run_apps ("implementations", interface, with_usr, with_home, NULL, NULL, NULL);
|
||
g_strchomp (result);
|
||
assert_strings_equivalent (expected, result);
|
||
g_free (result);
|
||
}
|
||
|
||
#define ALL_USR_APPS "evince-previewer.desktop nautilus-classic.desktop gnome-font-viewer.desktop " \
|
||
"baobab.desktop yelp.desktop eog.desktop cheese.desktop org.gnome.clocks.desktop " \
|
||
"gnome-contacts.desktop kde4-kate.desktop gcr-prompter.desktop totem.desktop " \
|
||
"gnome-terminal.desktop nautilus-autorun-software.desktop gcr-viewer.desktop " \
|
||
"nautilus-connect-server.desktop kde4-dolphin.desktop gnome-music.desktop " \
|
||
"kde4-konqbrowser.desktop gucharmap.desktop kde4-okular.desktop nautilus.desktop " \
|
||
"gedit.desktop evince.desktop file-roller.desktop dconf-editor.desktop glade.desktop " \
|
||
"invalid-desktop.desktop"
|
||
#define HOME_APPS "epiphany-weather-for-toronto-island-9c6a4e022b17686306243dada811d550d25eb1fb.desktop"
|
||
#define ALL_HOME_APPS HOME_APPS " eog.desktop"
|
||
|
||
static void
|
||
test_search (void)
|
||
{
|
||
assert_list ("", FALSE, FALSE, NULL, NULL);
|
||
assert_list (ALL_USR_APPS, TRUE, FALSE, NULL, NULL);
|
||
assert_list (ALL_HOME_APPS, FALSE, TRUE, NULL, NULL);
|
||
assert_list (ALL_USR_APPS " " HOME_APPS, TRUE, TRUE, NULL, NULL);
|
||
|
||
/* The user has "installed" their own version of eog.desktop which
|
||
* calls it "Eye of GNOME". Do some testing based on that.
|
||
*
|
||
* We should always find "Pictures" keyword no matter where we look.
|
||
*/
|
||
assert_search ("Picture", "eog.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
assert_search ("Picture", "eog.desktop\n", TRUE, FALSE, NULL, NULL);
|
||
assert_search ("Picture", "eog.desktop\n", FALSE, TRUE, NULL, NULL);
|
||
assert_search ("Picture", "", FALSE, FALSE, NULL, NULL);
|
||
|
||
/* We should only find it called "eye of gnome" when using the user's
|
||
* directory.
|
||
*/
|
||
assert_search ("eye gnome", "", TRUE, FALSE, NULL, NULL);
|
||
assert_search ("eye gnome", "eog.desktop\n", FALSE, TRUE, NULL, NULL);
|
||
assert_search ("eye gnome", "eog.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* We should only find it called "image viewer" when _not_ using the
|
||
* user's directory.
|
||
*/
|
||
assert_search ("image viewer", "eog.desktop\n", TRUE, FALSE, NULL, NULL);
|
||
assert_search ("image viewer", "", FALSE, TRUE, NULL, NULL);
|
||
assert_search ("image viewer", "", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* There're "flatpak" apps (clocks) installed as well - they should *not*
|
||
* match the prefix command ("/bin/sh") in the Exec= line though. Then with
|
||
* substring matching, Image Viewer (eog) should be in next group because it
|
||
* contains "Slideshow" in its keywords.
|
||
*/
|
||
assert_search ("sh", "gnome-terminal.desktop\n"
|
||
"eog.desktop\n", TRUE, FALSE, NULL, NULL);
|
||
|
||
/* "frobnicator.desktop" is ignored by get_all() because the binary is
|
||
* missing, but search should still find it (to avoid either stale results
|
||
* from the cache or expensive stat() calls for each potential result)
|
||
*/
|
||
assert_search ("frobni", "frobnicator.desktop\n", TRUE, FALSE, NULL, NULL);
|
||
|
||
/* Obvious multi-word search */
|
||
assert_search ("doc hel", "yelp.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* Repeated search terms should do nothing... */
|
||
assert_search ("files file fil fi f", "nautilus.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* "con" will match "connect" and "contacts" on name with prefix match in
|
||
* first group, then second group is a Keyword prefix match for "configuration" in dconf-editor.desktop
|
||
* and third group is a substring match for "Desktop Icons" in Name of nautilus-classic.desktop.
|
||
*/
|
||
assert_search ("con", "gnome-contacts.desktop nautilus-connect-server.desktop\n"
|
||
"dconf-editor.desktop\n"
|
||
"nautilus-classic.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* "gnome" will match "eye of gnome" from the user's directory, plus
|
||
* matching "GNOME Clocks" X-GNOME-FullName.
|
||
*/
|
||
assert_search ("gnome", "eog.desktop\n"
|
||
"org.gnome.clocks.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* eog has exec name 'false' in usr only */
|
||
assert_search ("false", "eog.desktop\n", TRUE, FALSE, NULL, NULL);
|
||
assert_search ("false", "", FALSE, TRUE, NULL, NULL);
|
||
assert_search ("false", "", TRUE, TRUE, NULL, NULL);
|
||
assert_search ("false", "", FALSE, FALSE, NULL, NULL);
|
||
|
||
/* make sure we only search the first component */
|
||
assert_search ("nonsearchable", "", TRUE, FALSE, NULL, NULL);
|
||
|
||
/* "gnome con" will match only gnome contacts; via the name for
|
||
* "contacts" and keywords for "friend"
|
||
*/
|
||
assert_search ("friend con", "gnome-contacts.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* make sure we get the correct kde4- prefix on the application IDs
|
||
* from subdirectories
|
||
*/
|
||
assert_search ("konq", "kde4-konqbrowser.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
assert_search ("kate", "kde4-kate.desktop\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* make sure we can look up apps by name properly */
|
||
assert_info ("kde4-kate.desktop",
|
||
"kde4-kate.desktop\n"
|
||
"Kate\n"
|
||
"Kate\n"
|
||
"nil\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
assert_info ("nautilus.desktop",
|
||
"nautilus.desktop\n"
|
||
"Files\n"
|
||
"Files\n"
|
||
"Access and organize files\n", TRUE, TRUE, NULL, NULL);
|
||
|
||
/* make sure localised searching works properly */
|
||
assert_search ("foliumi", "nautilus.desktop\n"
|
||
"kde4-konqbrowser.desktop\n", TRUE, FALSE, "en_US.UTF-8", "eo");
|
||
/* the user's eog.desktop has no translations... */
|
||
assert_search ("foliumi", "nautilus.desktop\n"
|
||
"kde4-konqbrowser.desktop\n", TRUE, TRUE, "en_US.UTF-8", "eo");
|
||
}
|
||
|
||
static void
|
||
test_implements (void)
|
||
{
|
||
/* Make sure we can find our search providers... */
|
||
assert_implementations ("org.gnome.Shell.SearchProvider2",
|
||
"gnome-music.desktop gnome-contacts.desktop eog.desktop",
|
||
TRUE, FALSE);
|
||
|
||
/* And our image acquisition possibilities... */
|
||
assert_implementations ("org.freedesktop.ImageProvider",
|
||
"cheese.desktop",
|
||
TRUE, FALSE);
|
||
|
||
/* Make sure the user's eog is properly masking the system one */
|
||
assert_implementations ("org.gnome.Shell.SearchProvider2",
|
||
"gnome-music.desktop gnome-contacts.desktop",
|
||
TRUE, TRUE);
|
||
|
||
/* Make sure we get nothing if we have nothing */
|
||
assert_implementations ("org.gnome.Shell.SearchProvider2", "", FALSE, FALSE);
|
||
}
|
||
|
||
static void
|
||
assert_shown (const gchar *desktop_id,
|
||
gboolean expected,
|
||
const gchar *xdg_current_desktop)
|
||
{
|
||
gchar *result;
|
||
|
||
result = run_apps ("should-show", desktop_id, TRUE, TRUE, NULL, NULL, xdg_current_desktop);
|
||
g_assert_cmpstr (result, ==, expected ? "true\n" : "false\n");
|
||
g_free (result);
|
||
}
|
||
|
||
static void
|
||
test_show_in (void)
|
||
{
|
||
assert_shown ("gcr-prompter.desktop", FALSE, NULL);
|
||
assert_shown ("gcr-prompter.desktop", FALSE, "GNOME");
|
||
assert_shown ("gcr-prompter.desktop", FALSE, "KDE");
|
||
assert_shown ("gcr-prompter.desktop", FALSE, "GNOME:GNOME-Classic");
|
||
assert_shown ("gcr-prompter.desktop", TRUE, "GNOME-Classic:GNOME");
|
||
assert_shown ("gcr-prompter.desktop", TRUE, "GNOME-Classic");
|
||
assert_shown ("gcr-prompter.desktop", TRUE, "GNOME-Classic:KDE");
|
||
assert_shown ("gcr-prompter.desktop", TRUE, "KDE:GNOME-Classic");
|
||
assert_shown ("invalid-desktop.desktop", TRUE, "GNOME");
|
||
assert_shown ("invalid-desktop.desktop", FALSE, "../invalid/desktop");
|
||
assert_shown ("invalid-desktop.desktop", FALSE, "../invalid/desktop:../invalid/desktop");
|
||
}
|
||
|
||
static void
|
||
on_launch_started (GAppLaunchContext *context, GAppInfo *info, GVariant *platform_data, gpointer data)
|
||
{
|
||
gboolean *invoked = data;
|
||
|
||
g_assert_true (G_IS_APP_LAUNCH_CONTEXT (context));
|
||
|
||
if (TEST_IS_LAUNCH_CONTEXT (context))
|
||
{
|
||
GVariantDict dict;
|
||
const char *sni;
|
||
char *expected_sni;
|
||
|
||
g_assert_nonnull (platform_data);
|
||
g_variant_dict_init (&dict, platform_data);
|
||
g_assert_true (
|
||
g_variant_dict_lookup (&dict, "startup-notification-id", "&s", &sni));
|
||
expected_sni = g_app_launch_context_get_startup_notify_id (context, info, NULL);
|
||
g_assert_cmpstr (sni, ==, expected_sni);
|
||
|
||
g_free (expected_sni);
|
||
g_variant_dict_clear (&dict);
|
||
}
|
||
else
|
||
{
|
||
/* Our default context doesn't fill in any platform data */
|
||
g_assert_null (platform_data);
|
||
}
|
||
|
||
g_assert_false (*invoked);
|
||
*invoked = TRUE;
|
||
}
|
||
|
||
static void
|
||
on_launched (GAppLaunchContext *context, GAppInfo *info, GVariant *platform_data, gpointer data)
|
||
{
|
||
gboolean *launched = data;
|
||
GVariantDict dict;
|
||
int pid;
|
||
|
||
g_assert_true (G_IS_APP_LAUNCH_CONTEXT (context));
|
||
g_assert_true (G_IS_APP_INFO (info));
|
||
g_assert_nonnull (platform_data);
|
||
g_variant_dict_init (&dict, platform_data);
|
||
g_assert_true (g_variant_dict_lookup (&dict, "pid", "i", &pid, NULL));
|
||
g_assert_cmpint (pid, >, 1);
|
||
|
||
g_assert_false (*launched);
|
||
*launched = TRUE;
|
||
|
||
g_variant_dict_clear (&dict);
|
||
}
|
||
|
||
static void
|
||
on_launch_failed (GAppLaunchContext *context, const char *startup_notify_id, gpointer data)
|
||
{
|
||
gboolean *invoked = data;
|
||
|
||
g_assert_true (G_IS_APP_LAUNCH_CONTEXT (context));
|
||
g_assert_nonnull (startup_notify_id);
|
||
g_test_message ("Application launch failed: %s", startup_notify_id);
|
||
|
||
g_assert_false (*invoked);
|
||
*invoked = TRUE;
|
||
}
|
||
|
||
/* Test g_desktop_app_info_launch_uris_as_manager() and
|
||
* g_desktop_app_info_launch_uris_as_manager_with_fds()
|
||
*/
|
||
static void
|
||
test_launch_as_manager (void)
|
||
{
|
||
GDesktopAppInfo *appinfo;
|
||
GError *error = NULL;
|
||
gboolean retval;
|
||
const gchar *path;
|
||
gboolean invoked = FALSE;
|
||
gboolean launched = FALSE;
|
||
gboolean failed = FALSE;
|
||
GAppLaunchContext *context;
|
||
|
||
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
|
||
appinfo = g_desktop_app_info_new_from_filename (path);
|
||
g_assert_true (G_IS_APP_INFO (appinfo));
|
||
|
||
context = g_object_new (test_launch_context_get_type (), NULL);
|
||
g_signal_connect (context, "launch-started",
|
||
G_CALLBACK (on_launch_started),
|
||
&invoked);
|
||
g_signal_connect (context, "launched",
|
||
G_CALLBACK (on_launched),
|
||
&launched);
|
||
g_signal_connect (context, "launch-failed",
|
||
G_CALLBACK (on_launch_failed),
|
||
&failed);
|
||
retval = g_desktop_app_info_launch_uris_as_manager (appinfo, NULL, context, 0,
|
||
NULL, NULL,
|
||
NULL, NULL,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
g_assert_true (retval);
|
||
g_assert_true (invoked);
|
||
g_assert_true (launched);
|
||
g_assert_false (failed);
|
||
|
||
invoked = FALSE;
|
||
launched = FALSE;
|
||
failed = FALSE;
|
||
retval = g_desktop_app_info_launch_uris_as_manager_with_fds (appinfo,
|
||
NULL, context, 0,
|
||
NULL, NULL,
|
||
NULL, NULL,
|
||
-1, -1, -1,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
g_assert_true (retval);
|
||
g_assert_true (invoked);
|
||
g_assert_true (launched);
|
||
g_assert_false (failed);
|
||
|
||
g_object_unref (appinfo);
|
||
g_assert_finalize_object (context);
|
||
}
|
||
|
||
static void
|
||
test_launch_as_manager_fail (void)
|
||
{
|
||
GAppLaunchContext *context;
|
||
GDesktopAppInfo *appinfo;
|
||
GError *error = NULL;
|
||
gboolean retval;
|
||
const gchar *path;
|
||
gboolean launch_started = FALSE;
|
||
gboolean launched = FALSE;
|
||
gboolean failed = FALSE;
|
||
|
||
g_test_summary ("Tests that launch-errors are properly handled, we force " \
|
||
"this by using invalid FD's values when launching as manager");
|
||
|
||
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
|
||
appinfo = g_desktop_app_info_new_from_filename (path);
|
||
g_assert_true (G_IS_APP_INFO (appinfo));
|
||
|
||
context = g_object_new (test_launch_context_get_type (), NULL);
|
||
g_signal_connect (context, "launch-started",
|
||
G_CALLBACK (on_launch_started),
|
||
&launch_started);
|
||
g_signal_connect (context, "launched",
|
||
G_CALLBACK (on_launched),
|
||
&launched);
|
||
g_signal_connect (context, "launch-failed",
|
||
G_CALLBACK (on_launch_failed),
|
||
&failed);
|
||
|
||
retval = g_desktop_app_info_launch_uris_as_manager_with_fds (appinfo,
|
||
NULL, context, 0,
|
||
NULL, NULL,
|
||
NULL, NULL,
|
||
3000, 3001, 3002,
|
||
&error);
|
||
g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED);
|
||
g_assert_false (retval);
|
||
g_assert_true (launch_started);
|
||
g_assert_false (launched);
|
||
g_assert_true (failed);
|
||
|
||
g_clear_error (&error);
|
||
g_object_unref (appinfo);
|
||
g_assert_finalize_object (context);
|
||
}
|
||
|
||
static GAppInfo *
|
||
create_app_info_toucher (const char *name,
|
||
const char *touched_file_name,
|
||
const char *handled_type,
|
||
char **out_file_path)
|
||
{
|
||
GError *error = NULL;
|
||
GAppInfo *info;
|
||
gchar *command_line;
|
||
gchar *file_path;
|
||
gchar *tmpdir;
|
||
|
||
g_assert_nonnull (out_file_path);
|
||
|
||
tmpdir = g_dir_make_tmp ("desktop-app-info-launch-XXXXXX", &error);
|
||
g_assert_no_error (error);
|
||
|
||
file_path = g_build_filename (tmpdir, touched_file_name, NULL);
|
||
command_line = g_strdup_printf ("touch %s", file_path);
|
||
|
||
info = create_command_line_app_info (name, command_line, handled_type);
|
||
*out_file_path = g_steal_pointer (&file_path);
|
||
|
||
g_free (tmpdir);
|
||
g_free (command_line);
|
||
|
||
return info;
|
||
}
|
||
|
||
static void
|
||
test_default_uri_handler (void)
|
||
{
|
||
GError *error = NULL;
|
||
gchar *file_path = NULL;
|
||
GAppInfo *info;
|
||
|
||
info = create_app_info_toucher ("Touch Handled", "handled",
|
||
"x-scheme-handler/glib-touch",
|
||
&file_path);
|
||
g_assert_true (G_IS_APP_INFO (info));
|
||
g_assert_nonnull (file_path);
|
||
|
||
g_assert_true (g_app_info_launch_default_for_uri ("glib-touch://touch-me",
|
||
NULL, &error));
|
||
g_assert_no_error (error);
|
||
|
||
while (!g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
|
||
g_assert_true (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
|
||
|
||
g_assert_false (g_app_info_launch_default_for_uri ("glib-INVALID-touch://touch-me",
|
||
NULL, &error));
|
||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
|
||
g_clear_error (&error);
|
||
|
||
g_object_unref (info);
|
||
g_free (file_path);
|
||
}
|
||
|
||
static void
|
||
on_launch_default_for_uri_success_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
GError *error = NULL;
|
||
gboolean *called = user_data;
|
||
|
||
g_assert_true (g_app_info_launch_default_for_uri_finish (result, &error));
|
||
g_assert_no_error (error);
|
||
|
||
*called = TRUE;
|
||
}
|
||
|
||
static void
|
||
on_launch_default_for_uri_not_found_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
GError *error = NULL;
|
||
GMainLoop *loop = user_data;
|
||
|
||
g_assert_false (g_app_info_launch_default_for_uri_finish (result, &error));
|
||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
|
||
g_clear_error (&error);
|
||
|
||
g_main_loop_quit (loop);
|
||
}
|
||
|
||
static void
|
||
on_launch_default_for_uri_cancelled_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
GError *error = NULL;
|
||
GMainLoop *loop = user_data;
|
||
|
||
g_assert_false (g_app_info_launch_default_for_uri_finish (result, &error));
|
||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
|
||
g_clear_error (&error);
|
||
|
||
g_main_loop_quit (loop);
|
||
}
|
||
|
||
static void
|
||
test_default_uri_handler_async (void)
|
||
{
|
||
GCancellable *cancellable;
|
||
gchar *file_path = NULL;
|
||
GAppInfo *info;
|
||
GMainLoop *loop;
|
||
gboolean called = FALSE;
|
||
gint64 start_time, touch_time;
|
||
|
||
loop = g_main_loop_new (NULL, FALSE);
|
||
info = create_app_info_toucher ("Touch Handled", "handled-async",
|
||
"x-scheme-handler/glib-async-touch",
|
||
&file_path);
|
||
g_assert_true (G_IS_APP_INFO (info));
|
||
g_assert_nonnull (file_path);
|
||
|
||
start_time = g_get_real_time ();
|
||
g_app_info_launch_default_for_uri_async ("glib-async-touch://touch-me", NULL,
|
||
NULL,
|
||
on_launch_default_for_uri_success_cb,
|
||
&called);
|
||
|
||
while (!g_file_test (file_path, G_FILE_TEST_IS_REGULAR) || !called)
|
||
g_main_context_iteration (NULL, FALSE);
|
||
|
||
touch_time = g_get_real_time () - start_time;
|
||
g_assert_true (called);
|
||
g_assert_true (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
|
||
|
||
g_unlink (file_path);
|
||
g_assert_false (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
|
||
|
||
g_app_info_launch_default_for_uri_async ("glib-async-INVALID-touch://touch-me",
|
||
NULL, NULL,
|
||
on_launch_default_for_uri_not_found_cb,
|
||
loop);
|
||
g_main_loop_run (loop);
|
||
|
||
cancellable = g_cancellable_new ();
|
||
g_app_info_launch_default_for_uri_async ("glib-async-touch://touch-me", NULL,
|
||
cancellable,
|
||
on_launch_default_for_uri_cancelled_cb,
|
||
loop);
|
||
g_cancellable_cancel (cancellable);
|
||
g_main_loop_run (loop);
|
||
|
||
/* If started, our touch app would take some time to actually write the
|
||
* file to disk, so let's wait a bit here to ensure that the file isn't
|
||
* inadvertently getting created when a launch operation is canceled up
|
||
* front. Give it 3× as long as the successful case took, to allow for
|
||
* some variance.
|
||
*/
|
||
g_usleep (touch_time * 3);
|
||
g_assert_false (g_file_test (file_path, G_FILE_TEST_IS_REGULAR));
|
||
|
||
g_object_unref (info);
|
||
g_main_loop_unref (loop);
|
||
g_free (file_path);
|
||
}
|
||
|
||
/* Test if Desktop-File Id is correctly formed */
|
||
static void
|
||
test_id (void)
|
||
{
|
||
gchar *result;
|
||
|
||
result = run_apps ("default-for-type", "application/vnd.kde.okular-archive",
|
||
TRUE, FALSE, NULL, NULL, NULL);
|
||
g_assert_cmpstr (result, ==, "kde4-okular.desktop\n");
|
||
g_free (result);
|
||
}
|
||
|
||
static const char *
|
||
get_terminal_divider (const char *terminal_name)
|
||
{
|
||
if (g_str_equal (terminal_name, "xdg-terminal-exec"))
|
||
return NULL;
|
||
if (g_str_equal (terminal_name, "kgx"))
|
||
return "-e";
|
||
if (g_str_equal (terminal_name, "gnome-terminal"))
|
||
return "--";
|
||
if (g_str_equal (terminal_name, "tilix"))
|
||
return "-e";
|
||
if (g_str_equal (terminal_name, "konsole"))
|
||
return "-e";
|
||
if (g_str_equal (terminal_name, "nxterm"))
|
||
return "-e";
|
||
if (g_str_equal (terminal_name, "color-xterm"))
|
||
return "-e";
|
||
if (g_str_equal (terminal_name, "rxvt"))
|
||
return "-e";
|
||
if (g_str_equal (terminal_name, "dtterm"))
|
||
return "-e";
|
||
if (g_str_equal (terminal_name, "xterm"))
|
||
return "-e";
|
||
if (g_str_equal (terminal_name, "mate-terminal"))
|
||
return "-x";
|
||
if (g_str_equal (terminal_name, "xfce4-terminal"))
|
||
return "-x";
|
||
|
||
g_return_val_if_reached (NULL);
|
||
}
|
||
|
||
typedef enum {
|
||
TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE,
|
||
TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT,
|
||
TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH,
|
||
} TerminalLaunchType;
|
||
|
||
typedef struct {
|
||
const char *exec;
|
||
TerminalLaunchType type;
|
||
} TerminalLaunchData;
|
||
|
||
static TerminalLaunchData *
|
||
terminal_launch_data_new (const char *exec, TerminalLaunchType type)
|
||
{
|
||
TerminalLaunchData *d = NULL;
|
||
|
||
d = g_new0 (TerminalLaunchData, 1);
|
||
d->exec = exec;
|
||
d->type = type;
|
||
|
||
return d;
|
||
}
|
||
|
||
static void
|
||
test_launch_uris_with_terminal (gconstpointer data)
|
||
{
|
||
int fd;
|
||
int ret;
|
||
int flags;
|
||
int terminal_divider_arg_length;
|
||
const TerminalLaunchData *launch_data = data;
|
||
const char *terminal_exec = launch_data->exec;
|
||
char *old_path = NULL;
|
||
char *command_line;
|
||
char *bin_path;
|
||
char *terminal_path;
|
||
char *output_fd_path;
|
||
char *script_contents;
|
||
char *output_contents = NULL;
|
||
char *sh;
|
||
GAppInfo *app_info;
|
||
GList *uris;
|
||
GList *paths;
|
||
GStrv output_args;
|
||
GError *error = NULL;
|
||
GInputStream *input_stream;
|
||
GDataInputStream *data_input_stream;
|
||
GAppLaunchContext *launch_context;
|
||
|
||
sh = g_find_program_in_path ("sh");
|
||
g_assert_nonnull (sh);
|
||
|
||
bin_path = g_dir_make_tmp ("bin-path-XXXXXX", &error);
|
||
g_assert_no_error (error);
|
||
|
||
launch_context = g_object_new (test_launch_context_get_type (), NULL);
|
||
|
||
switch (launch_data->type)
|
||
{
|
||
case TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE:
|
||
old_path = g_strdup (g_getenv ("PATH"));
|
||
g_assert_true (g_setenv ("PATH", bin_path, TRUE));
|
||
break;
|
||
|
||
case TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT:
|
||
g_app_launch_context_setenv (launch_context, "PATH", bin_path);
|
||
break;
|
||
|
||
case TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH:
|
||
g_app_launch_context_setenv (launch_context, "PATH", "/not/valid");
|
||
break;
|
||
|
||
default:
|
||
g_assert_not_reached ();
|
||
}
|
||
|
||
terminal_path = g_build_filename (bin_path, terminal_exec, NULL);
|
||
output_fd_path = g_build_filename (bin_path, "fifo", NULL);
|
||
|
||
ret = mkfifo (output_fd_path, 0600);
|
||
g_assert_cmpint (ret, ==, 0);
|
||
|
||
fd = g_open (output_fd_path, O_RDONLY | O_CLOEXEC | O_NONBLOCK, 0);
|
||
g_assert_cmpint (fd, >=, 0);
|
||
|
||
flags = fcntl (fd, F_GETFL);
|
||
g_assert_cmpint (flags, >=, 0);
|
||
|
||
ret = fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
|
||
g_assert_cmpint (ret, ==, 0);
|
||
|
||
input_stream = g_unix_input_stream_new (fd, TRUE);
|
||
data_input_stream = g_data_input_stream_new (input_stream);
|
||
script_contents = g_strdup_printf ("#!%s\n" \
|
||
"out='%s'\n"
|
||
"printf '%%s\\n' \"$*\" > \"$out\"\n",
|
||
sh,
|
||
output_fd_path);
|
||
g_file_set_contents (terminal_path, script_contents, -1, &error);
|
||
g_assert_no_error (error);
|
||
g_assert_cmpint (g_chmod (terminal_path, 0500), ==, 0);
|
||
|
||
g_test_message ("Fake '%s' terminal created as: %s", terminal_exec, terminal_path);
|
||
|
||
command_line = g_strdup_printf ("true %s-argument", terminal_exec);
|
||
|
||
if (launch_data->type == TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH)
|
||
{
|
||
GKeyFile *key_file;
|
||
char *key_file_contents;
|
||
const char base_file[] =
|
||
"[Desktop Entry]\n"
|
||
"Type=Application\n"
|
||
"Name=terminal launched app\n"
|
||
"Terminal=true\n"
|
||
"Path=%s\n"
|
||
"Exec=%s\n";
|
||
|
||
key_file = g_key_file_new ();
|
||
key_file_contents = g_strdup_printf (base_file, bin_path, command_line);
|
||
|
||
g_assert_true (
|
||
g_key_file_load_from_data (key_file, key_file_contents, -1,
|
||
G_KEY_FILE_NONE, NULL));
|
||
|
||
app_info = (GAppInfo*) g_desktop_app_info_new_from_keyfile (key_file);
|
||
g_assert_true (G_IS_DESKTOP_APP_INFO (app_info));
|
||
g_assert_true (
|
||
g_desktop_app_info_get_boolean (G_DESKTOP_APP_INFO (app_info), "Terminal"));
|
||
|
||
g_key_file_unref (key_file);
|
||
g_free (key_file_contents);
|
||
}
|
||
else
|
||
{
|
||
app_info = g_app_info_create_from_commandline (command_line,
|
||
"Test App on Terminal",
|
||
G_APP_INFO_CREATE_NEEDS_TERMINAL |
|
||
G_APP_INFO_CREATE_SUPPORTS_URIS,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
}
|
||
|
||
paths = g_list_prepend (NULL, bin_path);
|
||
uris = g_list_prepend (NULL, g_filename_to_uri (bin_path, NULL, &error));
|
||
g_assert_no_error (error);
|
||
|
||
paths = g_list_prepend (paths, (gpointer) g_get_user_data_dir ());
|
||
uris = g_list_append (uris, g_filename_to_uri (g_get_user_data_dir (), NULL, &error));
|
||
g_assert_no_error (error);
|
||
|
||
g_assert_cmpint (g_list_length (paths), ==, 2);
|
||
g_app_info_launch_uris (app_info, uris, launch_context, &error);
|
||
g_assert_no_error (error);
|
||
|
||
while (output_contents == NULL)
|
||
{
|
||
output_contents =
|
||
g_data_input_stream_read_upto (data_input_stream, "\n", 1, NULL, NULL, &error);
|
||
g_assert_no_error (error);
|
||
|
||
if (output_contents == NULL)
|
||
g_usleep (G_USEC_PER_SEC / 10);
|
||
}
|
||
g_test_message ("'%s' called with arguments: '%s'", terminal_exec, output_contents);
|
||
|
||
g_data_input_stream_read_byte (data_input_stream, NULL, &error);
|
||
g_assert_no_error (error);
|
||
|
||
output_args = g_strsplit (output_contents, " ", -1);
|
||
g_clear_pointer (&output_contents, g_free);
|
||
|
||
terminal_divider_arg_length = (get_terminal_divider (terminal_exec) != NULL) ? 1 : 0;
|
||
g_assert_cmpuint (g_strv_length (output_args), ==, 3 + terminal_divider_arg_length);
|
||
if (terminal_divider_arg_length == 1)
|
||
{
|
||
g_assert_cmpstr (output_args[0], ==, get_terminal_divider (terminal_exec));
|
||
g_assert_cmpstr (output_args[1], ==, "true");
|
||
g_assert_cmpstr (output_args[2], ==, command_line + 5);
|
||
}
|
||
else
|
||
{
|
||
g_assert_cmpstr (output_args[0], ==, "true");
|
||
g_assert_cmpstr (output_args[1], ==, command_line + 5);
|
||
}
|
||
paths = g_list_delete_link (paths,
|
||
g_list_find_custom (paths, output_args[2 + terminal_divider_arg_length], g_str_equal));
|
||
g_assert_cmpint (g_list_length (paths), ==, 1);
|
||
g_clear_pointer (&output_args, g_strfreev);
|
||
|
||
while (output_contents == NULL)
|
||
{
|
||
output_contents =
|
||
g_data_input_stream_read_upto (data_input_stream, "\n", 1, NULL, NULL, &error);
|
||
g_assert_no_error (error);
|
||
|
||
if (output_contents == NULL)
|
||
g_usleep (G_USEC_PER_SEC / 10);
|
||
}
|
||
g_test_message ("'%s' called with arguments: '%s'", terminal_exec, output_contents);
|
||
|
||
g_data_input_stream_read_byte (data_input_stream, NULL, &error);
|
||
g_assert_no_error (error);
|
||
|
||
output_args = g_strsplit (output_contents, " ", -1);
|
||
g_clear_pointer (&output_contents, g_free);
|
||
g_assert_cmpuint (g_strv_length (output_args), ==, 3 + terminal_divider_arg_length);
|
||
if (terminal_divider_arg_length > 0)
|
||
{
|
||
g_assert_cmpstr (output_args[0], ==, get_terminal_divider (terminal_exec));
|
||
g_assert_cmpstr (output_args[1], ==, "true");
|
||
g_assert_cmpstr (output_args[2], ==, command_line + 5);
|
||
}
|
||
else
|
||
{
|
||
g_assert_cmpstr (output_args[0], ==, "true");
|
||
g_assert_cmpstr (output_args[1], ==, command_line + 5);
|
||
}
|
||
paths = g_list_delete_link (paths,
|
||
g_list_find_custom (paths, output_args[2 + terminal_divider_arg_length], g_str_equal));
|
||
g_assert_cmpint (g_list_length (paths), ==, 0);
|
||
g_clear_pointer (&output_args, g_strfreev);
|
||
|
||
g_assert_null (paths);
|
||
|
||
if (launch_data->type == TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE)
|
||
g_assert_true (g_setenv ("PATH", old_path, TRUE));
|
||
|
||
g_close (fd, &error);
|
||
g_assert_no_error (error);
|
||
|
||
g_free (sh);
|
||
g_free (command_line);
|
||
g_free (bin_path);
|
||
g_free (terminal_path);
|
||
g_free (output_fd_path);
|
||
g_free (script_contents);
|
||
g_free (old_path);
|
||
g_clear_pointer (&output_args, g_strfreev);
|
||
g_clear_pointer (&output_contents, g_free);
|
||
g_clear_object (&data_input_stream);
|
||
g_clear_object (&input_stream);
|
||
g_clear_object (&app_info);
|
||
g_clear_object (&launch_context);
|
||
g_clear_error (&error);
|
||
g_clear_list (&paths, NULL);
|
||
g_clear_list (&uris, g_free);
|
||
}
|
||
|
||
static void
|
||
test_launch_uris_with_invalid_terminal (void)
|
||
{
|
||
char *old_path;
|
||
char *bin_path;
|
||
GAppInfo *app_info;
|
||
GError *error = NULL;
|
||
|
||
bin_path = g_dir_make_tmp ("bin-path-XXXXXX", &error);
|
||
g_assert_no_error (error);
|
||
|
||
old_path = g_strdup (g_getenv ("PATH"));
|
||
g_assert_true (g_setenv ("PATH", bin_path, TRUE));
|
||
|
||
app_info = g_app_info_create_from_commandline ("true invalid-glib-terminal",
|
||
"Test App on Invalid Terminal",
|
||
G_APP_INFO_CREATE_NEEDS_TERMINAL |
|
||
G_APP_INFO_CREATE_SUPPORTS_URIS,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
|
||
g_app_info_launch_uris (app_info, NULL, NULL, &error);
|
||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
|
||
g_clear_error (&error);
|
||
|
||
g_assert_true (g_setenv ("PATH", old_path, TRUE));
|
||
|
||
g_clear_object (&app_info);
|
||
g_clear_error (&error);
|
||
g_free (bin_path);
|
||
g_free (old_path);
|
||
}
|
||
|
||
static void
|
||
test_app_path (void)
|
||
{
|
||
GDesktopAppInfo *appinfo;
|
||
const char *desktop_path;
|
||
|
||
desktop_path = g_test_get_filename (G_TEST_BUILT, "appinfo-test-path.desktop", NULL);
|
||
appinfo = g_desktop_app_info_new_from_filename (desktop_path);
|
||
|
||
g_assert_true (G_IS_DESKTOP_APP_INFO (appinfo));
|
||
|
||
g_clear_object (&appinfo);
|
||
}
|
||
|
||
static void
|
||
test_app_path_wrong (void)
|
||
{
|
||
GKeyFile *key_file;
|
||
GDesktopAppInfo *appinfo;
|
||
const gchar bad_try_exec_file_contents[] =
|
||
"[Desktop Entry]\n"
|
||
"Type=Application\n"
|
||
"Name=appinfo-test\n"
|
||
"TryExec=appinfo-test\n"
|
||
"Path=this-must-not-exist‼\n"
|
||
"Exec=true\n";
|
||
const gchar bad_exec_file_contents[] =
|
||
"[Desktop Entry]\n"
|
||
"Type=Application\n"
|
||
"Name=appinfo-test\n"
|
||
"TryExec=true\n"
|
||
"Path=this-must-not-exist‼\n"
|
||
"Exec=appinfo-test\n";
|
||
|
||
g_assert_true (
|
||
g_file_test (g_test_get_filename (G_TEST_BUILT, "appinfo-test", NULL),
|
||
G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE));
|
||
|
||
key_file = g_key_file_new ();
|
||
|
||
g_assert_true (
|
||
g_key_file_load_from_data (key_file, bad_try_exec_file_contents, -1,
|
||
G_KEY_FILE_NONE, NULL));
|
||
|
||
appinfo = g_desktop_app_info_new_from_keyfile (key_file);
|
||
g_assert_false (G_IS_DESKTOP_APP_INFO (appinfo));
|
||
|
||
g_assert_true (
|
||
g_key_file_load_from_data (key_file, bad_exec_file_contents, -1,
|
||
G_KEY_FILE_NONE, NULL));
|
||
|
||
appinfo = g_desktop_app_info_new_from_keyfile (key_file);
|
||
g_assert_false (G_IS_DESKTOP_APP_INFO (appinfo));
|
||
|
||
g_clear_pointer (&key_file, g_key_file_unref);
|
||
g_clear_object (&appinfo);
|
||
}
|
||
|
||
static void
|
||
test_launch_startup_notify_fail (void)
|
||
{
|
||
GAppInfo *app_info;
|
||
GAppLaunchContext *context;
|
||
GError *error = NULL;
|
||
gboolean launch_started;
|
||
gboolean launch_failed;
|
||
gboolean launched;
|
||
GList *uris;
|
||
|
||
app_info = g_app_info_create_from_commandline ("this-must-not-exist‼",
|
||
"failing app",
|
||
G_APP_INFO_CREATE_NONE |
|
||
G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
|
||
context = g_object_new (test_launch_context_get_type (), NULL);
|
||
g_signal_connect (context, "launch-started",
|
||
G_CALLBACK (on_launch_started),
|
||
&launch_started);
|
||
g_signal_connect (context, "launched",
|
||
G_CALLBACK (on_launch_started),
|
||
&launched);
|
||
g_signal_connect (context, "launch-failed",
|
||
G_CALLBACK (on_launch_failed),
|
||
&launch_failed);
|
||
|
||
launch_started = FALSE;
|
||
launch_failed = FALSE;
|
||
launched = FALSE;
|
||
uris = g_list_prepend (NULL, g_file_new_for_uri ("foo://bar"));
|
||
uris = g_list_prepend (uris, g_file_new_for_uri ("bar://foo"));
|
||
g_assert_false (g_app_info_launch (app_info, uris, context, &error));
|
||
g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
|
||
g_assert_true (launch_started);
|
||
g_assert_true (launch_failed);
|
||
g_assert_false (launched);
|
||
|
||
g_clear_error (&error);
|
||
g_clear_object (&app_info);
|
||
g_clear_object (&context);
|
||
g_clear_list (&uris, g_object_unref);
|
||
}
|
||
|
||
static void
|
||
test_launch_fail (void)
|
||
{
|
||
GAppInfo *app_info;
|
||
GError *error = NULL;
|
||
|
||
app_info = g_app_info_create_from_commandline ("this-must-not-exist‼",
|
||
"failing app",
|
||
G_APP_INFO_CREATE_NONE,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
|
||
g_assert_false (g_app_info_launch (app_info, NULL, NULL, &error));
|
||
g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
|
||
|
||
g_clear_error (&error);
|
||
g_clear_object (&app_info);
|
||
}
|
||
|
||
static void
|
||
test_launch_fail_absolute_path (void)
|
||
{
|
||
GAppInfo *app_info;
|
||
GError *error = NULL;
|
||
|
||
app_info = g_app_info_create_from_commandline ("/nothing/of/this-must-exist‼",
|
||
NULL,
|
||
G_APP_INFO_CREATE_NONE,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
|
||
g_assert_false (g_app_info_launch (app_info, NULL, NULL, &error));
|
||
g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
|
||
|
||
g_clear_error (&error);
|
||
g_clear_object (&app_info);
|
||
|
||
app_info = g_app_info_create_from_commandline ("/",
|
||
NULL,
|
||
G_APP_INFO_CREATE_NONE,
|
||
&error);
|
||
g_assert_no_error (error);
|
||
|
||
g_assert_false (g_app_info_launch (app_info, NULL, NULL, &error));
|
||
g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT);
|
||
|
||
g_clear_error (&error);
|
||
g_clear_object (&app_info);
|
||
}
|
||
|
||
static void
|
||
async_result_cb (GObject *source_object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
GAsyncResult **result_out = user_data;
|
||
|
||
g_assert (*result_out == NULL);
|
||
*result_out = g_object_ref (result);
|
||
g_main_context_wakeup (g_main_context_get_thread_default ());
|
||
}
|
||
|
||
static void
|
||
test_launch_fail_dbus (void)
|
||
{
|
||
GTestDBus *bus = NULL;
|
||
GDesktopAppInfo *app_info = NULL;
|
||
GAppLaunchContext *context = NULL;
|
||
GAsyncResult *result = NULL;
|
||
GError *error = NULL;
|
||
|
||
/* Set up a test session bus to ensure that launching the app happens using
|
||
* D-Bus rather than spawning. */
|
||
bus = g_test_dbus_new (G_TEST_DBUS_NONE);
|
||
g_test_dbus_up (bus);
|
||
|
||
app_info = g_desktop_app_info_new_from_filename (g_test_get_filename (G_TEST_DIST, "org.gtk.test.dbusappinfo.desktop", NULL));
|
||
g_assert_nonnull (app_info);
|
||
|
||
g_assert_true (g_desktop_app_info_has_key (app_info, "DBusActivatable"));
|
||
|
||
context = g_app_launch_context_new ();
|
||
|
||
g_app_info_launch_uris_async (G_APP_INFO (app_info), NULL, context, NULL, async_result_cb, &result);
|
||
|
||
while (result == NULL)
|
||
g_main_context_iteration (NULL, TRUE);
|
||
|
||
g_assert_false (g_app_info_launch_uris_finish (G_APP_INFO (app_info), result, &error));
|
||
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN);
|
||
|
||
g_test_dbus_down (bus);
|
||
g_clear_object (&bus);
|
||
|
||
g_clear_error (&error);
|
||
g_clear_object (&result);
|
||
g_clear_object (&context);
|
||
g_clear_object (&app_info);
|
||
}
|
||
|
||
int
|
||
main (int argc,
|
||
char *argv[])
|
||
{
|
||
guint i;
|
||
const gchar *supported_terminals[] = {
|
||
"xdg-terminal-exec",
|
||
"kgx",
|
||
"gnome-terminal",
|
||
"mate-terminal",
|
||
"xfce4-terminal",
|
||
"tilix",
|
||
"konsole",
|
||
"nxterm",
|
||
"color-xterm",
|
||
"rxvt",
|
||
"dtterm",
|
||
"xterm",
|
||
};
|
||
|
||
/* While we use %G_TEST_OPTION_ISOLATE_DIRS to create temporary directories
|
||
* for each of the tests, we want to use the system MIME registry, assuming
|
||
* that it exists and correctly has shared-mime-info installed. */
|
||
g_content_type_set_mime_dirs (NULL);
|
||
|
||
g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
|
||
|
||
g_test_add_func ("/desktop-app-info/delete", test_delete);
|
||
g_test_add_func ("/desktop-app-info/default", test_default);
|
||
g_test_add_func ("/desktop-app-info/default-async", test_default_async);
|
||
g_test_add_func ("/desktop-app-info/fallback", test_fallback);
|
||
g_test_add_func ("/desktop-app-info/lastused", test_last_used);
|
||
g_test_add_func ("/desktop-app-info/extra-getters", test_extra_getters);
|
||
g_test_add_func ("/desktop-app-info/actions", test_actions);
|
||
g_test_add_func ("/desktop-app-info/search", test_search);
|
||
g_test_add_func ("/desktop-app-info/implements", test_implements);
|
||
g_test_add_func ("/desktop-app-info/show-in", test_show_in);
|
||
g_test_add_func ("/desktop-app-info/app-path", test_app_path);
|
||
g_test_add_func ("/desktop-app-info/app-path/wrong", test_app_path_wrong);
|
||
g_test_add_func ("/desktop-app-info/launch/fail", test_launch_fail);
|
||
g_test_add_func ("/desktop-app-info/launch/fail-absolute-path", test_launch_fail_absolute_path);
|
||
g_test_add_func ("/desktop-app-info/launch/fail-startup-notify", test_launch_startup_notify_fail);
|
||
g_test_add_func ("/desktop-app-info/launch/fail-dbus", test_launch_fail_dbus);
|
||
g_test_add_func ("/desktop-app-info/launch-as-manager", test_launch_as_manager);
|
||
g_test_add_func ("/desktop-app-info/launch-as-manager/fail", test_launch_as_manager_fail);
|
||
g_test_add_func ("/desktop-app-info/launch-default-uri-handler", test_default_uri_handler);
|
||
g_test_add_func ("/desktop-app-info/launch-default-uri-handler-async", test_default_uri_handler_async);
|
||
g_test_add_func ("/desktop-app-info/id", test_id);
|
||
|
||
for (i = 0; i < G_N_ELEMENTS (supported_terminals); i++)
|
||
{
|
||
char *path;
|
||
|
||
path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-path/%s",
|
||
supported_terminals[i]);
|
||
g_test_add_data_func_full (path,
|
||
terminal_launch_data_new (supported_terminals[i],
|
||
TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE),
|
||
test_launch_uris_with_terminal, g_free);
|
||
g_clear_pointer (&path, g_free);
|
||
|
||
path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-context/%s",
|
||
supported_terminals[i]);
|
||
g_test_add_data_func_full (path,
|
||
terminal_launch_data_new (supported_terminals[i],
|
||
TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT),
|
||
test_launch_uris_with_terminal, g_free);
|
||
g_clear_pointer (&path, g_free);
|
||
|
||
path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-desktop-path/%s",
|
||
supported_terminals[i]);
|
||
g_test_add_data_func_full (path,
|
||
terminal_launch_data_new (supported_terminals[i],
|
||
TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH),
|
||
test_launch_uris_with_terminal, g_free);
|
||
g_clear_pointer (&path, g_free);
|
||
}
|
||
|
||
g_test_add_func ("/desktop-app-info/launch-uris-with-terminal/invalid-glib-terminal",
|
||
test_launch_uris_with_invalid_terminal);
|
||
|
||
return g_test_run ();
|
||
}
|