Merge branch '1601-appinfo-test-again' into 'master'

Support isolating directories for unit tests

Closes #538 and #1601

See merge request GNOME/glib!505
This commit is contained in:
Philip Withnall 2018-12-17 17:51:37 +00:00
commit 70eb076ac3
33 changed files with 1631 additions and 966 deletions

View File

@ -64,6 +64,7 @@ IGNORE_HFILES = \
glib-init.h \
gconstructor.h \
valgrind.h \
gutilsprivate.h \
gvalgrind.h \
$(NULL)

View File

@ -1544,6 +1544,7 @@ g_strjoinv
GStrv
g_strv_length
g_strv_contains
g_strv_equal
<SUBSECTION>
g_strerror
@ -3101,6 +3102,7 @@ g_compute_hmac_for_bytes
<SECTION>
<TITLE>Testing</TITLE>
<FILE>testing</FILE>
G_TEST_OPTION_ISOLATE_DIRS
g_test_minimized_result
g_test_maximized_result
g_test_init

View File

@ -36,6 +36,7 @@ if get_option('gtk_doc')
'glib-init.h',
'gconstructor.h',
'valgrind.h',
'gutilsprivate.h',
'gvalgrind.h',
]

View File

@ -41,13 +41,13 @@
*
* A content type is a platform specific string that defines the type
* of a file. On UNIX it is a
* [mime type](http://www.wikipedia.org/wiki/Internet_media_type)
* like "text/plain" or "image/png".
* On Win32 it is an extension string like ".doc", ".txt" or a perceived
* string like "audio". Such strings can be looked up in the registry at
* HKEY_CLASSES_ROOT.
* On OSX it is a [Uniform Type Identifier](https://en.wikipedia.org/wiki/Uniform_Type_Identifier)
* such as "com.apple.application".
* [MIME type](http://www.wikipedia.org/wiki/Internet_media_type)
* like `text/plain` or `image/png`.
* On Win32 it is an extension string like `.doc`, `.txt` or a perceived
* string like `audio`. Such strings can be looked up in the registry at
* `HKEY_CLASSES_ROOT`.
* On macOS it is a [Uniform Type Identifier](https://en.wikipedia.org/wiki/Uniform_Type_Identifier)
* such as `com.apple.application`.
**/
#include <dirent.h>
@ -55,6 +55,8 @@
#define XDG_PREFIX _gio_xdg
#include "xdgmime/xdgmime.h"
static void tree_magic_schedule_reload (void);
/* We lock this mutex whenever we modify global state in this module. */
G_LOCK_DEFINE_STATIC (gio_xdgmime);
@ -111,6 +113,106 @@ _g_unix_content_type_get_parents (const gchar *type)
return (gchar **)g_ptr_array_free (array, FALSE);
}
G_LOCK_DEFINE_STATIC (global_mime_dirs);
static gchar **global_mime_dirs = NULL;
static void
_g_content_type_set_mime_dirs_locked (const char * const *dirs)
{
g_clear_pointer (&global_mime_dirs, g_strfreev);
if (dirs != NULL)
{
global_mime_dirs = g_strdupv ((gchar **) dirs);
}
else
{
GPtrArray *mime_dirs = g_ptr_array_new_with_free_func (g_free);
const gchar * const *system_dirs = g_get_system_data_dirs ();
g_ptr_array_add (mime_dirs, g_build_filename (g_get_user_data_dir (), "mime", NULL));
for (; *system_dirs != NULL; system_dirs++)
g_ptr_array_add (mime_dirs, g_build_filename (*system_dirs, "mime", NULL));
g_ptr_array_add (mime_dirs, NULL); /* NULL terminator */
global_mime_dirs = (gchar **) g_ptr_array_free (mime_dirs, FALSE);
}
xdg_mime_set_dirs ((const gchar * const *) global_mime_dirs);
tree_magic_schedule_reload ();
}
/**
* g_content_type_set_mime_dirs:
* @dirs: (array zero-terminated=1) (nullable): %NULL-terminated list of
* directories to load MIME data from, including any `mime/` subdirectory,
* and with the first directory to try listed first
*
* Set the list of directories used by GIO to load the MIME database.
* If @dirs is %NULL, the directories used are the default:
*
* - the `mime` subdirectory of the directory in `$XDG_DATA_HOME`
* - the `mime` subdirectory of every directory in `$XDG_DATA_DIRS`
*
* This function is intended to be used when writing tests that depend on
* information stored in the MIME database, in order to control the data.
*
* Typically, in case your tests use %G_TEST_OPTION_ISOLATE_DIRS, but they
* depend on the systems MIME database, you should call this function
* with @dirs set to %NULL before calling g_test_init(), for instance:
*
* |[<!-- language="C" -->
* // Load MIME data from the system
* g_content_type_set_mime_dirs (NULL);
* // Isolate the environment
* g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
*
*
*
* return g_test_run ();
* ]|
*
* Since: 2.60
*/
/*< private >*/
void
g_content_type_set_mime_dirs (const gchar * const *dirs)
{
G_LOCK (global_mime_dirs);
_g_content_type_set_mime_dirs_locked (dirs);
G_UNLOCK (global_mime_dirs);
}
/**
* g_content_type_get_mime_dirs:
*
* Get the list of directories which MIME data is loaded from. See
* g_content_type_set_mime_dirs() for details.
*
* Returns: (transfer none) (array zero-terminated=1): %NULL-terminated list of
* directories to load MIME data from, including any `mime/` subdirectory,
* and with the first directory to try listed first
* Since: 2.60
*/
/*< private >*/
const gchar * const *
g_content_type_get_mime_dirs (void)
{
const gchar * const *mime_dirs;
G_LOCK (global_mime_dirs);
if (global_mime_dirs == NULL)
_g_content_type_set_mime_dirs_locked (NULL);
mime_dirs = (const gchar * const *) global_mime_dirs;
G_UNLOCK (global_mime_dirs);
g_assert (mime_dirs != NULL);
return mime_dirs;
}
/**
* g_content_type_equals:
* @type1: a content type string
@ -306,7 +408,7 @@ load_comment_for_mime_helper (const char *dir,
mime_info_text
};
filename = g_build_filename (dir, "mime", basename, NULL);
filename = g_build_filename (dir, basename, NULL);
res = g_file_get_contents (filename, &data, &len, NULL);
g_free (filename);
@ -328,22 +430,14 @@ load_comment_for_mime_helper (const char *dir,
static char *
load_comment_for_mime (const char *mimetype)
{
const char * const* dirs;
const char * const *dirs;
char *basename;
char *comment;
int i;
gsize i;
basename = g_strdup_printf ("%s.xml", mimetype);
comment = load_comment_for_mime_helper (g_get_user_data_dir (), basename);
if (comment)
{
g_free (basename);
return comment;
}
dirs = g_get_system_data_dirs ();
dirs = g_content_type_get_mime_dirs ();
for (i = 0; dirs[i] != NULL; i++)
{
comment = load_comment_for_mime_helper (dirs[i], basename);
@ -780,10 +874,10 @@ enumerate_mimetypes_dir (const char *dir,
{
DIR *d;
struct dirent *ent;
char *mimedir;
const char *mimedir;
char *name;
mimedir = g_build_filename (dir, "mime", NULL);
mimedir = dir;
d = opendir (mimedir);
if (d)
@ -800,8 +894,6 @@ enumerate_mimetypes_dir (const char *dir,
}
closedir (d);
}
g_free (mimedir);
}
/**
@ -809,7 +901,7 @@ enumerate_mimetypes_dir (const char *dir,
*
* Gets a list of strings containing all the registered content types
* known to the system. The list and its data should be freed using
* g_list_free_full (list, g_free).
* `g_list_free_full (list, g_free)`.
*
* Returns: (element-type utf8) (transfer full): list of the registered
* content types
@ -817,18 +909,16 @@ enumerate_mimetypes_dir (const char *dir,
GList *
g_content_types_get_registered (void)
{
const char * const* dirs;
const char * const *dirs;
GHashTable *mimetypes;
GHashTableIter iter;
gpointer key;
int i;
gsize i;
GList *l;
mimetypes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
enumerate_mimetypes_dir (g_get_user_data_dir (), mimetypes);
dirs = g_get_system_data_dirs ();
dirs = g_content_type_get_mime_dirs ();
for (i = 0; dirs[i] != NULL; i++)
enumerate_mimetypes_dir (dirs[i], mimetypes);
@ -1030,7 +1120,7 @@ read_tree_magic_from_directory (const gchar *prefix)
TreeMatchlet *matchlet;
gint depth;
filename = g_build_filename (prefix, "mime", "treemagic", NULL);
filename = g_build_filename (prefix, "treemagic", NULL);
if (g_file_get_contents (filename, &text, &len, NULL))
{
@ -1068,11 +1158,16 @@ read_tree_magic_from_directory (const gchar *prefix)
g_free (filename);
}
static void
tree_magic_schedule_reload (void)
{
need_reload = TRUE;
}
static void
xdg_mime_reload (void *user_data)
{
need_reload = TRUE;
tree_magic_schedule_reload ();
}
static void
@ -1086,9 +1181,7 @@ static void
tree_magic_init (void)
{
static gboolean initialized = FALSE;
const gchar *dir;
const gchar * const * dirs;
int i;
gsize i;
if (!initialized)
{
@ -1100,14 +1193,14 @@ tree_magic_init (void)
if (need_reload)
{
const char * const *dirs;
need_reload = FALSE;
tree_magic_shutdown ();
dir = g_get_user_data_dir ();
read_tree_magic_from_directory (dir);
dirs = g_get_system_data_dirs ();
for (i = 0; dirs[i]; i++)
dirs = g_content_type_get_mime_dirs ();
for (i = 0; dirs[i] != NULL; i++)
read_tree_magic_from_directory (dirs[i]);
}
}

View File

@ -69,6 +69,12 @@ gchar ** g_content_type_guess_for_tree (GFile *root);
GLIB_AVAILABLE_IN_ALL
GList * g_content_types_get_registered (void);
/*< private >*/
GLIB_AVAILABLE_IN_2_60
const gchar * const *g_content_type_get_mime_dirs (void);
GLIB_AVAILABLE_IN_2_60
void g_content_type_set_mime_dirs (const gchar * const *dirs);
G_END_DECLS
#endif /* __G_CONTENT_TYPE_H__ */

View File

@ -152,6 +152,7 @@ typedef struct
static DesktopFileDir *desktop_file_dirs;
static guint n_desktop_file_dirs;
static const gchar *desktop_file_dirs_config_dir = NULL;
static const guint desktop_file_dir_user_config_index = 0;
static guint desktop_file_dir_user_data_index;
static GMutex desktop_file_dir_lock;
@ -1476,9 +1477,24 @@ static void
desktop_file_dirs_lock (void)
{
gint i;
const gchar *user_config_dir = g_get_user_config_dir ();
g_mutex_lock (&desktop_file_dir_lock);
/* If the XDG dirs configuration has changed (expected only during tests),
* clear and reload the state. */
if (g_strcmp0 (desktop_file_dirs_config_dir, user_config_dir) != 0)
{
g_debug ("%s: Resetting desktop app info dirs from %s to %s",
G_STRFUNC, desktop_file_dirs_config_dir, user_config_dir);
for (i = 0; i < n_desktop_file_dirs; i++)
desktop_file_dir_reset (&desktop_file_dirs[i]);
g_clear_pointer (&desktop_file_dirs, g_free);
n_desktop_file_dirs = 0;
desktop_file_dir_user_data_index = 0;
}
if (desktop_file_dirs == NULL)
{
const char * const *dirs;
@ -1488,7 +1504,7 @@ desktop_file_dirs_lock (void)
tmp = g_array_new (FALSE, FALSE, sizeof (DesktopFileDir));
/* First, the configs. Highest priority: the user's ~/.config */
desktop_file_dir_create_for_config (tmp, g_get_user_config_dir ());
desktop_file_dir_create_for_config (tmp, user_config_dir);
/* Next, the system configs (/etc/xdg, and so on). */
dirs = g_get_system_config_dirs ();
@ -1504,9 +1520,11 @@ desktop_file_dirs_lock (void)
for (i = 0; dirs[i]; i++)
desktop_file_dir_create (tmp, dirs[i]);
/* The list of directories will never change after this. */
/* The list of directories will never change after this, unless
* g_get_user_config_dir() changes due to %G_TEST_OPTION_ISOLATE_DIRS. */
desktop_file_dirs = (DesktopFileDir *) tmp->data;
n_desktop_file_dirs = tmp->len;
desktop_file_dirs_config_dir = user_config_dir;
g_array_free (tmp, FALSE);
}
@ -3191,6 +3209,8 @@ ensure_dir (DirType type,
g_assert_not_reached ();
}
g_debug ("%s: Ensuring %s", G_STRFUNC, path);
errno = 0;
if (g_mkdir_with_parents (path, 0700) == 0)
return path;

View File

@ -141,9 +141,6 @@ unix-fd
unix-streams
vfs
volumemonitor
xdgconfighome
xdgdatadir
xdgdatahome
xgen-gio
xgen-giosrc.c
gresource-big-test.txt

View File

@ -339,10 +339,7 @@ dist_test_data += \
dist_test_data += \
appinfo-test-actions.desktop \
appinfo-test-gnome.desktop \
appinfo-test-notgnome.desktop \
appinfo-test.desktop \
appinfo-test2.desktop \
appinfo-test-static.desktop \
file.c \
org.gtk.test.dbusappinfo.desktop \
x-content/image-dcf/DCIM/Camera/20130831_203925.jpg \
@ -362,11 +359,37 @@ uninstalled_test_extra_programs += \
if !OS_COCOA
test_extra_programs += apps
test_programs += mimeapps
clean-local: clean-mimeapps
clean-mimeapps:
rm -rf xdgdatadir xdgdatahome xdgconfighome
endif
appinfo-test-gnome.desktop: appinfo-test-gnome.desktop.in Makefile
$(AM_V_GEN)$(SED) \
-e 's|[@]installed_tests_dir[@]|$(installed_testdir)|g' \
$< > $@
appinfo-test-notgnome.desktop: appinfo-test-notgnome.desktop.in Makefile
$(AM_V_GEN)$(SED) \
-e 's|[@]installed_tests_dir[@]|$(installed_testdir)|g' \
$< > $@
appinfo-test.desktop: appinfo-test.desktop.in Makefile
$(AM_V_GEN)$(SED) \
-e 's|[@]installed_tests_dir[@]|$(installed_testdir)|g' \
$< > $@
appinfo-test2.desktop: appinfo-test2.desktop.in Makefile
$(AM_V_GEN)$(SED) \
-e 's|[@]installed_tests_dir[@]|$(installed_testdir)|g' \
$< > $@
appinfo_desktop_templates = \
appinfo-test-gnome.desktop.in \
appinfo-test-notgnome.desktop.in \
appinfo-test.desktop.in \
appinfo-test2.desktop.in \
$(NULL)
appinfo_desktop_files = $(appinfo_desktop_templates:.in=)
EXTRA_DIST += $(appinfo_desktop_templates)
CLEANFILES += $(appinfo_desktop_files)
test_data += $(appinfo_desktop_files)
uninstalled_test_programs += gsettings gschema-compile
gsettings_DEPENDENCIES = test.mo
CLEANFILES += test.mo de/LC_MESSAGES/test.mo keyfile/gsettings.store

View File

@ -1,6 +1,6 @@
[Desktop Entry]
Type=Application
Name=appinfo-test
Exec=./appinfo-test --option
Exec=@installed_tests_dir@/appinfo-test --option
OnlyShowIn=GNOME;KDE;
NotShowIn=ROX;

View File

@ -1,6 +1,6 @@
[Desktop Entry]
Type=Application
Name=appinfo-test
Exec=./appinfo-test --option
Exec=@installed_tests_dir@/appinfo-test --option
OnlyShowIn=KDE;
NotShowIn=GNOME;

View File

@ -0,0 +1,19 @@
[Desktop Entry]
Type=Application
GenericName=generic-appinfo-test
Name=appinfo-test
Name[de]=appinfo-test-de
X-GNOME-FullName=example
X-GNOME-FullName[de]=Beispiel
Comment=GAppInfo example
Comment[de]=GAppInfo Beispiel
Exec=true --option %U %i --name %c --filename %k %m %%
Icon=testicon.svg
Terminal=true
StartupNotify=true
StartupWMClass=appinfo-class
MimeType=image/png;image/jpeg;
Keywords=keyword1;test keyword;
Categories=GNOME;GTK;
X-JunkFood=Burger
X-JunkFood[de]=Bratwurst

View File

@ -14,7 +14,7 @@ main (int argc, char *argv[])
gchar *expected;
gint pid_from_env;
expected = g_test_build_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
expected = g_test_build_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
g_assert_cmpstr (envvar, ==, expected);
g_free (expected);

View File

@ -7,7 +7,7 @@ X-GNOME-FullName=example
X-GNOME-FullName[de]=Beispiel
Comment=GAppInfo example
Comment[de]=GAppInfo Beispiel
Exec=./appinfo-test --option %U %i --name %c --filename %k %m %%
Exec=@installed_tests_dir@/appinfo-test --option %U %i --name %c --filename %k %m %%
Icon=testicon.svg
Terminal=true
StartupNotify=true

View File

@ -6,6 +6,6 @@ X-GNOME-FullName=example
X-GNOME-FullName[de]=Beispiel
Comment=GAppInfo example
Comment[de]=GAppInfo Beispiel
Exec=./appinfo-test --option
Exec=@installed_tests_dir@/appinfo-test --option
TryExec=does-not-exist
Icon=testicon

View File

@ -6,115 +6,11 @@
#include <gio/gio.h>
#include <gio/gdesktopappinfo.h>
static gboolean
cleanup_dir_recurse (GFile *parent,
GFile *root,
GError **error)
{
gboolean ret = FALSE;
GFileEnumerator *enumerator;
GError *local_error = NULL;
g_assert (root != NULL);
enumerator =
g_file_enumerate_children (parent, "*",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
&local_error);
if (!enumerator)
{
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&local_error);
ret = TRUE;
}
goto out;
}
while (TRUE)
{
GFile *child;
GFileInfo *finfo;
char *relative_path;
if (!g_file_enumerator_iterate (enumerator, &finfo, &child, NULL, error))
goto out;
if (!finfo)
break;
relative_path = g_file_get_relative_path (root, child);
g_assert (relative_path != NULL);
g_free (relative_path);
if (g_file_info_get_file_type (finfo) == G_FILE_TYPE_DIRECTORY)
{
if (!cleanup_dir_recurse (child, root, error))
goto out;
}
if (!g_file_delete (child, NULL, error))
goto out;
}
ret = TRUE;
out:
g_clear_object (&enumerator);
return ret;
}
typedef struct
{
gchar *tmp_dir;
gchar *config_dir;
gchar *data_dir;
} Fixture;
static void
setup (Fixture *fixture,
gconstpointer user_data)
{
GError *local_error = NULL;
fixture->tmp_dir = g_dir_make_tmp ("gio-test-appinfo_XXXXXX", &local_error);
g_assert_no_error (local_error);
fixture->config_dir = g_build_filename (fixture->tmp_dir, "config", NULL);
g_assert_cmpint (g_mkdir (fixture->config_dir, 0755), ==, 0);
fixture->data_dir = g_build_filename (fixture->tmp_dir, "data", NULL);
g_assert_cmpint (g_mkdir (fixture->data_dir, 0755), ==, 0);
g_setenv ("XDG_CONFIG_HOME", fixture->config_dir, TRUE);
g_setenv ("XDG_DATA_HOME", fixture->data_dir, TRUE);
g_setenv ("XDG_DATA_DIRS", "/dev/null", TRUE);
g_setenv ("XDG_CONFIG_DIRS", "/dev/null", TRUE);
g_setenv ("XDG_CACHE_HOME", "/dev/null", TRUE);
g_setenv ("XDG_RUNTIME_DIR", "/dev/null", TRUE);
g_test_message ("Using tmp directory: %s", fixture->tmp_dir);
}
static void
teardown (Fixture *fixture,
gconstpointer user_data)
{
GFile *tmp_dir = g_file_new_for_path (fixture->tmp_dir);
GError *local_error = NULL;
cleanup_dir_recurse (tmp_dir, tmp_dir, &local_error);
g_assert_no_error (local_error);
g_clear_pointer (&fixture->config_dir, g_free);
g_clear_pointer (&fixture->data_dir, g_free);
g_clear_pointer (&fixture->tmp_dir, g_free);
}
static void
test_launch_for_app_info (GAppInfo *appinfo)
{
GError *error;
GError *error = NULL;
gboolean success;
GFile *file;
GList *l;
const gchar *path;
@ -126,52 +22,59 @@ test_launch_for_app_info (GAppInfo *appinfo)
return;
}
error = NULL;
g_assert (g_app_info_launch (appinfo, NULL, NULL, &error));
success = g_app_info_launch (appinfo, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_true (success);
g_assert (g_app_info_launch_uris (appinfo, NULL, NULL, &error));
success = g_app_info_launch_uris (appinfo, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_true (success);
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
file = g_file_new_for_path (path);
l = NULL;
l = g_list_append (l, file);
g_assert (g_app_info_launch (appinfo, l, NULL, &error));
success = g_app_info_launch (appinfo, l, NULL, &error);
g_assert_no_error (error);
g_assert_true (success);
g_list_free (l);
g_object_unref (file);
l = NULL;
uri = g_strconcat ("file://", g_test_get_dir (G_TEST_DIST), "/appinfo-test.desktop", NULL);
uri = g_strconcat ("file://", g_test_get_dir (G_TEST_BUILT), "/appinfo-test.desktop", NULL);
l = g_list_append (l, uri);
l = g_list_append (l, "file:///etc/group#adm");
g_assert (g_app_info_launch_uris (appinfo, l, NULL, &error));
success = g_app_info_launch_uris (appinfo, l, NULL, &error);
g_assert_no_error (error);
g_assert_true (success);
g_list_free (l);
g_free (uri);
}
static void
test_launch (Fixture *fixture,
gconstpointer user_data)
test_launch (void)
{
GAppInfo *appinfo;
const gchar *path;
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
g_assert (appinfo != NULL);
if (appinfo == NULL)
{
g_test_skip ("appinfo-test binary not installed");
return;
}
test_launch_for_app_info (appinfo);
g_object_unref (appinfo);
}
static void
test_launch_no_app_id (Fixture *fixture,
gconstpointer user_data)
test_launch_no_app_id (void)
{
const gchar desktop_file_base_contents[] =
"[Desktop Entry]\n"
@ -191,44 +94,50 @@ test_launch_no_app_id (Fixture *fixture,
"Keywords=keyword1;test keyword;\n"
"Categories=GNOME;GTK;\n";
const char *exec_line_variants[] = {
"Exec=./appinfo-test --option %U %i --name %c --filename %k %m %%",
"Exec=./appinfo-test --option %u %i --name %c --filename %k %m %%"
};
gchar *exec_line_variants[2];
gsize i;
exec_line_variants[0] = g_strdup_printf (
"Exec=%s/appinfo-test --option %%U %%i --name %%c --filename %%k %%m %%%%",
g_test_get_dir (G_TEST_BUILT));
exec_line_variants[1] = g_strdup_printf (
"Exec=%s/appinfo-test --option %%u %%i --name %%c --filename %%k %%m %%%%",
g_test_get_dir (G_TEST_BUILT));
g_test_bug ("791337");
for (i = 0; i < G_N_ELEMENTS (exec_line_variants); i++)
{
gchar *desktop_file_contents;
GKeyFile *fake_desktop_file;
GAppInfo *appinfo;
gboolean loaded;
{
gchar *desktop_file_contents;
GKeyFile *fake_desktop_file;
GAppInfo *appinfo;
gboolean loaded;
g_test_message ("Exec line variant #%" G_GSIZE_FORMAT, i);
g_test_message ("Exec line variant #%" G_GSIZE_FORMAT, i);
desktop_file_contents = g_strdup_printf ("%s\n%s",
desktop_file_base_contents,
exec_line_variants[i]);
desktop_file_contents = g_strdup_printf ("%s\n%s",
desktop_file_base_contents,
exec_line_variants[i]);
/* We load a desktop file from memory to force the app not
* to have an app ID, which would check different codepaths.
*/
fake_desktop_file = g_key_file_new ();
loaded = g_key_file_load_from_data (fake_desktop_file, desktop_file_contents, -1, G_KEY_FILE_NONE, NULL);
g_assert_true (loaded);
/* We load a desktop file from memory to force the app not
* to have an app ID, which would check different codepaths.
*/
fake_desktop_file = g_key_file_new ();
loaded = g_key_file_load_from_data (fake_desktop_file, desktop_file_contents, -1, G_KEY_FILE_NONE, NULL);
g_assert_true (loaded);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_keyfile (fake_desktop_file);
g_assert (appinfo != NULL);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_keyfile (fake_desktop_file);
g_assert_nonnull (appinfo);
test_launch_for_app_info (appinfo);
test_launch_for_app_info (appinfo);
g_free (desktop_file_contents);
g_object_unref (appinfo);
g_key_file_unref (fake_desktop_file);
}
g_free (desktop_file_contents);
g_object_unref (appinfo);
g_key_file_unref (fake_desktop_file);
}
g_free (exec_line_variants[1]);
g_free (exec_line_variants[0]);
}
static void
@ -242,7 +151,7 @@ test_locale (const char *locale)
g_setenv ("LANGUAGE", locale, TRUE);
setlocale (LC_ALL, "");
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_DIST, "appinfo-test-static.desktop", NULL);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
if (g_strcmp0 (locale, "C") == 0)
@ -272,8 +181,7 @@ test_locale (const char *locale)
}
static void
test_text (Fixture *fixture,
gconstpointer user_data)
test_text (void)
{
test_locale ("C");
test_locale ("en_US");
@ -282,24 +190,24 @@ test_text (Fixture *fixture,
}
static void
test_basic (Fixture *fixture,
gconstpointer user_data)
test_basic (void)
{
GAppInfo *appinfo;
GAppInfo *appinfo2;
GIcon *icon, *icon2;
const gchar *path;
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_DIST, "appinfo-test-static.desktop", NULL);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
g_assert_nonnull (appinfo);
g_assert_cmpstr (g_app_info_get_id (appinfo), ==, "appinfo-test.desktop");
g_assert (strstr (g_app_info_get_executable (appinfo), "appinfo-test") != NULL);
g_assert_cmpstr (g_app_info_get_id (appinfo), ==, "appinfo-test-static.desktop");
g_assert_nonnull (strstr (g_app_info_get_executable (appinfo), "true"));
icon = g_app_info_get_icon (appinfo);
g_assert (G_IS_THEMED_ICON (icon));
g_assert_true (G_IS_THEMED_ICON (icon));
icon2 = g_themed_icon_new ("testicon");
g_assert (g_icon_equal (icon, icon2));
g_assert_true (g_icon_equal (icon, icon2));
g_object_unref (icon2);
appinfo2 = g_app_info_dup (appinfo);
@ -311,31 +219,36 @@ test_basic (Fixture *fixture,
}
static void
test_show_in (Fixture *fixture,
gconstpointer user_data)
test_show_in (void)
{
GAppInfo *appinfo;
const gchar *path;
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
g_assert (g_app_info_should_show (appinfo));
if (appinfo == NULL)
{
g_test_skip ("appinfo-test binary not installed");
return;
}
g_assert_true (g_app_info_should_show (appinfo));
g_object_unref (appinfo);
path = g_test_get_filename (G_TEST_DIST, "appinfo-test-gnome.desktop", NULL);
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test-gnome.desktop", NULL);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
g_assert (g_app_info_should_show (appinfo));
g_assert_true (g_app_info_should_show (appinfo));
g_object_unref (appinfo);
path = g_test_get_filename (G_TEST_DIST, "appinfo-test-notgnome.desktop", NULL);
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test-notgnome.desktop", NULL);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
g_assert (!g_app_info_should_show (appinfo));
g_assert_false (g_app_info_should_show (appinfo));
g_object_unref (appinfo);
}
static void
test_commandline (Fixture *fixture,
gconstpointer user_data)
test_commandline (void)
{
GAppInfo *appinfo;
GError *error;
@ -350,12 +263,12 @@ test_commandline (Fixture *fixture,
"cmdline-app-test",
G_APP_INFO_CREATE_SUPPORTS_URIS,
&error);
g_assert (appinfo != NULL);
g_assert_no_error (error);
g_assert_nonnull (appinfo);
g_assert_cmpstr (g_app_info_get_name (appinfo), ==, "cmdline-app-test");
g_assert_cmpstr (g_app_info_get_commandline (appinfo), ==, cmdline_out);
g_assert (g_app_info_supports_uris (appinfo));
g_assert (!g_app_info_supports_files (appinfo));
g_assert_true (g_app_info_supports_uris (appinfo));
g_assert_false (g_app_info_supports_files (appinfo));
g_object_unref (appinfo);
@ -367,12 +280,12 @@ test_commandline (Fixture *fixture,
"cmdline-app-test",
G_APP_INFO_CREATE_NONE,
&error);
g_assert (appinfo != NULL);
g_assert_no_error (error);
g_assert_nonnull (appinfo);
g_assert_cmpstr (g_app_info_get_name (appinfo), ==, "cmdline-app-test");
g_assert_cmpstr (g_app_info_get_commandline (appinfo), ==, cmdline_out);
g_assert (!g_app_info_supports_uris (appinfo));
g_assert (g_app_info_supports_files (appinfo));
g_assert_false (g_app_info_supports_uris (appinfo));
g_assert_true (g_app_info_supports_files (appinfo));
g_object_unref (appinfo);
@ -381,8 +294,7 @@ test_commandline (Fixture *fixture,
}
static void
test_launch_context (Fixture *fixture,
gconstpointer user_data)
test_launch_context (void)
{
GAppLaunchContext *context;
GAppInfo *appinfo;
@ -398,10 +310,10 @@ test_launch_context (Fixture *fixture,
NULL);
str = g_app_launch_context_get_display (context, appinfo, NULL);
g_assert (str == NULL);
g_assert_null (str);
str = g_app_launch_context_get_startup_notify_id (context, appinfo, NULL);
g_assert (str == NULL);
g_assert_null (str);
g_object_unref (appinfo);
g_object_unref (context);
@ -420,8 +332,8 @@ launched (GAppLaunchContext *context,
gint pid;
pid = 0;
g_assert (g_variant_lookup (platform_data, "pid", "i", &pid));
g_assert (pid != 0);
g_assert_true (g_variant_lookup (platform_data, "pid", "i", &pid));
g_assert_cmpint (pid, !=, 0);
launched_reached = TRUE;
}
@ -434,12 +346,12 @@ launch_failed (GAppLaunchContext *context,
}
static void
test_launch_context_signals (Fixture *fixture,
gconstpointer user_data)
test_launch_context_signals (void)
{
GAppLaunchContext *context;
GAppInfo *appinfo;
GError *error = NULL;
gboolean success;
gchar *cmdline;
cmdline = g_strconcat (g_test_get_dir (G_TEST_BUILT), "/appinfo-test --option", NULL);
@ -452,11 +364,11 @@ test_launch_context_signals (Fixture *fixture,
G_APP_INFO_CREATE_SUPPORTS_URIS,
NULL);
error = NULL;
g_assert (g_app_info_launch (appinfo, NULL, context, &error));
success = g_app_info_launch (appinfo, NULL, context, &error);
g_assert_no_error (error);
g_assert_true (success);
g_assert (launched_reached);
g_assert_true (launched_reached);
g_object_unref (appinfo);
g_object_unref (context);
@ -465,28 +377,26 @@ test_launch_context_signals (Fixture *fixture,
}
static void
test_tryexec (Fixture *fixture,
gconstpointer user_data)
test_tryexec (void)
{
GAppInfo *appinfo;
const gchar *path;
path = g_test_get_filename (G_TEST_DIST, "appinfo-test2.desktop", NULL);
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test2.desktop", NULL);
appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
g_assert (appinfo == NULL);
g_assert_null (appinfo);
}
/* Test that we can set an appinfo as default for a mime type or
* file extension, and also add and remove handled mime types.
*/
static void
test_associations (Fixture *fixture,
gconstpointer user_data)
test_associations (void)
{
GAppInfo *appinfo;
GAppInfo *appinfo2;
GError *error;
GError *error = NULL;
gboolean result;
GList *list;
gchar *cmdline;
@ -498,33 +408,31 @@ test_associations (Fixture *fixture,
NULL);
g_free (cmdline);
error = NULL;
result = g_app_info_set_as_default_for_type (appinfo, "application/x-glib-test", &error);
g_assert (result);
g_assert_no_error (error);
g_assert_true (result);
appinfo2 = g_app_info_get_default_for_type ("application/x-glib-test", FALSE);
g_assert (appinfo2);
g_assert_nonnull (appinfo2);
g_assert_cmpstr (g_app_info_get_commandline (appinfo), ==, g_app_info_get_commandline (appinfo2));
g_object_unref (appinfo2);
result = g_app_info_set_as_default_for_extension (appinfo, "gio-tests", &error);
g_assert (result);
g_assert_no_error (error);
g_assert_true (result);
appinfo2 = g_app_info_get_default_for_type ("application/x-extension-gio-tests", FALSE);
g_assert (appinfo2);
g_assert_nonnull (appinfo2);
g_assert_cmpstr (g_app_info_get_commandline (appinfo), ==, g_app_info_get_commandline (appinfo2));
g_object_unref (appinfo2);
result = g_app_info_add_supports_type (appinfo, "application/x-gio-test", &error);
g_assert (result);
g_assert_no_error (error);
g_assert_true (result);
list = g_app_info_get_all_for_type ("application/x-gio-test");
g_assert_cmpint (g_list_length (list), ==, 1);
@ -533,18 +441,18 @@ test_associations (Fixture *fixture,
g_object_unref (appinfo2);
g_list_free (list);
g_assert (g_app_info_can_remove_supports_type (appinfo));
g_assert (g_app_info_remove_supports_type (appinfo, "application/x-gio-test", &error));
g_assert_true (g_app_info_can_remove_supports_type (appinfo));
result = g_app_info_remove_supports_type (appinfo, "application/x-gio-test", &error);
g_assert_no_error (error);
g_assert_true (result);
g_assert (g_app_info_can_delete (appinfo));
g_assert (g_app_info_delete (appinfo));
g_assert_true (g_app_info_can_delete (appinfo));
g_assert_true (g_app_info_delete (appinfo));
g_object_unref (appinfo);
}
static void
test_environment (Fixture *fixture,
gconstpointer user_data)
test_environment (void)
{
GAppLaunchContext *ctx;
gchar **env;
@ -558,8 +466,8 @@ test_environment (Fixture *fixture,
env = g_app_launch_context_get_environment (ctx);
g_assert (g_environ_getenv (env, "FOO") == NULL);
g_assert (g_environ_getenv (env, "BLA") == NULL);
g_assert_null (g_environ_getenv (env, "FOO"));
g_assert_null (g_environ_getenv (env, "BLA"));
g_assert_cmpstr (g_environ_getenv (env, "PATH"), ==, path);
g_strfreev (env);
@ -581,7 +489,7 @@ test_environment (Fixture *fixture,
env = g_app_launch_context_get_environment (ctx);
g_assert_cmpstr (g_environ_getenv (env, "FOO"), ==, "baz");
g_assert (g_environ_getenv (env, "BLA") == NULL);
g_assert_null (g_environ_getenv (env, "BLA"));
g_strfreev (env);
@ -589,14 +497,13 @@ test_environment (Fixture *fixture,
}
static void
test_startup_wm_class (Fixture *fixture,
gconstpointer user_data)
test_startup_wm_class (void)
{
GDesktopAppInfo *appinfo;
const char *wm_class;
const gchar *path;
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_DIST, "appinfo-test-static.desktop", NULL);
appinfo = g_desktop_app_info_new_from_filename (path);
wm_class = g_desktop_app_info_get_startup_wm_class (appinfo);
@ -606,14 +513,13 @@ test_startup_wm_class (Fixture *fixture,
}
static void
test_supported_types (Fixture *fixture,
gconstpointer user_data)
test_supported_types (void)
{
GAppInfo *appinfo;
const char * const *content_types;
const gchar *path;
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_DIST, "appinfo-test-static.desktop", NULL);
appinfo = G_APP_INFO (g_desktop_app_info_new_from_filename (path));
content_types = g_app_info_get_supported_types (appinfo);
@ -624,8 +530,7 @@ test_supported_types (Fixture *fixture,
}
static void
test_from_keyfile (Fixture *fixture,
gconstpointer user_data)
test_from_keyfile (void)
{
GDesktopAppInfo *info;
GKeyFile *kf;
@ -638,19 +543,19 @@ test_from_keyfile (Fixture *fixture,
const gchar *name;
const gchar *path;
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_DIST, "appinfo-test-static.desktop", NULL);
kf = g_key_file_new ();
g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, &error);
g_assert_no_error (error);
info = g_desktop_app_info_new_from_keyfile (kf);
g_key_file_unref (kf);
g_assert (info != NULL);
g_assert_nonnull (info);
g_object_get (info, "filename", &file, NULL);
g_assert (file == NULL);
g_assert_null (file);
file = g_desktop_app_info_get_filename (info);
g_assert (file == NULL);
g_assert_null (file);
categories = g_desktop_app_info_get_categories (info);
g_assert_cmpstr (categories, ==, "GNOME;GTK;");
categories_list = g_desktop_app_info_get_string_list (info, "Categories", &categories_count);
@ -664,7 +569,7 @@ test_from_keyfile (Fixture *fixture,
g_assert_cmpstr (keywords[1], ==, "test keyword");
name = g_desktop_app_info_get_generic_name (info);
g_assert_cmpstr (name, ==, "generic-appinfo-test");
g_assert (!g_desktop_app_info_get_nodisplay (info));
g_assert_false (g_desktop_app_info_get_nodisplay (info));
g_strfreev (categories_list);
g_object_unref (info);
@ -673,33 +578,25 @@ test_from_keyfile (Fixture *fixture,
int
main (int argc, char *argv[])
{
const gchar *build_dir;
g_setenv ("XDG_CURRENT_DESKTOP", "GNOME", TRUE);
g_test_init (&argc, &argv, NULL);
g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=");
/* With Meson build we need to change into right directory, so that the
* appinfo-test binary can be found. */
build_dir = g_getenv ("G_TEST_BUILDDIR");
if (build_dir)
g_chdir (build_dir);
g_test_add ("/appinfo/basic", Fixture, NULL, setup, test_basic, teardown);
g_test_add ("/appinfo/text", Fixture, NULL, setup, test_text, teardown);
g_test_add ("/appinfo/launch", Fixture, NULL, setup, test_launch, teardown);
g_test_add ("/appinfo/launch/no-appid", Fixture, NULL, setup, test_launch_no_app_id, teardown);
g_test_add ("/appinfo/show-in", Fixture, NULL, setup, test_show_in, teardown);
g_test_add ("/appinfo/commandline", Fixture, NULL, setup, test_commandline, teardown);
g_test_add ("/appinfo/launch-context", Fixture, NULL, setup, test_launch_context, teardown);
g_test_add ("/appinfo/launch-context-signals", Fixture, NULL, setup, test_launch_context_signals, teardown);
g_test_add ("/appinfo/tryexec", Fixture, NULL, setup, test_tryexec, teardown);
g_test_add ("/appinfo/associations", Fixture, NULL, setup, test_associations, teardown);
g_test_add ("/appinfo/environment", Fixture, NULL, setup, test_environment, teardown);
g_test_add ("/appinfo/startup-wm-class", Fixture, NULL, setup, test_startup_wm_class, teardown);
g_test_add ("/appinfo/supported-types", Fixture, NULL, setup, test_supported_types, teardown);
g_test_add ("/appinfo/from-keyfile", Fixture, NULL, setup, test_from_keyfile, teardown);
g_test_add_func ("/appinfo/basic", test_basic);
g_test_add_func ("/appinfo/text", test_text);
g_test_add_func ("/appinfo/launch", test_launch);
g_test_add_func ("/appinfo/launch/no-appid", test_launch_no_app_id);
g_test_add_func ("/appinfo/show-in", test_show_in);
g_test_add_func ("/appinfo/commandline", test_commandline);
g_test_add_func ("/appinfo/launch-context", test_launch_context);
g_test_add_func ("/appinfo/launch-context-signals", test_launch_context_signals);
g_test_add_func ("/appinfo/tryexec", test_tryexec);
g_test_add_func ("/appinfo/associations", test_associations);
g_test_add_func ("/appinfo/environment", test_environment);
g_test_add_func ("/appinfo/startup-wm-class", test_startup_wm_class);
g_test_add_func ("/appinfo/supported-types", test_supported_types);
g_test_add_func ("/appinfo/from-keyfile", test_from_keyfile);
return g_test_run ();
}

View File

@ -3,7 +3,6 @@
typedef struct
{
gchar *data_dir;
gchar *applications_dir;
} Fixture;
@ -11,18 +10,10 @@ static void
setup (Fixture *fixture,
gconstpointer user_data)
{
GError *error = NULL;
fixture->applications_dir = g_build_filename (g_get_user_data_dir (), "applications", NULL);
g_assert_cmpint (g_mkdir_with_parents (fixture->applications_dir, 0755), ==, 0);
fixture->data_dir = g_dir_make_tmp ("gio-test-app-monitor_XXXXXX", &error);
g_assert_no_error (error);
fixture->applications_dir = g_build_filename (fixture->data_dir, "applications", NULL);
g_assert_cmpint (g_mkdir (fixture->applications_dir, 0755), ==, 0);
g_setenv ("XDG_DATA_DIRS", fixture->data_dir, TRUE);
g_setenv ("XDG_DATA_HOME", fixture->data_dir, TRUE);
g_test_message ("Using data directory: %s", fixture->data_dir);
g_test_message ("Using data directory: %s", g_get_user_data_dir ());
}
static void
@ -31,9 +22,6 @@ teardown (Fixture *fixture,
{
g_assert_cmpint (g_rmdir (fixture->applications_dir), ==, 0);
g_clear_pointer (&fixture->applications_dir, g_free);
g_assert_cmpint (g_rmdir (fixture->data_dir), ==, 0);
g_clear_pointer (&fixture->data_dir, g_free);
}
static gboolean
@ -129,7 +117,7 @@ test_app_monitor (Fixture *fixture,
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
g_test_add ("/monitor/app", Fixture, NULL, setup, test_app_monitor, teardown);

View File

@ -27,9 +27,7 @@
#include <string.h>
#include <unistd.h>
static char *basedir;
static GAppInfo *
static GAppInfo *
create_app_info (const char *name)
{
GError *error;
@ -40,13 +38,13 @@ create_app_info (const char *name)
name,
G_APP_INFO_CREATE_NONE,
&error);
g_assert (error == NULL);
g_assert_no_error (error);
/* this is necessary to ensure that the info is saved */
g_app_info_set_as_default_for_type (info, "application/x-blah", &error);
g_assert (error == NULL);
g_assert_no_error (error);
g_app_info_remove_supports_type (info, "application/x-blah", &error);
g_assert (error == NULL);
g_assert_no_error (error);
g_app_info_reset_type_associations ("application/x-blah");
return info;
@ -64,34 +62,34 @@ test_delete (void)
info = create_app_info ("Blah");
id = g_app_info_get_id (info);
g_assert (id != NULL);
g_assert_nonnull (id);
filename = g_build_filename (basedir, "applications", id, NULL);
filename = g_build_filename (g_get_user_data_dir (), "applications", id, NULL);
res = g_file_test (filename, G_FILE_TEST_EXISTS);
g_assert (res);
g_assert_true (res);
res = g_app_info_can_delete (info);
g_assert (res);
g_assert_true (res);
res = g_app_info_delete (info);
g_assert (res);
g_assert_true (res);
res = g_file_test (filename, G_FILE_TEST_EXISTS);
g_assert (!res);
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 (info);
g_assert_nonnull (info);
res = g_app_info_can_delete (info);
g_assert (!res);
g_assert_false (res);
res = g_app_info_delete (info);
g_assert (!res);
g_assert_false (res);
}
g_free (filename);
@ -109,33 +107,33 @@ test_default (void)
info3 = create_app_info ("Blah3");
g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
g_assert (error == NULL);
g_assert_no_error (error);
g_app_info_set_as_default_for_type (info2, "application/x-test", &error);
g_assert (error == NULL);
g_assert_no_error (error);
info = g_app_info_get_default_for_type ("application/x-test", FALSE);
g_assert (info != NULL);
g_assert_nonnull (info);
g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
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 (error == NULL);
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 (info != NULL);
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 (error == NULL);
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 (info != NULL);
g_assert_nonnull (info);
g_assert_cmpstr (g_app_info_get_id (info), ==, g_app_info_get_id (info2));
g_object_unref (info);
@ -143,7 +141,7 @@ test_default (void)
g_app_info_reset_type_associations ("application/x-test");
list = g_app_info_get_all_for_type ("application/x-test");
g_assert (list == NULL);
g_assert_null (list);
g_app_info_delete (info1);
g_app_info_delete (info2);
@ -165,17 +163,17 @@ test_fallback (void)
info1 = create_app_info ("Test1");
info2 = create_app_info ("Test2");
g_assert (g_content_type_is_a ("text/x-python", "text/plain"));
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 (error == NULL);
g_assert_no_error (error);
g_app_info_add_supports_type (info2, "text/plain", &error);
g_assert (error == NULL);
g_assert_no_error (error);
/* check that both apps are registered */
apps = g_app_info_get_all_for_type ("text/x-python");
@ -183,18 +181,18 @@ test_fallback (void)
/* check that Test1 is among the recommended apps */
recomm = g_app_info_get_recommended_for_type ("text/x-python");
g_assert (recomm != NULL);
g_assert_nonnull (recomm);
for (l = recomm; l; l = l->next)
{
app = l->data;
if (g_app_info_equal (info1, app))
break;
}
g_assert (g_app_info_equal (info1, 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 (fallback != NULL);
g_assert_nonnull (fallback);
for (l = fallback; l; l = l->next)
{
app = l->data;
@ -205,11 +203,11 @@ test_fallback (void)
/* check that recomm + fallback = all applications */
list = g_list_concat (g_list_copy (recomm), g_list_copy (fallback));
g_assert (g_list_length (list) == g_list_length (apps));
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 (g_app_info_equal (l->data, m->data));
g_assert_true (g_app_info_equal (l->data, m->data));
}
g_list_free (list);
@ -239,32 +237,32 @@ test_last_used (void)
info2 = create_app_info ("Test2");
g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
g_assert (error == NULL);
g_assert_no_error (error);
g_app_info_add_supports_type (info2, "application/x-test", &error);
g_assert (error == NULL);
g_assert_no_error (error);
applications = g_app_info_get_recommended_for_type ("application/x-test");
g_assert (g_list_length (applications) == 2);
g_assert_cmpuint (g_list_length (applications), ==, 2);
/* the first should be the default app now */
g_assert (g_app_info_equal (g_list_nth_data (applications, 0), info1));
g_assert (g_app_info_equal (g_list_nth_data (applications, 1), info2));
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 (error == NULL);
g_assert_no_error (error);
applications = g_app_info_get_recommended_for_type ("application/x-test");
g_assert (g_list_length (applications) == 2);
g_assert_cmpuint (g_list_length (applications), ==, 2);
default_app = g_app_info_get_default_for_type ("application/x-test", FALSE);
g_assert (g_app_info_equal (default_app, info1));
g_assert_true (g_app_info_equal (default_app, info1));
/* the first should be the other app now */
g_assert (g_app_info_equal (g_list_nth_data (applications, 0), info2));
g_assert (g_app_info_equal (g_list_nth_data (applications, 1), info1));
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);
@ -278,81 +276,6 @@ test_last_used (void)
g_object_unref (default_app);
}
static gboolean
cleanup_dir_recurse (GFile *parent,
GFile *root,
GError **error)
{
gboolean ret = FALSE;
GFileEnumerator *enumerator;
GError *local_error = NULL;
g_assert (root != NULL);
enumerator =
g_file_enumerate_children (parent, "*",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
&local_error);
if (!enumerator)
{
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&local_error);
ret = TRUE;
}
goto out;
}
while (TRUE)
{
GFile *child;
GFileInfo *finfo;
char *relative_path;
if (!g_file_enumerator_iterate (enumerator, &finfo, &child, NULL, error))
goto out;
if (!finfo)
break;
relative_path = g_file_get_relative_path (root, child);
g_assert (relative_path != NULL);
g_free (relative_path);
if (g_file_info_get_file_type (finfo) == G_FILE_TYPE_DIRECTORY)
{
if (!cleanup_dir_recurse (child, root, error))
goto out;
}
if (!g_file_delete (child, NULL, error))
goto out;
}
ret = TRUE;
out:
g_clear_object (&enumerator);
return ret;
}
static void
cleanup_subdirs (const char *base_dir)
{
GFile *base, *file;
GError *error = NULL;
base = g_file_new_for_path (base_dir);
file = g_file_get_child (base, "applications");
(void) cleanup_dir_recurse (file, file, &error);
g_assert_no_error (error);
g_object_unref (file);
file = g_file_get_child (base, "mime");
(void) cleanup_dir_recurse (file, file, &error);
g_assert_no_error (error);
g_object_unref (file);
g_object_unref (base);
}
static void
test_extra_getters (void)
{
@ -365,11 +288,11 @@ test_extra_getters (void)
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.desktop", NULL));
g_assert (appinfo != NULL);
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 (g_desktop_app_info_has_key (appinfo, "Terminal"));
g_assert (!g_desktop_app_info_has_key (appinfo, "Bratwurst"));
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");
@ -387,7 +310,7 @@ test_extra_getters (void)
g_free (s);
b = g_desktop_app_info_get_boolean (appinfo, "Terminal");
g_assert (b);
g_assert_true (b);
g_object_unref (appinfo);
@ -400,7 +323,7 @@ wait_for_file (const gchar *want_this,
const gchar *but_not_this,
const gchar *or_this)
{
gint retries = 600;
guint retries = 600;
/* I hate time-based conditions in tests, but this will wait up to one
* whole minute for "touch file" to finish running. I think it should
@ -411,12 +334,12 @@ wait_for_file (const gchar *want_this,
while (access (want_this, F_OK) != 0)
{
g_usleep (100000); /* 100ms */
g_assert (retries);
g_assert_cmpuint (retries, >, 0);
retries--;
}
g_assert (access (but_not_this, F_OK) != 0);
g_assert (access (or_this, F_OK) != 0);
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);
@ -431,7 +354,7 @@ test_actions (void)
gchar *name;
appinfo = g_desktop_app_info_new_from_filename (g_test_get_filename (G_TEST_DIST, "appinfo-test-actions.desktop", NULL));
g_assert (appinfo != NULL);
g_assert_nonnull (appinfo);
actions = g_desktop_app_info_list_actions (appinfo);
g_assert_cmpstr (actions[0], ==, "frob");
@ -453,8 +376,8 @@ test_actions (void)
g_free (name);
name = g_desktop_app_info_get_action_name (appinfo, "broken");
g_assert (name != NULL);
g_assert (g_utf8_validate (name, -1, NULL));
g_assert_nonnull (name);
g_assert_true (g_utf8_validate (name, -1, NULL));
g_free (name);
unlink ("frob"); unlink ("tweak"); unlink ("twiddle");
@ -485,6 +408,7 @@ run_apps (const gchar *command,
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);
@ -527,9 +451,15 @@ run_apps (const gchar *command,
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 (success);
g_assert (status == 0);
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);
@ -814,9 +744,14 @@ test_launch_as_manager (void)
return;
}
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
path = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
appinfo = g_desktop_app_info_new_from_filename (path);
g_assert_nonnull (appinfo);
if (appinfo == NULL)
{
g_test_skip ("appinfo-test binary not installed");
return;
}
retval = g_desktop_app_info_launch_uris_as_manager (appinfo, NULL, NULL, 0,
NULL, NULL,
@ -841,20 +776,12 @@ int
main (int argc,
char *argv[])
{
const gchar *build_dir;
gint result;
/* 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);
/* With Meson build we need to change into right directory, so that the
* appinfo-test binary can be found. */
build_dir = g_getenv ("G_TEST_BUILDDIR");
if (build_dir)
g_chdir (build_dir);
g_test_init (&argc, &argv, NULL);
basedir = g_get_current_dir ();
g_setenv ("XDG_DATA_HOME", basedir, TRUE);
cleanup_subdirs (basedir);
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);
@ -867,9 +794,5 @@ main (int argc,
g_test_add_func ("/desktop-app-info/show-in", test_show_in);
g_test_add_func ("/desktop-app-info/launch-as-manager", test_launch_as_manager);
result = g_test_run ();
cleanup_subdirs (basedir);
return result;
return g_test_run ();
}

View File

@ -156,11 +156,9 @@ if host_machine.system() != 'windows'
gio_tests += {
'appinfo' : {
'install' : false,
'is_parallel' : false,
},
'desktop-app-info' : {
'install' : false,
'is_parallel' : false,
},
}
endif
@ -397,15 +395,36 @@ if host_machine.system() != 'windows'
}
endif
appinfo_test_desktop_files = [
'appinfo-test-gnome.desktop',
'appinfo-test-notgnome.desktop',
'appinfo-test.desktop',
'appinfo-test2.desktop',
]
cdata = configuration_data()
if installed_tests_enabled
cdata.set('installed_tests_dir', installed_tests_execdir)
else
cdata.set('installed_tests_dir', meson.current_build_dir())
endif
foreach appinfo_test_desktop_file : appinfo_test_desktop_files
configure_file(
input: appinfo_test_desktop_file + '.in',
output: appinfo_test_desktop_file,
install_dir: installed_tests_execdir,
install: installed_tests_enabled,
configuration: cdata,
)
endforeach
if installed_tests_enabled
install_data(
'contexts.c',
'g-icon.c',
'appinfo-test-actions.desktop',
'appinfo-test-gnome.desktop',
'appinfo-test-notgnome.desktop',
'appinfo-test.desktop',
'appinfo-test2.desktop',
'appinfo-test-static.desktop',
'file.c',
'org.gtk.test.dbusappinfo.desktop',
install_dir : installed_tests_execdir,

View File

@ -95,109 +95,114 @@ const gchar *mimecache_data =
"image/bmp=myapp4.desktop;myapp5.desktop;\n"
"image/png=myapp3.desktop;\n";
typedef struct
{
gchar *mimeapps_list_home; /* (owned) */
} Fixture;
/* Set up XDG_DATA_HOME and XDG_DATA_DIRS.
* XDG_DATA_DIRS/applications will contain mimeapps.list
* XDG_DATA_HOME/applications will contain myapp.desktop
* and myapp2.desktop, and no mimeapps.list
*/
static void
setup (void)
setup (Fixture *fixture,
gconstpointer test_data)
{
gchar *dir;
gchar *xdgconfighome;
gchar *xdgdatahome;
gchar *xdgdatadir;
const gchar *xdgdatahome;
const gchar * const *xdgdatadirs;
gchar *appdir;
gchar *apphome;
gchar *mimeapps;
gchar *name;
gboolean res;
gint res;
GError *error = NULL;
dir = g_get_current_dir ();
xdgconfighome = g_build_filename (dir, "xdgconfighome", NULL);
xdgdatahome = g_build_filename (dir, "xdgdatahome", NULL);
xdgdatadir = g_build_filename (dir, "xdgdatadir", NULL);
g_test_message ("setting XDG_CONFIG_HOME to '%s'\n", xdgconfighome);
g_setenv ("XDG_CONFIG_HOME", xdgconfighome, TRUE);
g_test_message ("setting XDG_DATA_HOME to '%s'\n", xdgdatahome);
g_setenv ("XDG_DATA_HOME", xdgdatahome, TRUE);
g_test_message ("setting XDG_DATA_DIRS to '%s'\n", xdgdatadir);
g_setenv ("XDG_DATA_DIRS", xdgdatadir, TRUE);
/* These are already set to a temporary directory through our use of
* %G_TEST_OPTION_ISOLATE_DIRS below. */
xdgdatahome = g_get_user_data_dir ();
xdgdatadirs = g_get_system_data_dirs ();
appdir = g_build_filename (xdgdatadir, "applications", NULL);
g_test_message ("creating '%s'\n", appdir);
appdir = g_build_filename (xdgdatadirs[0], "applications", NULL);
g_test_message ("creating '%s'", appdir);
res = g_mkdir_with_parents (appdir, 0700);
g_assert (res == 0);
g_assert_cmpint (res, ==, 0);
name = g_build_filename (appdir, "mimeapps.list", NULL);
g_test_message ("creating '%s'\n", name);
g_test_message ("creating '%s'", name);
g_file_set_contents (name, defaults_data, -1, &error);
g_assert_no_error (error);
g_free (name);
apphome = g_build_filename (xdgdatahome, "applications", NULL);
g_test_message ("creating '%s'\n", apphome);
g_test_message ("creating '%s'", apphome);
res = g_mkdir_with_parents (apphome, 0700);
g_assert (res == 0);
g_assert_cmpint (res, ==, 0);
name = g_build_filename (apphome, "myapp.desktop", NULL);
g_test_message ("creating '%s'\n", name);
g_test_message ("creating '%s'", name);
g_file_set_contents (name, myapp_data, -1, &error);
g_assert_no_error (error);
g_free (name);
name = g_build_filename (apphome, "myapp2.desktop", NULL);
g_test_message ("creating '%s'\n", name);
g_test_message ("creating '%s'", name);
g_file_set_contents (name, myapp2_data, -1, &error);
g_assert_no_error (error);
g_free (name);
name = g_build_filename (apphome, "myapp3.desktop", NULL);
g_test_message ("creating '%s'\n", name);
g_test_message ("creating '%s'", name);
g_file_set_contents (name, myapp3_data, -1, &error);
g_assert_no_error (error);
g_free (name);
name = g_build_filename (apphome, "myapp4.desktop", NULL);
g_test_message ("creating '%s'\n", name);
g_test_message ("creating '%s'", name);
g_file_set_contents (name, myapp4_data, -1, &error);
g_assert_no_error (error);
g_free (name);
name = g_build_filename (apphome, "myapp5.desktop", NULL);
g_test_message ("creating '%s'\n", name);
g_test_message ("creating '%s'", name);
g_file_set_contents (name, myapp5_data, -1, &error);
g_assert_no_error (error);
g_free (name);
name = g_build_filename (apphome, "nosuchapp.desktop", NULL);
g_test_message ("creating '%s'\n", name);
g_test_message ("creating '%s'", name);
g_file_set_contents (name, nosuchapp_data, -1, &error);
g_assert_no_error (error);
g_free (name);
mimeapps = g_build_filename (apphome, "mimeapps.list", NULL);
g_test_message ("removing '%s'\n", mimeapps);
g_test_message ("removing '%s'", mimeapps);
g_remove (mimeapps);
name = g_build_filename (apphome, "mimeinfo.cache", NULL);
g_test_message ("creating '%s'\n", name);
g_test_message ("creating '%s'", name);
g_file_set_contents (name, mimecache_data, -1, &error);
g_assert_no_error (error);
g_free (name);
g_free (dir);
g_free (xdgconfighome);
g_free (xdgdatahome);
g_free (xdgdatadir);
g_free (apphome);
g_free (appdir);
g_free (mimeapps);
/* Pointer to one of the temporary directories. */
fixture->mimeapps_list_home = g_build_filename (g_get_user_config_dir (), "mimeapps.list", NULL);
}
static void
test_mime_api (void)
teardown (Fixture *fixture,
gconstpointer test_data)
{
g_free (fixture->mimeapps_list_home);
}
static void
test_mime_api (Fixture *fixture,
gconstpointer test_data)
{
GAppInfo *appinfo;
GAppInfo *appinfo2;
@ -214,8 +219,8 @@ test_mime_api (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (def == NULL);
g_assert (list == NULL);
g_assert_null (def);
g_assert_null (list);
/* 1. add a non-default association */
g_app_info_add_supports_type (appinfo, contenttype, &error);
@ -223,9 +228,9 @@ test_mime_api (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo));
g_assert_true (g_app_info_equal (def, appinfo));
g_assert_cmpint (g_list_length (list), ==, 1);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -235,10 +240,10 @@ test_mime_api (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo));
g_assert_true (g_app_info_equal (def, appinfo));
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -248,10 +253,10 @@ test_mime_api (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo));
g_assert_true (g_app_info_equal (def, appinfo));
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -261,10 +266,10 @@ test_mime_api (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo));
g_assert_true (g_app_info_equal (def, appinfo));
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo2));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo2));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -273,8 +278,8 @@ test_mime_api (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (def == NULL);
g_assert (list == NULL);
g_assert_null (def);
g_assert_null (list);
g_object_unref (appinfo);
g_object_unref (appinfo2);
@ -286,7 +291,8 @@ test_mime_api (void)
* mimeapps.list to verify the results.
*/
static void
test_mime_file (void)
test_mime_file (Fixture *fixture,
gconstpointer test_data)
{
gchar **assoc;
GAppInfo *appinfo;
@ -297,13 +303,8 @@ test_mime_file (void)
gboolean res;
GAppInfo *def;
GList *list;
gchar *mimeapps;
gchar *dir;
const gchar *contenttype = "application/pdf";
dir = g_get_current_dir ();
mimeapps = g_build_filename (dir, "xdgconfighome", "mimeapps.list", NULL);
/* clear things out */
g_app_info_reset_type_associations (contenttype);
@ -312,25 +313,25 @@ test_mime_file (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (def == NULL);
g_assert (list == NULL);
g_assert_null (def);
g_assert_null (list);
/* 1. add a non-default association */
g_app_info_add_supports_type (appinfo, contenttype, &error);
g_assert_no_error (error);
keyfile = g_key_file_new ();
g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
g_key_file_load_from_file (keyfile, fixture->mimeapps_list_home, G_KEY_FILE_NONE, &error);
g_assert_no_error (error);
assoc = g_key_file_get_string_list (keyfile, "Added Associations", contenttype, NULL, &error);
g_assert_no_error (error);
g_assert (strv_equal (assoc, "myapp.desktop", NULL));
g_assert_true (strv_equal (assoc, "myapp.desktop", NULL));
g_strfreev (assoc);
/* we've unset XDG_DATA_DIRS so there should be no default */
assoc = g_key_file_get_string_list (keyfile, "Default Applications", contenttype, NULL, &error);
g_assert (error != NULL);
g_assert_nonnull (error);
g_clear_error (&error);
g_key_file_free (keyfile);
@ -340,16 +341,16 @@ test_mime_file (void)
g_assert_no_error (error);
keyfile = g_key_file_new ();
g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
g_key_file_load_from_file (keyfile, fixture->mimeapps_list_home, G_KEY_FILE_NONE, &error);
g_assert_no_error (error);
assoc = g_key_file_get_string_list (keyfile, "Added Associations", contenttype, NULL, &error);
g_assert_no_error (error);
g_assert (strv_equal (assoc, "myapp.desktop", "myapp2.desktop", NULL));
g_assert_true (strv_equal (assoc, "myapp.desktop", "myapp2.desktop", NULL));
g_strfreev (assoc);
assoc = g_key_file_get_string_list (keyfile, "Default Applications", contenttype, NULL, &error);
g_assert (error != NULL);
g_assert_nonnull (error);
g_clear_error (&error);
g_key_file_free (keyfile);
@ -359,12 +360,12 @@ test_mime_file (void)
g_assert_no_error (error);
keyfile = g_key_file_new ();
g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
g_key_file_load_from_file (keyfile, fixture->mimeapps_list_home, G_KEY_FILE_NONE, &error);
g_assert_no_error (error);
assoc = g_key_file_get_string_list (keyfile, "Added Associations", contenttype, NULL, &error);
g_assert_no_error (error);
g_assert (strv_equal (assoc, "myapp.desktop", "myapp2.desktop", NULL));
g_assert_true (strv_equal (assoc, "myapp.desktop", "myapp2.desktop", NULL));
g_strfreev (assoc);
str = g_key_file_get_string (keyfile, "Default Applications", contenttype, &error);
@ -379,12 +380,12 @@ test_mime_file (void)
g_assert_no_error (error);
keyfile = g_key_file_new ();
g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
g_key_file_load_from_file (keyfile, fixture->mimeapps_list_home, G_KEY_FILE_NONE, &error);
g_assert_no_error (error);
assoc = g_key_file_get_string_list (keyfile, "Added Associations", contenttype, NULL, &error);
g_assert_no_error (error);
g_assert (strv_equal (assoc, "myapp2.desktop", "myapp.desktop", NULL));
g_assert_true (strv_equal (assoc, "myapp2.desktop", "myapp.desktop", NULL));
g_strfreev (assoc);
g_key_file_free (keyfile);
@ -393,27 +394,25 @@ test_mime_file (void)
g_app_info_reset_type_associations (contenttype);
keyfile = g_key_file_new ();
g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
g_key_file_load_from_file (keyfile, fixture->mimeapps_list_home, G_KEY_FILE_NONE, &error);
g_assert_no_error (error);
res = g_key_file_has_key (keyfile, "Added Associations", contenttype, NULL);
g_assert (!res);
g_assert_false (res);
res = g_key_file_has_key (keyfile, "Default Applications", contenttype, NULL);
g_assert (!res);
g_assert_false (res);
g_key_file_free (keyfile);
g_object_unref (appinfo);
g_object_unref (appinfo2);
g_free (mimeapps);
g_free (dir);
}
/* test interaction between mimeapps.list at different levels */
static void
test_mime_default (void)
test_mime_default (Fixture *fixture,
gconstpointer test_data)
{
GAppInfo *appinfo;
GAppInfo *appinfo2;
@ -433,9 +432,9 @@ test_mime_default (void)
/* myapp3 is set as the default in defaults.list */
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo3));
g_assert_true (g_app_info_equal (def, appinfo3));
g_assert_cmpint (g_list_length (list), ==, 1);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo3));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo3));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -445,10 +444,10 @@ test_mime_default (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo3)); /* default is unaffected */
g_assert_true (g_app_info_equal (def, appinfo3)); /* default is unaffected */
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo3));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo3));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -458,11 +457,11 @@ test_mime_default (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo3));
g_assert_true (g_app_info_equal (def, appinfo3));
g_assert_cmpint (g_list_length (list), ==, 3);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
g_assert (g_app_info_equal ((GAppInfo*)list->next->next->data, appinfo3));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->next->data, appinfo3));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -472,11 +471,11 @@ test_mime_default (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo));
g_assert_true (g_app_info_equal (def, appinfo));
g_assert_cmpint (g_list_length (list), ==, 3);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
g_assert (g_app_info_equal ((GAppInfo*)list->next->next->data, appinfo3));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->next->data, appinfo3));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -490,7 +489,8 @@ test_mime_default (void)
* change the default
*/
static void
test_mime_default_last_used (void)
test_mime_default_last_used (Fixture *fixture,
gconstpointer test_data)
{
GAppInfo *appinfo4;
GAppInfo *appinfo5;
@ -509,10 +509,10 @@ test_mime_default_last_used (void)
/* myapp4 and myapp5 can both handle image/bmp */
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo4));
g_assert_true (g_app_info_equal (def, appinfo4));
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -522,10 +522,10 @@ test_mime_default_last_used (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo4)); /* default is unaffected */
g_assert_true (g_app_info_equal (def, appinfo4)); /* default is unaffected */
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -535,10 +535,10 @@ test_mime_default_last_used (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo4));
g_assert_true (g_app_info_equal (def, appinfo4));
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -548,10 +548,10 @@ test_mime_default_last_used (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo5));
g_assert_true (g_app_info_equal (def, appinfo5));
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -561,10 +561,10 @@ test_mime_default_last_used (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo5));
g_assert_true (g_app_info_equal (def, appinfo5));
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -574,10 +574,10 @@ test_mime_default_last_used (void)
def = g_app_info_get_default_for_type (contenttype, FALSE);
list = g_app_info_get_recommended_for_type (contenttype);
g_assert (g_app_info_equal (def, appinfo5));
g_assert_true (g_app_info_equal (def, appinfo5));
g_assert_cmpint (g_list_length (list), ==, 2);
g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
g_assert_true (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
g_assert_true (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
g_object_unref (def);
g_list_free_full (list, g_object_unref);
@ -586,13 +586,14 @@ test_mime_default_last_used (void)
}
static void
test_scheme_handler (void)
test_scheme_handler (Fixture *fixture,
gconstpointer test_data)
{
GAppInfo *info, *info5;
info5 = (GAppInfo*)g_desktop_app_info_new ("myapp5.desktop");
info = g_app_info_get_default_for_uri_scheme ("ftp");
g_assert (g_app_info_equal (info, info5));
g_assert_true (g_app_info_equal (info, info5));
g_object_unref (info);
g_object_unref (info5);
@ -601,23 +602,25 @@ test_scheme_handler (void)
/* test that g_app_info_* ignores desktop files with nonexisting executables
*/
static void
test_mime_ignore_nonexisting (void)
test_mime_ignore_nonexisting (Fixture *fixture,
gconstpointer test_data)
{
GAppInfo *appinfo;
appinfo = (GAppInfo*)g_desktop_app_info_new ("nosuchapp.desktop");
g_assert (appinfo == NULL);
g_assert_null (appinfo);
}
static void
test_all (void)
test_all (Fixture *fixture,
gconstpointer test_data)
{
GList *all, *l;
all = g_app_info_get_all ();
for (l = all; l; l = l->next)
g_assert (G_IS_APP_INFO (l->data));
g_assert_true (G_IS_APP_INFO (l->data));
g_list_free_full (all, g_object_unref);
}
@ -625,17 +628,21 @@ test_all (void)
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
setup ();
g_test_add_func ("/appinfo/mime/api", test_mime_api);
g_test_add_func ("/appinfo/mime/default", test_mime_default);
g_test_add_func ("/appinfo/mime/file", test_mime_file);
g_test_add_func ("/appinfo/mime/scheme-handler", test_scheme_handler);
g_test_add_func ("/appinfo/mime/default-last-used", test_mime_default_last_used);
g_test_add_func ("/appinfo/mime/ignore-nonexisting", test_mime_ignore_nonexisting);
g_test_add_func ("/appinfo/all", test_all);
g_test_add ("/appinfo/mime/api", Fixture, NULL, setup,
test_mime_api, teardown);
g_test_add ("/appinfo/mime/default", Fixture, NULL, setup,
test_mime_default, teardown);
g_test_add ("/appinfo/mime/file", Fixture, NULL, setup,
test_mime_file, teardown);
g_test_add ("/appinfo/mime/scheme-handler", Fixture, NULL, setup,
test_scheme_handler, teardown);
g_test_add ("/appinfo/mime/default-last-used", Fixture, NULL, setup,
test_mime_default_last_used, teardown);
g_test_add ("/appinfo/mime/ignore-nonexisting", Fixture, NULL, setup,
test_mime_ignore_nonexisting, teardown);
g_test_add ("/appinfo/all", Fixture, NULL, setup, test_all, teardown);
return g_test_run ();
}

View File

@ -56,6 +56,8 @@ static XdgCallbackList *callback_list = NULL;
static XdgIconList *icon_list = NULL;
static XdgIconList *generic_icon_list = NULL;
static char **xdg_dirs = NULL; /* NULL terminated */
XdgMimeCache **_caches = NULL;
static int n_caches = 0;
@ -139,8 +141,8 @@ xdg_mime_init_from_directory (const char *directory)
assert (directory != NULL);
file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
file_name = malloc (strlen (directory) + strlen ("/mime.cache") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime.cache");
if (stat (file_name, &st) == 0)
{
XdgMimeCache *cache = _xdg_mime_cache_new_from_file (file_name);
@ -159,8 +161,8 @@ xdg_mime_init_from_directory (const char *directory)
}
free (file_name);
file_name = malloc (strlen (directory) + strlen ("/mime/globs2") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/globs2");
file_name = malloc (strlen (directory) + strlen ("/globs2") + 1);
strcpy (file_name, directory); strcat (file_name, "/globs2");
if (stat (file_name, &st) == 0)
{
_xdg_mime_glob_read_from_file (global_hash, file_name, TRUE);
@ -169,8 +171,8 @@ xdg_mime_init_from_directory (const char *directory)
else
{
free (file_name);
file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/globs");
file_name = malloc (strlen (directory) + strlen ("/globs") + 1);
strcpy (file_name, directory); strcat (file_name, "/globs");
if (stat (file_name, &st) == 0)
{
_xdg_mime_glob_read_from_file (global_hash, file_name, FALSE);
@ -182,8 +184,8 @@ xdg_mime_init_from_directory (const char *directory)
}
}
file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/magic");
file_name = malloc (strlen (directory) + strlen ("/magic") + 1);
strcpy (file_name, directory); strcat (file_name, "/magic");
if (stat (file_name, &st) == 0)
{
_xdg_mime_magic_read_from_file (global_magic, file_name);
@ -194,69 +196,81 @@ xdg_mime_init_from_directory (const char *directory)
free (file_name);
}
file_name = malloc (strlen (directory) + strlen ("/mime/aliases") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/aliases");
file_name = malloc (strlen (directory) + strlen ("/aliases") + 1);
strcpy (file_name, directory); strcat (file_name, "/aliases");
_xdg_mime_alias_read_from_file (alias_list, file_name);
free (file_name);
file_name = malloc (strlen (directory) + strlen ("/mime/subclasses") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/subclasses");
file_name = malloc (strlen (directory) + strlen ("/subclasses") + 1);
strcpy (file_name, directory); strcat (file_name, "/subclasses");
_xdg_mime_parent_read_from_file (parent_list, file_name);
free (file_name);
file_name = malloc (strlen (directory) + strlen ("/mime/icons") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/icons");
file_name = malloc (strlen (directory) + strlen ("/icons") + 1);
strcpy (file_name, directory); strcat (file_name, "/icons");
_xdg_mime_icon_read_from_file (icon_list, file_name);
free (file_name);
file_name = malloc (strlen (directory) + strlen ("/mime/generic-icons") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/generic-icons");
file_name = malloc (strlen (directory) + strlen ("/generic-icons") + 1);
strcpy (file_name, directory); strcat (file_name, "/generic-icons");
_xdg_mime_icon_read_from_file (generic_icon_list, file_name);
free (file_name);
return FALSE; /* Keep processing */
}
/* Runs a command on all the directories in the search path */
/* Set @xdg_dirs from the environment. It must not have been set already. */
static void
xdg_run_command_on_dirs (XdgDirectoryFunc func,
void *user_data)
xdg_init_dirs (void)
{
const char *xdg_data_home;
const char *xdg_data_dirs;
const char *xdg_data_home, *home, *xdg_data_dirs;
const char *ptr;
size_t n_dirs = 0;
size_t i, current_dir;
assert (xdg_dirs == NULL);
xdg_data_home = getenv ("XDG_DATA_HOME");
if (xdg_data_home)
{
if ((func) (xdg_data_home, user_data))
return;
}
else
{
const char *home;
home = getenv ("HOME");
if (home != NULL)
{
char *guessed_xdg_home;
int stop_processing;
guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1);
strcpy (guessed_xdg_home, home);
strcat (guessed_xdg_home, "/.local/share/");
stop_processing = (func) (guessed_xdg_home, user_data);
free (guessed_xdg_home);
if (stop_processing)
return;
}
}
home = getenv ("HOME");
xdg_data_dirs = getenv ("XDG_DATA_DIRS");
if (xdg_data_dirs == NULL)
xdg_data_dirs = "/usr/local/share/:/usr/share/";
/* Work out how many dirs were dealing with. */
if (xdg_data_home != NULL || home != NULL)
n_dirs++;
n_dirs++; /* initial entry in @xdg_data_dirs */
for (i = 0; xdg_data_dirs[i] != '\0'; i++)
if (xdg_data_dirs[i] == ':')
n_dirs++;
xdg_dirs = calloc (n_dirs + 1 /* NULL terminator */, sizeof (char *));
current_dir = 0;
/* $XDG_DATA_HOME */
if (xdg_data_home != NULL)
{
char *mime_subdir;
mime_subdir = malloc (strlen (xdg_data_home) + strlen ("/mime/") + 1);
strcpy (mime_subdir, xdg_data_home);
strcat (mime_subdir, "/mime/");
xdg_dirs[current_dir++] = mime_subdir;
}
else if (home != NULL)
{
char *guessed_xdg_home;
guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/mime/") + 1);
strcpy (guessed_xdg_home, home);
strcat (guessed_xdg_home, "/.local/share/mime/");
xdg_dirs[current_dir++] = guessed_xdg_home;
}
/* $XDG_DATA_DIRS */
ptr = xdg_data_dirs;
while (*ptr != '\000')
@ -264,33 +278,83 @@ xdg_run_command_on_dirs (XdgDirectoryFunc func,
const char *end_ptr;
char *dir;
int len;
int stop_processing;
end_ptr = ptr;
while (*end_ptr != ':' && *end_ptr != '\000')
end_ptr ++;
end_ptr ++;
if (end_ptr == ptr)
{
ptr++;
continue;
}
{
ptr++;
continue;
}
if (*end_ptr == ':')
len = end_ptr - ptr;
len = end_ptr - ptr;
else
len = end_ptr - ptr + 1;
dir = malloc (len + 1);
len = end_ptr - ptr + 1;
dir = malloc (len + strlen ("/mime/") + 1);
strncpy (dir, ptr, len);
dir[len] = '\0';
stop_processing = (func) (dir, user_data);
free (dir);
strcat (dir, "/mime/");
if (stop_processing)
return;
xdg_dirs[current_dir++] = dir;
ptr = end_ptr;
}
/* NULL terminator */
xdg_dirs[current_dir] = NULL;
need_reread = TRUE;
}
/* Runs a command on all the directories in the search path (@xdg_dirs). */
static void
xdg_run_command_on_dirs (XdgDirectoryFunc func,
void *user_data)
{
size_t i;
if (xdg_dirs == NULL)
xdg_init_dirs ();
for (i = 0; xdg_dirs[i] != NULL; i++)
{
if ((func) (xdg_dirs[i], user_data))
return;
}
}
/* Allows the calling code to override the directories used by xdgmime, without
* having to change environment variables in a running process (which is not
* thread safe). This is intended to be used by tests. The changes will be
* picked up by xdg_mime_init() next time public API is called.
*
* This will set @xdg_dirs. Directories in @dirs must be complete, including
* the conventional `/mime` subdirectory. This is to allow tests to override
* them without the need to create a subdirectory. */
void
xdg_mime_set_dirs (const char * const *dirs)
{
size_t i;
for (i = 0; xdg_dirs != NULL && xdg_dirs[i] != NULL; i++)
free (xdg_dirs[i]);
if (xdg_dirs != NULL)
free (xdg_dirs[i]);
xdg_dirs = NULL;
if (dirs != NULL)
{
for (i = 0; dirs[i] != NULL; i++);
xdg_dirs = calloc (i + 1 /* NULL terminator */, sizeof (char*));
for (i = 0; dirs[i] != NULL; i++)
xdg_dirs[i] = strdup (dirs[i]);
xdg_dirs[i] = NULL;
}
need_reread = TRUE;
}
/* Checks file_path to make sure it has the same mtime as last time it was
@ -344,8 +408,8 @@ xdg_check_dir (const char *directory,
assert (directory != NULL);
/* Check the mime.cache file */
file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
file_name = malloc (strlen (directory) + strlen ("/mime.cache") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime.cache");
invalid = xdg_check_file (file_name, &exists);
free (file_name);
if (invalid)
@ -359,8 +423,8 @@ xdg_check_dir (const char *directory,
}
/* Check the globs file */
file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/globs");
file_name = malloc (strlen (directory) + strlen ("/globs") + 1);
strcpy (file_name, directory); strcat (file_name, "/globs");
invalid = xdg_check_file (file_name, NULL);
free (file_name);
if (invalid)
@ -370,8 +434,8 @@ xdg_check_dir (const char *directory,
}
/* Check the magic file */
file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/magic");
file_name = malloc (strlen (directory) + strlen ("/magic") + 1);
strcpy (file_name, directory); strcat (file_name, "/magic");
invalid = xdg_check_file (file_name, NULL);
free (file_name);
if (invalid)

View File

@ -127,6 +127,8 @@ int xdg_mime_register_reload_callback (XdgMimeCallback callback,
void xdg_mime_remove_callback (int callback_id);
#endif
void xdg_mime_set_dirs (const char * const *dirs);
/* Private versions of functions that don't call xdg_mime_init () */
int _xdg_mime_mime_type_equal (const char *mime_a,
const char *mime_b);

116
glib.supp
View File

@ -229,13 +229,21 @@
}
{
g-get-language-names
g-get-language-names-malloc
Memcheck:Leak
fun:malloc
...
fun:g_get_language_names
}
{
g-get-language-names-calloc
Memcheck:Leak
fun:calloc
...
fun:g_get_language_names
}
{
g-static-mutex
Memcheck:Leak
@ -543,3 +551,109 @@
...
fun:g_object_new_valist
}
# g_set_user_dirs() deliberately leaks the previous cached g_get_user_*() values.
{
g_set_user_dirs_str
Memcheck:Leak
fun:malloc
...
fun:set_str_if_different
fun:g_set_user_dirs
}
# g_set_user_dirs() deliberately leaks the previous cached g_get_user_*() values.
{
g_set_user_dirs_strv
Memcheck:Leak
fun:malloc
...
fun:set_strv_if_different
fun:g_set_user_dirs
}
# g_get_system_data_dirs() caches a one-time allocation
{
g_get_system_data_dirs
Memcheck:Leak
fun:malloc
...
fun:g_build_system_data_dirs
fun:g_get_system_data_dirs
}
# g_get_user_data_dir() caches a one-time allocation
{
g_get_user_data_dir
Memcheck:Leak
fun:realloc
...
fun:g_build_user_data_dir
fun:g_get_user_data_dir
}
# gdesktopappinfo.c caches a one-time allocation global table of @desktop_file_dirs.
{
desktop_file_dirs_malloc
Memcheck:Leak
fun:malloc
...
fun:desktop_file_dirs_lock
}
# gdesktopappinfo.c caches a one-time allocation global table of @desktop_file_dirs.
{
desktop_file_dirs_realloc
Memcheck:Leak
fun:realloc
...
fun:desktop_file_dirs_lock
}
# gdesktopappinfo.c caches a one-time allocation global table of @desktop_file_dirs.
{
desktop_file_dir_unindexed_setup_search
Memcheck:Leak
fun:malloc
...
fun:desktop_file_dir_unindexed_setup_search
fun:desktop_file_dir_unindexed_setup_search
}
# g_io_extension_point_register() caches a one-time allocation global table of @extension_points.
{
g_io_extension_point_register
Memcheck:Leak
fun:calloc
...
fun:g_io_extension_point_register
}
# g_strerror() caches a one-time allocation global table of @errors.
{
g_strerror
Memcheck:Leak
fun:malloc
...
fun:g_locale_to_utf8
fun:g_strerror
}
# g_socket_connection_factory_register_type() caches a one-time allocation global table of @connection_types.
{
g_socket_connection_factory_register_type
Memcheck:Leak
fun:calloc
...
fun:g_socket_connection_factory_register_type
}
# g_dbus_error_quark() never unregisters itself as a GDBusError domain, as its always available
{
g_dbus_error_quark
Memcheck:Leak
fun:calloc
...
fun:g_dbus_error_register_error_domain
fun:g_dbus_error_quark
}

View File

@ -191,6 +191,7 @@ libglib_2_0_la_SOURCES = \
gunicodeprivate.h \
gurifuncs.c \
gutils.c \
gutilsprivate.h \
guuid.c \
gvalgrind.h \
gvariant.h \

View File

@ -3181,6 +3181,40 @@ g_strv_contains (const gchar * const *strv,
return FALSE;
}
/**
* g_strv_equal:
* @strv1: a %NULL-terminated array of strings
* @strv2: another %NULL-terminated array of strings
*
* Checks if @strv1 and @strv2 contain exactly the same elements in exactly the
* same order. Elements are compared using g_str_equal(). To match independently
* of order, sort the arrays first (using g_qsort_with_data() or similar).
*
* Two empty arrays are considered equal. Neither @strv1 not @strv2 may be
* %NULL.
*
* Returns: %TRUE if @strv1 and @strv2 are equal
* Since: 2.60
*/
gboolean
g_strv_equal (const gchar * const *strv1,
const gchar * const *strv2)
{
g_return_val_if_fail (strv1 != NULL, FALSE);
g_return_val_if_fail (strv2 != NULL, FALSE);
if (strv1 == strv2)
return TRUE;
for (; *strv1 != NULL && *strv2 != NULL; strv1++, strv2++)
{
if (!g_str_equal (*strv1, *strv2))
return FALSE;
}
return (*strv1 == NULL && *strv2 == NULL);
}
static gboolean
str_has_sign (const gchar *str)
{

View File

@ -307,6 +307,10 @@ GLIB_AVAILABLE_IN_2_44
gboolean g_strv_contains (const gchar * const *strv,
const gchar *str);
GLIB_AVAILABLE_IN_2_60
gboolean g_strv_equal (const gchar * const *strv1,
const gchar * const *strv2);
/* Convenience ASCII string to number API */
/**

View File

@ -27,7 +27,6 @@
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <glib/gstdio.h>
#endif
#include <string.h>
#include <stdlib.h>
@ -44,6 +43,7 @@
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif /* HAVE_SYS_SELECT_H */
#include <glib/gstdio.h>
#include "gmain.h"
#include "gpattern.h"
@ -53,6 +53,7 @@
#include "gslice.h"
#include "gspawn.h"
#include "glib-private.h"
#include "gutilsprivate.h"
/**
@ -825,6 +826,9 @@ static const char * const g_test_result_names[] = {
static int test_log_fd = -1;
static gboolean test_mode_fatal = TRUE;
static gboolean g_test_run_once = TRUE;
static gboolean test_isolate_dirs = FALSE;
static gchar *test_isolate_dirs_tmpdir = NULL;
static const gchar *test_tmpdir = NULL;
static gboolean test_run_list = FALSE;
static gchar *test_run_seedstr = NULL;
G_LOCK_DEFINE_STATIC (test_run_rand);
@ -1261,15 +1265,139 @@ parse_args (gint *argc_p,
*argc_p = e;
}
/* A fairly naive `rm -rf` implementation to clean up after unit tests. */
static void
rm_rf (const gchar *path)
{
GDir *dir = NULL;
const gchar *entry;
dir = g_dir_open (path, 0, NULL);
if (dir == NULL)
{
/* Assume its a file. */
g_remove (path);
return;
}
while ((entry = g_dir_read_name (dir)) != NULL)
{
gchar *sub_path = g_build_filename (path, entry, NULL);
rm_rf (sub_path);
g_free (sub_path);
}
g_dir_close (dir);
g_rmdir (path);
}
/* Implement the %G_TEST_OPTION_ISOLATE_DIRS option, iff its enabled. Create
* a temporary directory for this unit test (disambiguated using @test_run_name)
* and use g_set_user_dirs() to point various XDG directories into it, without
* having to call setenv() in a process which potentially has threads running.
*
* Note that this is called for each unit test, and hence wont have taken
* effect before g_test_run() is called in the unit tests main(). Hence
* references to XDG variables in main() will not be using the temporary
* directory. */
static gboolean
test_do_isolate_dirs (GError **error)
{
gchar *subdir = NULL;
gchar *home_dir = NULL, *cache_dir = NULL, *config_dir = NULL;
gchar *data_dir = NULL, *runtime_dir = NULL;
gchar *config_dirs[3];
gchar *data_dirs[3];
if (!test_isolate_dirs)
return TRUE;
/* The @test_run_name includes the test suites, so may be several directories
* deep. Add a `.dirs` directory to contain all the paths we create, and
* guarantee none of them clash with test paths below the current one test
* paths may not contain components starting with `.`. */
subdir = g_build_filename (test_tmpdir, test_run_name, ".dirs", NULL);
/* We have to create the runtime directory (because it must be bound to
* the session lifetime, which we consider to be the lifetime of the unit
* test for testing purposes see
* https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html.
* We dont need to create the other directories the specification
* requires that client code create them if they dont exist. Not creating
* them automatically is a good test of clients adherence to the spec
* and error handling of missing directories. */
runtime_dir = g_build_filename (subdir, "runtime", NULL);
if (g_mkdir_with_parents (runtime_dir, 0700) != 0)
{
gint saved_errno = errno;
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
"Failed to create XDG_RUNTIME_DIR %s: %s",
runtime_dir, g_strerror (saved_errno));
g_free (runtime_dir);
g_free (subdir);
return FALSE;
}
home_dir = g_build_filename (subdir, "home", NULL);
cache_dir = g_build_filename (subdir, "cache", NULL);
config_dir = g_build_filename (subdir, "config", NULL);
data_dir = g_build_filename (subdir, "data", NULL);
config_dirs[0] = g_build_filename (subdir, "system-config1", NULL);
config_dirs[1] = g_build_filename (subdir, "system-config2", NULL);
config_dirs[2] = NULL;
data_dirs[0] = g_build_filename (subdir, "system-data1", NULL);
data_dirs[1] = g_build_filename (subdir, "system-data2", NULL);
data_dirs[2] = NULL;
/* Remember to update the documentation for %G_TEST_OPTION_ISOLATE_DIRS if
* this list changes. */
g_set_user_dirs ("HOME", home_dir,
"XDG_CACHE_HOME", cache_dir,
"XDG_CONFIG_DIRS", config_dirs,
"XDG_CONFIG_HOME", config_dir,
"XDG_DATA_DIRS", data_dirs,
"XDG_DATA_HOME", data_dir,
"XDG_RUNTIME_DIR", runtime_dir,
NULL);
g_free (runtime_dir);
g_free (data_dir);
g_free (config_dir);
g_free (cache_dir);
g_free (home_dir);
g_free (data_dirs[1]);
g_free (data_dirs[0]);
g_free (config_dirs[1]);
g_free (config_dirs[0]);
g_free (subdir);
return TRUE;
}
/* Clean up after test_do_isolate_dirs(). */
static void
test_rm_isolate_dirs (void)
{
gchar *subdir = NULL;
if (!test_isolate_dirs)
return;
subdir = g_build_filename (test_tmpdir, test_run_name, NULL);
rm_rf (subdir);
g_free (subdir);
}
/**
* g_test_init:
* @argc: Address of the @argc parameter of the main() function.
* Changed if any arguments were handled.
* @argv: Address of the @argv parameter of main().
* Any parameters understood by g_test_init() stripped before return.
* @...: %NULL-terminated list of special options. Currently the only
* defined option is `"no_g_set_prgname"`, which
* will cause g_test_init() to not call g_set_prgname().
* @...: %NULL-terminated list of special options, documented below.
*
* Initialize the GLib testing framework, e.g. by seeding the
* test random number generator, the name for g_get_prgname()
@ -1303,6 +1431,14 @@ parse_args (gint *argc_p,
*
* - `--debug-log`: Debug test logging output.
*
* Options which can be passed to @... are:
*
* - `"no_g_set_prgname"`: Causes g_test_init() to not call g_set_prgname().
* - %G_TEST_OPTION_ISOLATE_DIRS: Creates a unique temporary directory for each
* unit test and uses g_set_user_dirs() to set XDG directories to point into
* that temporary directory for the duration of the unit test. See the
* documentation for %G_TEST_OPTION_ISOLATE_DIRS.
*
* Since 2.58, if tests are compiled with `G_DISABLE_ASSERT` defined,
* g_test_init() will print an error and exit. This is to prevent no-op tests
* from being executed, as g_assert() is commonly (erroneously) used in unit
@ -1335,6 +1471,8 @@ void
{
if (g_strcmp0 (option, "no_g_set_prgname") == 0)
no_g_set_prgname = TRUE;
else if (g_strcmp0 (option, G_TEST_OPTION_ISOLATE_DIRS) == 0)
test_isolate_dirs = TRUE;
}
va_end (args);
@ -1348,6 +1486,77 @@ void
if (!g_get_prgname() && !no_g_set_prgname)
g_set_prgname ((*argv)[0]);
/* Set up the temporary directory for isolating the test. We have to do this
* early, as we want the return values from g_get_user_data_dir() (and
* friends) to return subdirectories of the temporary directory throughout
* the setup function, test, and teardown function, for each unit test.
* See test_do_isolate_dirs().
*
* The directory is deleted at the bottom of g_test_run().
*
* Rather than setting the XDG_* environment variables we use a new
* G_TEST_TMPDIR variable which gives the top-level temporary directory. This
* allows test subprocesses to reuse the same temporary directory when
* g_test_init() is called in them. */
if (test_isolate_dirs)
{
if (g_getenv ("G_TEST_TMPDIR") == NULL)
{
gchar *test_prgname = NULL;
gchar *tmpl = NULL;
GError *local_error = NULL;
test_prgname = g_path_get_basename (g_get_prgname ());
if (*test_prgname == '\0')
test_prgname = g_strdup ("unknown");
tmpl = g_strdup_printf ("test_%s_XXXXXX", test_prgname);
g_free (test_prgname);
test_isolate_dirs_tmpdir = g_dir_make_tmp (tmpl, &local_error);
if (local_error != NULL)
{
g_printerr ("%s: Failed to create temporary directory: %s\n",
(*argv)[0], local_error->message);
g_error_free (local_error);
exit (1);
}
g_free (tmpl);
/* Propagate the temporary directory to subprocesses. */
g_setenv ("G_TEST_TMPDIR", test_isolate_dirs_tmpdir, TRUE);
/* And clear the traditional environment variables so subprocesses
* spawned by the code under test cant trash anything. If a test
* spawns a process, the test is responsible for propagating
* appropriate environment variables.
*
* We assume that any in-process code will use g_get_user_data_dir()
* and friends, rather than getenv() directly.
*
* We set them to /dev/null as that should fairly obviously not
* accidentally work, and should be fairly greppable. */
{
const gchar *overridden_environment_variables[] =
{
"HOME",
"XDG_CACHE_HOME",
"XDG_CONFIG_DIRS",
"XDG_CONFIG_HOME",
"XDG_DATA_DIRS",
"XDG_DATA_HOME",
"XDG_RUNTIME_DIR",
};
gsize i;
for (i = 0; i < G_N_ELEMENTS (overridden_environment_variables); i++)
g_setenv (overridden_environment_variables[i], "/dev/null", TRUE);
}
}
/* Cache this for the remainder of this process lifetime. */
test_tmpdir = g_getenv ("G_TEST_TMPDIR");
}
/* sanity check */
if (test_tap_log)
{
@ -1798,6 +2007,14 @@ g_test_run (void)
if (g_test_run_suite (g_test_get_root()) != 0)
return 1;
/* Clean up the temporary directory. */
if (test_isolate_dirs_tmpdir != NULL)
{
rm_rf (test_isolate_dirs_tmpdir);
g_free (test_isolate_dirs_tmpdir);
test_isolate_dirs_tmpdir = NULL;
}
/* 77 is special to Automake's default driver, but not Automake's TAP driver
* or Perl's prove(1) TAP driver. */
if (test_tap_log)
@ -1914,6 +2131,7 @@ g_test_add_vtable (const char *testpath,
g_return_if_fail (testpath != NULL);
g_return_if_fail (g_path_is_absolute (testpath));
g_return_if_fail (fixture_test_func != NULL);
g_return_if_fail (!test_isolate_dirs || strstr (testpath, "/.") == NULL);
suite = g_test_get_root();
segments = g_strsplit (testpath, "/", -1);
@ -2102,6 +2320,10 @@ g_test_set_nonfatal_assertions (void)
* the test will be skipped by default, and only run if explicitly
* required via the `-p` command-line option or g_test_trap_subprocess().
*
* No component of @testpath may start with a dot (`.`) if the
* %G_TEST_OPTION_ISOLATE_DIRS option is being used; and it is recommended to
* do so even if it isnt.
*
* Since: 2.16
*/
void
@ -2140,6 +2362,10 @@ g_test_add_func (const char *testpath,
* the test will be skipped by default, and only run if explicitly
* required via the `-p` command-line option or g_test_trap_subprocess().
*
* No component of @testpath may start with a dot (`.`) if the
* %G_TEST_OPTION_ISOLATE_DIRS option is being used; and it is recommended to
* do so even if it isnt.
*
* Since: 2.16
*/
void
@ -2353,25 +2579,38 @@ test_case_run (GTestCase *tc)
g_test_skip ("by request (-s option)");
else
{
g_timer_start (test_run_timer);
fixture = tc->fixture_size ? g_malloc0 (tc->fixture_size) : tc->test_data;
test_run_seed (test_run_seedstr);
if (tc->fixture_setup)
tc->fixture_setup (fixture, tc->test_data);
tc->fixture_test (fixture, tc->test_data);
test_trap_clear();
while (test_destroy_queue)
GError *local_error = NULL;
if (!test_do_isolate_dirs (&local_error))
{
DestroyEntry *dentry = test_destroy_queue;
test_destroy_queue = dentry->next;
dentry->destroy_func (dentry->destroy_data);
g_slice_free (DestroyEntry, dentry);
g_test_log (G_TEST_LOG_ERROR, local_error->message, NULL, 0, NULL);
g_test_fail ();
g_error_free (local_error);
}
if (tc->fixture_teardown)
tc->fixture_teardown (fixture, tc->test_data);
if (tc->fixture_size)
g_free (fixture);
g_timer_stop (test_run_timer);
else
{
g_timer_start (test_run_timer);
fixture = tc->fixture_size ? g_malloc0 (tc->fixture_size) : tc->test_data;
test_run_seed (test_run_seedstr);
if (tc->fixture_setup)
tc->fixture_setup (fixture, tc->test_data);
tc->fixture_test (fixture, tc->test_data);
test_trap_clear();
while (test_destroy_queue)
{
DestroyEntry *dentry = test_destroy_queue;
test_destroy_queue = dentry->next;
dentry->destroy_func (dentry->destroy_data);
g_slice_free (DestroyEntry, dentry);
}
if (tc->fixture_teardown)
tc->fixture_teardown (fixture, tc->test_data);
if (tc->fixture_size)
g_free (fixture);
g_timer_stop (test_run_timer);
}
test_rm_isolate_dirs ();
}
success = test_run_success;
test_run_success = G_TEST_RUN_FAILURE;
@ -3781,25 +4020,3 @@ g_test_get_filename (GTestFileType file_type,
return result;
}
/* --- macros docs START --- */
/**
* g_test_add:
* @testpath: The test path for a new test case.
* @Fixture: The type of a fixture data structure.
* @tdata: Data argument for the test functions.
* @fsetup: The function to set up the fixture data.
* @ftest: The actual test function.
* @fteardown: The function to tear down the fixture data.
*
* Hook up a new test case at @testpath, similar to g_test_add_func().
* A fixture data structure with setup and teardown functions may be provided,
* similar to g_test_create_case().
*
* g_test_add() is implemented as a macro, so that the fsetup(), ftest() and
* fteardown() callbacks can expect a @Fixture pointer as their first argument
* in a type safe manner. They otherwise have type #GTestFixtureFunc.
*
* Since: 2.16
**/
/* --- macros docs END --- */

View File

@ -165,6 +165,36 @@ void g_test_init (int *argc,
char ***argv,
...) G_GNUC_NULL_TERMINATED;
/**
* G_TEST_OPTION_ISOLATE_DIRS:
*
* Creates a unique temporary directory for each unit test and uses
* g_set_user_dirs() to set XDG directories to point into subdirectories of it
* for the duration of the unit test. The directory tree is cleaned up after the
* test finishes successfully. Note that this doesnt take effect until
* g_test_run() is called, so calls to (for example) g_get_user_home_dir() will
* return the system-wide value when made in a test programs main() function.
*
* The following functions will return subdirectories of the temporary directory
* when this option is used. The specific subdirectory paths in use are not
* guaranteed to be stable API always use a getter function to retrieve them.
*
* - g_get_home_dir()
* - g_get_user_cache_dir()
* - g_get_system_config_dirs()
* - g_get_user_config_dir()
* - g_get_system_data_dirs()
* - g_get_user_data_dir()
* - g_get_user_runtime_dir()
*
* The subdirectories may not be created by the test harness; as with normal
* calls to functions like g_get_user_cache_dir(), the caller must be prepared
* to create the directory if it doesnt exist.
*
* Since: 2.60
*/
#define G_TEST_OPTION_ISOLATE_DIRS "isolate_dirs"
/* While we discourage its use, g_assert() is often used in unit tests
* (especially in legacy code). g_assert_*() should really be used instead.
* g_assert() can be disabled at client program compile time, which can render
@ -230,7 +260,25 @@ gboolean g_test_failed (void);
GLIB_AVAILABLE_IN_2_38
void g_test_set_nonfatal_assertions (void);
/* hook up a test with fixture under test path */
/**
* g_test_add:
* @testpath: The test path for a new test case.
* @Fixture: The type of a fixture data structure.
* @tdata: Data argument for the test functions.
* @fsetup: The function to set up the fixture data.
* @ftest: The actual test function.
* @fteardown: The function to tear down the fixture data.
*
* Hook up a new test case at @testpath, similar to g_test_add_func().
* A fixture data structure with setup and teardown functions may be provided,
* similar to g_test_create_case().
*
* g_test_add() is implemented as a macro, so that the fsetup(), ftest() and
* fteardown() callbacks can expect a @Fixture pointer as their first argument
* in a type safe manner. They otherwise have type #GTestFixtureFunc.
*
* Since: 2.16
*/
#define g_test_add(testpath, Fixture, tdata, fsetup, ftest, fteardown) \
G_STMT_START { \
void (*add_vtable) (const char*, \

View File

@ -29,6 +29,7 @@
#include "config.h"
#include "gutils.h"
#include "gutilsprivate.h"
#include <stdarg.h>
#include <stdlib.h>
@ -555,12 +556,13 @@ typedef struct
gchar *home_dir;
} UserDatabaseEntry;
/* These must all be read/written with @g_utils_global held. */
static gchar *g_user_data_dir = NULL;
static gchar **g_system_data_dirs = NULL;
static gchar *g_user_cache_dir = NULL;
static gchar *g_user_config_dir = NULL;
static gchar *g_user_runtime_dir = NULL;
static gchar **g_system_config_dirs = NULL;
static gchar **g_user_special_dirs = NULL;
/* fifteen minutes of fame for everybody */
@ -790,6 +792,79 @@ g_get_real_name (void)
return entry->real_name;
}
/* Protected by @g_utils_global_lock. */
static gchar *g_home_dir = NULL; /* (owned) (nullable before initialised) */
static gchar *
g_build_home_dir (void)
{
gchar *home_dir;
/* We first check HOME and use it if it is set */
home_dir = g_strdup (g_getenv ("HOME"));
#ifdef G_OS_WIN32
/* Only believe HOME if it is an absolute path and exists.
*
* We only do this check on Windows for a couple of reasons.
* Historically, we only did it there because we used to ignore $HOME
* on UNIX. There are concerns about enabling it now on UNIX because
* of things like autofs. In short, if the user has a bogus value in
* $HOME then they get what they pay for...
*/
if (home_dir != NULL)
{
if (!(g_path_is_absolute (home_dir) &&
g_file_test (home_dir, G_FILE_TEST_IS_DIR)))
g_clear_pointer (&home_dir, g_free);
}
/* In case HOME is Unix-style (it happens), convert it to
* Windows style.
*/
if (home_dir != NULL)
{
gchar *p;
while ((p = strchr (home_dir, '/')) != NULL)
*p = '\\';
}
if (home_dir == NULL)
{
/* USERPROFILE is probably the closest equivalent to $HOME? */
if (g_getenv ("USERPROFILE") != NULL)
home_dir = g_strdup (g_getenv ("USERPROFILE"));
}
if (home_dir == NULL)
home_dir = get_special_folder (CSIDL_PROFILE);
if (home_dir == NULL)
home_dir = get_windows_directory_root ();
#endif /* G_OS_WIN32 */
if (home_dir == NULL)
{
/* If we didn't get it from any of those methods, we will have
* to read the user database entry.
*/
UserDatabaseEntry *entry = g_get_user_database_entry ();
home_dir = g_strdup (entry->home_dir);
}
/* If we have been denied access to /etc/passwd (for example, by an
* overly-zealous LSM), make up a junk value. The return value at this
* point is explicitly documented as undefined. */
if (home_dir == NULL)
{
g_warning ("Could not find home directory: $HOME is not set, and "
"user database could not be read.");
home_dir = g_strdup ("/");
}
return g_steal_pointer (&home_dir);
}
/**
* g_get_home_dir:
*
@ -819,87 +894,15 @@ g_get_real_name (void)
const gchar *
g_get_home_dir (void)
{
static gchar *home_dir;
const gchar *home_dir;
if (g_once_init_enter (&home_dir))
{
gchar *tmp;
G_LOCK (g_utils_global);
/* We first check HOME and use it if it is set */
tmp = g_strdup (g_getenv ("HOME"));
if (g_home_dir == NULL)
g_home_dir = g_build_home_dir ();
home_dir = g_home_dir;
#ifdef G_OS_WIN32
/* Only believe HOME if it is an absolute path and exists.
*
* We only do this check on Windows for a couple of reasons.
* Historically, we only did it there because we used to ignore $HOME
* on UNIX. There are concerns about enabling it now on UNIX because
* of things like autofs. In short, if the user has a bogus value in
* $HOME then they get what they pay for...
*/
if (tmp)
{
if (!(g_path_is_absolute (tmp) &&
g_file_test (tmp, G_FILE_TEST_IS_DIR)))
{
g_free (tmp);
tmp = NULL;
}
}
/* In case HOME is Unix-style (it happens), convert it to
* Windows style.
*/
if (tmp)
{
gchar *p;
while ((p = strchr (tmp, '/')) != NULL)
*p = '\\';
}
if (!tmp)
{
/* USERPROFILE is probably the closest equivalent to $HOME? */
if (g_getenv ("USERPROFILE") != NULL)
tmp = g_strdup (g_getenv ("USERPROFILE"));
}
if (!tmp)
tmp = get_special_folder (CSIDL_PROFILE);
if (!tmp)
tmp = get_windows_directory_root ();
#endif /* G_OS_WIN32 */
if (!tmp)
{
/* If we didn't get it from any of those methods, we will have
* to read the user database entry.
*/
UserDatabaseEntry *entry;
entry = g_get_user_database_entry ();
/* Strictly speaking, we should copy this, but we know that
* neither will ever be freed, so don't bother...
*/
tmp = entry->home_dir;
}
/* If we have been denied access to /etc/passwd (for example, by an
* overly-zealous LSM), make up a junk value. The return value at this
* point is explicitly documented as undefined. Memory management is as
* immediately above: strictly this should be copied, but we know not
* copying it is OK. */
if (tmp == NULL)
{
g_warning ("Could not find home directory: $HOME is not set, and "
"user database could not be read.");
tmp = "/";
}
g_once_init_leave (&home_dir, tmp);
}
G_UNLOCK (g_utils_global);
return home_dir;
}
@ -1167,6 +1170,135 @@ g_set_application_name (const gchar *application_name)
g_warning ("g_set_application_name() called multiple times");
}
/* Set @global_str to a copy of @new_value if its currently unset or has a
* different value. If its current value matches @new_value, do nothing. If
* replaced, we have to leak the old value as client code could still have
* pointers to it. */
static void
set_str_if_different (gchar **global_str,
const gchar *type,
const gchar *new_value)
{
if (*global_str == NULL ||
!g_str_equal (new_value, *global_str))
{
g_debug ("g_set_user_dirs: Setting %s to %s", type, new_value);
/* We have to leak the old value, as user code could be retaining pointers
* to it. */
*global_str = g_strdup (new_value);
}
}
static void
set_strv_if_different (gchar ***global_strv,
const gchar *type,
const gchar * const *new_value)
{
if (*global_strv == NULL ||
!g_strv_equal (new_value, (const gchar * const *) *global_strv))
{
gchar *new_value_str = g_strjoinv (":", (gchar **) new_value);
g_debug ("g_set_user_dirs: Setting %s to %s", type, new_value_str);
g_free (new_value_str);
/* We have to leak the old value, as user code could be retaining pointers
* to it. */
*global_strv = g_strdupv ((gchar **) new_value);
}
}
/*
* g_set_user_dirs:
* @first_dir_type: Type of the first directory to set
* @...: Value to set the first directory to, followed by additional type/value
* pairs, followed by %NULL
*
* Set one or more user directories to custom values. This is intended to be
* used by test code (particularly with the %G_TEST_OPTION_ISOLATE_DIRS option)
* to override the values returned by the following functions, so that test
* code can be run without touching an installed system and user data:
*
* - g_get_home_dir() use type `HOME`, pass a string
* - g_get_user_cache_dir() use type `XDG_CACHE_HOME`, pass a string
* - g_get_system_config_dirs() use type `XDG_CONFIG_DIRS`, pass a
* %NULL-terminated string array
* - g_get_user_config_dir() use type `XDG_CONFIG_HOME`, pass a string
* - g_get_system_data_dirs() use type `XDG_DATA_DIRS`, pass a
* %NULL-terminated string array
* - g_get_user_data_dir() use type `XDG_DATA_HOME`, pass a string
* - g_get_user_runtime_dir() use type `XDG_RUNTIME_DIR`, pass a string
*
* The list must be terminated with a %NULL type. All of the values must be
* non-%NULL passing %NULL as a value wont reset a directory. If a reference
* to a directory from the calling environment needs to be kept, copy it before
* the first call to g_set_user_dirs(). g_set_user_dirs() can be called multiple
* times.
*
* Since: 2.60
*/
/*< private > */
void
g_set_user_dirs (const gchar *first_dir_type,
...)
{
va_list args;
const gchar *dir_type;
G_LOCK (g_utils_global);
va_start (args, first_dir_type);
for (dir_type = first_dir_type; dir_type != NULL; dir_type = va_arg (args, const gchar *))
{
gconstpointer dir_value = va_arg (args, gconstpointer);
g_assert (dir_value != NULL);
if (g_str_equal (dir_type, "HOME"))
set_str_if_different (&g_home_dir, dir_type, dir_value);
else if (g_str_equal (dir_type, "XDG_CACHE_HOME"))
set_str_if_different (&g_user_cache_dir, dir_type, dir_value);
else if (g_str_equal (dir_type, "XDG_CONFIG_DIRS"))
set_strv_if_different (&g_system_config_dirs, dir_type, dir_value);
else if (g_str_equal (dir_type, "XDG_CONFIG_HOME"))
set_str_if_different (&g_user_config_dir, dir_type, dir_value);
else if (g_str_equal (dir_type, "XDG_DATA_DIRS"))
set_strv_if_different (&g_system_data_dirs, dir_type, dir_value);
else if (g_str_equal (dir_type, "XDG_DATA_HOME"))
set_str_if_different (&g_user_data_dir, dir_type, dir_value);
else if (g_str_equal (dir_type, "XDG_RUNTIME_DIR"))
set_str_if_different (&g_user_runtime_dir, dir_type, dir_value);
else
g_assert_not_reached ();
}
va_end (args);
G_UNLOCK (g_utils_global);
}
static gchar *
g_build_user_data_dir (void)
{
gchar *data_dir = NULL;
const gchar *data_dir_env = g_getenv ("XDG_DATA_HOME");
if (data_dir_env && data_dir_env[0])
data_dir = g_strdup (data_dir_env);
#ifdef G_OS_WIN32
else
data_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
#endif
if (!data_dir || !data_dir[0])
{
gchar *home_dir = g_build_home_dir ();
data_dir = g_build_filename (home_dir, ".local", "share", NULL);
g_free (home_dir);
}
return g_steal_pointer (&data_dir);
}
/**
* g_get_user_data_dir:
*
@ -1192,67 +1324,39 @@ g_set_application_name (const gchar *application_name)
const gchar *
g_get_user_data_dir (void)
{
gchar *data_dir = NULL;
const gchar *user_data_dir;
G_LOCK (g_utils_global);
if (!g_user_data_dir)
{
const gchar *data_dir_env = g_getenv ("XDG_DATA_HOME");
if (data_dir_env && data_dir_env[0])
data_dir = g_strdup (data_dir_env);
#ifdef G_OS_WIN32
else
data_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
#endif
if (!data_dir || !data_dir[0])
{
const gchar *home_dir = g_get_home_dir ();
if (home_dir)
data_dir = g_build_filename (home_dir, ".local", "share", NULL);
else
data_dir = g_build_filename (g_get_tmp_dir (), g_get_user_name (), ".local", "share", NULL);
}
g_user_data_dir = data_dir;
}
else
data_dir = g_user_data_dir;
if (g_user_data_dir == NULL)
g_user_data_dir = g_build_user_data_dir ();
user_data_dir = g_user_data_dir;
G_UNLOCK (g_utils_global);
return data_dir;
return user_data_dir;
}
static void
g_init_user_config_dir (void)
static gchar *
g_build_user_config_dir (void)
{
gchar *config_dir = NULL;
const gchar *config_dir_env = g_getenv ("XDG_CONFIG_HOME");
if (!g_user_config_dir)
{
const gchar *config_dir_env = g_getenv ("XDG_CONFIG_HOME");
if (config_dir_env && config_dir_env[0])
config_dir = g_strdup (config_dir_env);
if (config_dir_env && config_dir_env[0])
config_dir = g_strdup (config_dir_env);
#ifdef G_OS_WIN32
else
config_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
else
config_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
#endif
if (!config_dir || !config_dir[0])
{
const gchar *home_dir = g_get_home_dir ();
if (home_dir)
config_dir = g_build_filename (home_dir, ".config", NULL);
else
config_dir = g_build_filename (g_get_tmp_dir (), g_get_user_name (), ".config", NULL);
}
g_user_config_dir = config_dir;
if (!config_dir || !config_dir[0])
{
gchar *home_dir = g_build_home_dir ();
config_dir = g_build_filename (home_dir, ".config", NULL);
g_free (home_dir);
}
return g_steal_pointer (&config_dir);
}
/**
@ -1280,13 +1384,39 @@ g_init_user_config_dir (void)
const gchar *
g_get_user_config_dir (void)
{
const gchar *user_config_dir;
G_LOCK (g_utils_global);
g_init_user_config_dir ();
if (g_user_config_dir == NULL)
g_user_config_dir = g_build_user_config_dir ();
user_config_dir = g_user_config_dir;
G_UNLOCK (g_utils_global);
return g_user_config_dir;
return user_config_dir;
}
static gchar *
g_build_user_cache_dir (void)
{
gchar *cache_dir = NULL;
const gchar *cache_dir_env = g_getenv ("XDG_CACHE_HOME");
if (cache_dir_env && cache_dir_env[0])
cache_dir = g_strdup (cache_dir_env);
#ifdef G_OS_WIN32
else
cache_dir = get_special_folder (CSIDL_INTERNET_CACHE);
#endif
if (!cache_dir || !cache_dir[0])
{
gchar *home_dir = g_build_home_dir ();
cache_dir = g_build_filename (home_dir, ".cache", NULL);
g_free (home_dir);
}
return g_steal_pointer (&cache_dir);
}
/**
@ -1313,37 +1443,45 @@ g_get_user_config_dir (void)
const gchar *
g_get_user_cache_dir (void)
{
gchar *cache_dir = NULL;
const gchar *user_cache_dir;
G_LOCK (g_utils_global);
if (!g_user_cache_dir)
{
const gchar *cache_dir_env = g_getenv ("XDG_CACHE_HOME");
if (cache_dir_env && cache_dir_env[0])
cache_dir = g_strdup (cache_dir_env);
#ifdef G_OS_WIN32
else
cache_dir = get_special_folder (CSIDL_INTERNET_CACHE);
#endif
if (!cache_dir || !cache_dir[0])
{
const gchar *home_dir = g_get_home_dir ();
if (home_dir)
cache_dir = g_build_filename (home_dir, ".cache", NULL);
else
cache_dir = g_build_filename (g_get_tmp_dir (), g_get_user_name (), ".cache", NULL);
}
g_user_cache_dir = cache_dir;
}
else
cache_dir = g_user_cache_dir;
if (g_user_cache_dir == NULL)
g_user_cache_dir = g_build_user_cache_dir ();
user_cache_dir = g_user_cache_dir;
G_UNLOCK (g_utils_global);
return cache_dir;
return user_cache_dir;
}
static gchar *
g_build_user_runtime_dir (void)
{
gchar *runtime_dir = NULL;
const gchar *runtime_dir_env = g_getenv ("XDG_RUNTIME_DIR");
if (runtime_dir_env && runtime_dir_env[0])
runtime_dir = g_strdup (runtime_dir_env);
else
{
runtime_dir = g_build_user_cache_dir ();
/* The user should be able to rely on the directory existing
* when the function returns. Probably it already does, but
* let's make sure. Just do mkdir() directly since it will be
* no more expensive than a stat() in the case that the
* directory already exists and is a lot easier.
*
* $XDG_CACHE_HOME is probably ~/.cache/ so as long as $HOME
* exists this will work. If the user changed $XDG_CACHE_HOME
* then they can make sure that it exists...
*/
(void) g_mkdir (runtime_dir, 0700);
}
return g_steal_pointer (&runtime_dir);
}
/**
@ -1368,38 +1506,17 @@ g_get_user_cache_dir (void)
const gchar *
g_get_user_runtime_dir (void)
{
static const gchar *runtime_dir;
const gchar *user_runtime_dir;
if (g_once_init_enter (&runtime_dir))
{
const gchar *dir;
G_LOCK (g_utils_global);
dir = g_strdup (getenv ("XDG_RUNTIME_DIR"));
if (g_user_runtime_dir == NULL)
g_user_runtime_dir = g_build_user_runtime_dir ();
user_runtime_dir = g_user_runtime_dir;
if (dir == NULL)
{
/* No need to strdup this one since it is valid forever. */
dir = g_get_user_cache_dir ();
G_UNLOCK (g_utils_global);
/* The user should be able to rely on the directory existing
* when the function returns. Probably it already does, but
* let's make sure. Just do mkdir() directly since it will be
* no more expensive than a stat() in the case that the
* directory already exists and is a lot easier.
*
* $XDG_CACHE_HOME is probably ~/.cache/ so as long as $HOME
* exists this will work. If the user changed $XDG_CACHE_HOME
* then they can make sure that it exists...
*/
(void) g_mkdir (dir, 0700);
}
g_assert (dir != NULL);
g_once_init_leave (&runtime_dir, dir);
}
return runtime_dir;
return user_runtime_dir;
}
#ifdef HAVE_CARBON
@ -1553,16 +1670,18 @@ load_user_special_dirs (void)
static void
load_user_special_dirs (void)
{
gchar *config_dir = NULL;
gchar *config_file;
gchar *data;
gchar **lines;
gint n_lines, i;
g_init_user_config_dir ();
config_file = g_build_filename (g_user_config_dir,
config_dir = g_build_user_config_dir ();
config_file = g_build_filename (config_dir,
"user-dirs.dirs",
NULL);
g_free (config_dir);
if (!g_file_get_contents (config_file, &data, NULL, NULL))
{
g_free (config_file);
@ -1669,7 +1788,9 @@ load_user_special_dirs (void)
if (is_relative)
{
g_user_special_dirs[directory] = g_build_filename (g_get_home_dir (), d, NULL);
gchar *home_dir = g_build_home_dir ();
g_user_special_dirs[directory] = g_build_filename (home_dir, d, NULL);
g_free (home_dir);
}
else
g_user_special_dirs[directory] = g_strdup (d);
@ -1689,7 +1810,7 @@ load_user_special_dirs (void)
* that the latest on-disk version is used. Call this only
* if you just changed the data on disk yourself.
*
* Due to threadsafety issues this may cause leaking of strings
* Due to thread safety issues this may cause leaking of strings
* that were previously returned from g_get_user_special_dir()
* that can't be freed. We ensure to only leak the data for
* the directories that actually changed value though.
@ -1762,6 +1883,8 @@ g_reload_user_special_dirs_cache (void)
const gchar *
g_get_user_special_dir (GUserDirectory directory)
{
const gchar *user_special_dir;
g_return_val_if_fail (directory >= G_USER_DIRECTORY_DESKTOP &&
directory < G_USER_N_DIRECTORIES, NULL);
@ -1775,12 +1898,17 @@ g_get_user_special_dir (GUserDirectory directory)
/* Special-case desktop for historical compatibility */
if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL)
g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = g_build_filename (g_get_home_dir (), "Desktop", NULL);
{
gchar *home_dir = g_build_home_dir ();
g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = g_build_filename (home_dir, "Desktop", NULL);
g_free (home_dir);
}
}
user_special_dir = g_user_special_dirs[directory];
G_UNLOCK (g_utils_global);
return g_user_special_dirs[directory];
return user_special_dir;
}
#ifdef G_OS_WIN32
@ -1942,7 +2070,7 @@ g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
gboolean should_call_g_get_system_data_dirs;
should_call_g_get_system_data_dirs = TRUE;
/* These checks are the same as the ones that g_get_system_data_dirs() does.
/* These checks are the same as the ones that g_build_system_data_dirs() does.
* Please keep them in sync.
*/
G_LOCK (g_utils_global);
@ -1986,6 +2114,30 @@ g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
#endif
static gchar **
g_build_system_data_dirs (void)
{
gchar **data_dir_vector = NULL;
gchar *data_dirs = (gchar *) g_getenv ("XDG_DATA_DIRS");
/* These checks are the same as the ones that g_win32_get_system_data_dirs_for_module()
* does. Please keep them in sync.
*/
#ifndef G_OS_WIN32
if (!data_dirs || !data_dirs[0])
data_dirs = "/usr/local/share/:/usr/share/";
data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
#else
if (!data_dirs || !data_dirs[0])
data_dir_vector = g_strdupv ((gchar **) g_win32_get_system_data_dirs_for_module_real (NULL));
else
data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
#endif
return g_steal_pointer (&data_dir_vector);
}
/**
* g_get_system_data_dirs:
*
@ -2030,37 +2182,49 @@ g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
const gchar * const *
g_get_system_data_dirs (void)
{
gchar **data_dir_vector;
const gchar * const *system_data_dirs;
/* These checks are the same as the ones that g_win32_get_system_data_dirs_for_module()
* does. Please keep them in sync.
*/
G_LOCK (g_utils_global);
if (!g_system_data_dirs)
{
gchar *data_dirs = (gchar *) g_getenv ("XDG_DATA_DIRS");
#ifndef G_OS_WIN32
if (!data_dirs || !data_dirs[0])
data_dirs = "/usr/local/share/:/usr/share/";
data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
#else
if (!data_dirs || !data_dirs[0])
data_dir_vector = g_strdupv ((gchar **) g_win32_get_system_data_dirs_for_module_real (NULL));
else
data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
#endif
g_system_data_dirs = data_dir_vector;
}
else
data_dir_vector = g_system_data_dirs;
if (g_system_data_dirs == NULL)
g_system_data_dirs = g_build_system_data_dirs ();
system_data_dirs = (const gchar * const *) g_system_data_dirs;
G_UNLOCK (g_utils_global);
return (const gchar * const *) data_dir_vector;
return system_data_dirs;
}
static gchar **
g_build_system_config_dirs (void)
{
gchar **conf_dir_vector = NULL;
const gchar *conf_dirs = g_getenv ("XDG_CONFIG_DIRS");
#ifdef G_OS_WIN32
if (conf_dirs)
{
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
}
else
{
gchar *special_conf_dirs = get_special_folder (CSIDL_COMMON_APPDATA);
if (special_conf_dirs)
conf_dir_vector = g_strsplit (special_conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
else
/* Return empty list */
conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
g_free (special_conf_dirs);
}
#else
if (!conf_dirs || !conf_dirs[0])
conf_dirs = "/etc/xdg";
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
#endif
return g_steal_pointer (&conf_dir_vector);
}
/**
@ -2093,44 +2257,17 @@ g_get_system_data_dirs (void)
const gchar * const *
g_get_system_config_dirs (void)
{
gchar **conf_dir_vector;
const gchar * const *system_config_dirs;
G_LOCK (g_utils_global);
if (!g_system_config_dirs)
{
const gchar *conf_dirs = g_getenv ("XDG_CONFIG_DIRS");
#ifdef G_OS_WIN32
if (conf_dirs)
{
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
}
else
{
gchar *special_conf_dirs = get_special_folder (CSIDL_COMMON_APPDATA);
if (g_system_config_dirs == NULL)
g_system_config_dirs = g_build_system_config_dirs ();
system_config_dirs = (const gchar * const *) g_system_config_dirs;
if (special_conf_dirs)
conf_dir_vector = g_strsplit (special_conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
else
/* Return empty list */
conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
g_free (special_conf_dirs);
}
#else
if (!conf_dirs || !conf_dirs[0])
conf_dirs = "/etc/xdg";
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
#endif
g_system_config_dirs = conf_dir_vector;
}
else
conf_dir_vector = g_system_config_dirs;
G_UNLOCK (g_utils_global);
return (const gchar * const *) conf_dir_vector;
return system_config_dirs;
}
/**

View File

@ -78,7 +78,7 @@ GLIB_AVAILABLE_IN_ALL
const gchar * const * g_get_system_data_dirs (void);
#ifdef G_OS_WIN32
/* This functions is not part of the public GLib API */
/* This function is not part of the public GLib API */
GLIB_AVAILABLE_IN_ALL
const gchar * const * g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void));
#endif

33
glib/gutilsprivate.h Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright © 2018 Endless Mobile, Inc.
*
* 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: Philip Withnall <withnall@endlessm.com>
*/
#ifndef __G_UTILS_PRIVATE_H__
#define __G_UTILS_PRIVATE_H__
#include "gtypes.h"
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_2_60
void g_set_user_dirs (const gchar *first_dir_type,
...) G_GNUC_NULL_TERMINATED;
G_END_DECLS
#endif /* __G_UTILS_PRIVATE_H__ */

View File

@ -199,6 +199,7 @@ glib_sources = files(
'gunidecomp.c',
'gurifuncs.c',
'gutils.c',
'gutilsprivate.h',
'guuid.c',
'gvariant.c',
'gvariant-core.c',

View File

@ -68,21 +68,6 @@ static CmdlineTest cmdline_tests[] =
{"foo '/bar/summer'\\''09 tours.pdf'", 2, {"foo", "/bar/summer'09 tours.pdf", NULL}, -1}
};
static gboolean
strv_equal (gchar **a, gchar **b)
{
gint i;
if (g_strv_length (a) != g_strv_length (b))
return FALSE;
for (i = 0; a[i]; i++)
if (g_strcmp0 (a[i], b[i]) != 0)
return FALSE;
return TRUE;
}
static void
do_cmdline_test (gconstpointer d)
{
@ -99,7 +84,7 @@ do_cmdline_test (gconstpointer d)
{
g_assert (res);
g_assert_cmpint (argc, ==, test->argc);
g_assert (strv_equal (argv, (gchar **)test->argv));
g_assert (g_strv_equal ((const gchar * const *) argv, (const gchar * const *) test->argv));
g_assert_no_error (err);
}
else

View File

@ -1507,6 +1507,34 @@ test_strv_contains (void)
g_assert_false (g_strv_contains (strv_empty, ""));
}
/* Test g_strv_equal() works for various inputs. */
static void
test_strv_equal (void)
{
const gchar *strv_empty[] = { NULL };
const gchar *strv_empty2[] = { NULL };
const gchar *strv_simple[] = { "hello", "you", NULL };
const gchar *strv_simple2[] = { "hello", "you", NULL };
const gchar *strv_simple_reordered[] = { "you", "hello", NULL };
const gchar *strv_simple_superset[] = { "hello", "you", "again", NULL };
const gchar *strv_another[] = { "not", "a", "coded", "message", NULL };
g_assert_true (g_strv_equal (strv_empty, strv_empty));
g_assert_true (g_strv_equal (strv_empty, strv_empty2));
g_assert_true (g_strv_equal (strv_empty2, strv_empty));
g_assert_false (g_strv_equal (strv_empty, strv_simple));
g_assert_false (g_strv_equal (strv_simple, strv_empty));
g_assert_true (g_strv_equal (strv_simple, strv_simple));
g_assert_true (g_strv_equal (strv_simple, strv_simple2));
g_assert_true (g_strv_equal (strv_simple2, strv_simple));
g_assert_false (g_strv_equal (strv_simple, strv_simple_reordered));
g_assert_false (g_strv_equal (strv_simple_reordered, strv_simple));
g_assert_false (g_strv_equal (strv_simple, strv_simple_superset));
g_assert_false (g_strv_equal (strv_simple_superset, strv_simple));
g_assert_false (g_strv_equal (strv_simple, strv_another));
g_assert_false (g_strv_equal (strv_another, strv_simple));
}
typedef enum
{
SIGNED,
@ -1761,6 +1789,7 @@ main (int argc,
g_test_add_func ("/strfuncs/strup", test_strup);
g_test_add_func ("/strfuncs/transliteration", test_transliteration);
g_test_add_func ("/strfuncs/strv-contains", test_strv_contains);
g_test_add_func ("/strfuncs/strv-equal", test_strv_equal);
g_test_add_func ("/strfuncs/ascii-string-to-num/usual", test_ascii_string_to_number_usual);
g_test_add_func ("/strfuncs/ascii-string-to-num/pathological", test_ascii_string_to_number_pathological);