Files
flatpak/tests/testcommon.c
Kalev Lember 34bb5592c9 common: Allow skewered to camelcase DConf path conversion both ways
commit 6b46d9a0ed that added DConf path
skewering to camelcase conversion only allowed it in one direction
(skewered path1 and camelcase path2).

That turned out to be not enough to allow /org/gnome/sound-juicer/ to
/org/gnome/SoundJuicer/ conversion as the caller had the
flatpak_dconf_path_is_similar() arguments the other way around.

This commit implements it both ways to avoid confusion which way it
should be called.

F: Ignoring D-Conf migrate-path setting /org/gnome/sound-juicer/
2020-10-01 11:15:54 +02:00

1215 lines
40 KiB
C

#include "config.h"
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <glib.h>
#include "flatpak.h"
#include "flatpak-utils-private.h"
#include "flatpak-appdata-private.h"
#include "flatpak-builtins-utils.h"
#include "flatpak-table-printer.h"
#include "parse-datetime.h"
static void
test_has_path_prefix (void)
{
g_assert_true (flatpak_has_path_prefix ("/a/prefix/foo/bar", "/a/prefix"));
g_assert_true (flatpak_has_path_prefix ("/a///prefix/foo/bar", "/a/prefix"));
g_assert_true (flatpak_has_path_prefix ("/a/prefix/foo/bar", "/a/prefix/"));
g_assert_true (flatpak_has_path_prefix ("/a/prefix/foo/bar", "/a/prefix//"));
g_assert_true (flatpak_has_path_prefix ("/a/prefix/foo/bar", ""));
g_assert_false (flatpak_has_path_prefix ("/a/prefixfoo/bar", "/a/prefix"));
}
static void
test_path_match_prefix (void)
{
g_assert_cmpstr (flatpak_path_match_prefix ("/?/pre*", "/a/prefix/x"), ==, "/x");
g_assert_cmpstr (flatpak_path_match_prefix ("/a/prefix/*", "/a/prefix/"), ==, "");
g_assert_null (flatpak_path_match_prefix ("/?/pre?", "/a/prefix/x"));
}
static void
test_fancy_output (void)
{
if (!isatty (STDOUT_FILENO))
g_assert_false (flatpak_fancy_output ()); // no tty
else
g_assert_true (flatpak_fancy_output ()); // a tty
flatpak_enable_fancy_output ();
g_assert_true (flatpak_fancy_output ());
flatpak_disable_fancy_output ();
g_assert_false (flatpak_fancy_output ());
}
static void
test_arches (void)
{
const char **arches = flatpak_get_arches ();
#if defined(__i386__)
g_assert_cmpstr (flatpak_get_arch (), ==, "i386");
g_assert_false (g_strv_contains (arches, "x86_64"));
g_assert_true (g_strv_contains (arches, "i386"));
#elif defined(__x86_64__)
g_assert_cmpstr (flatpak_get_arch (), ==, "x86_64");
g_assert_true (g_strv_contains (arches, "x86_64"));
g_assert_true (g_strv_contains (arches, "i386"));
g_assert_true (flatpak_is_linux32_arch ("i386"));
g_assert_false (flatpak_is_linux32_arch ("x86_64"));
#else
g_assert_true (g_strv_contains (arches, flatpak_get_arch ()));
#endif
}
static void
test_extension_matches (void)
{
g_assert_true (flatpak_extension_matches_reason ("org.foo.bar", "", TRUE));
g_assert_false (flatpak_extension_matches_reason ("org.foo.nosuchdriver", "active-gl-driver", TRUE));
g_assert_false (flatpak_extension_matches_reason ("org.foo.nosuchtheme", "active-gtk-theme", TRUE));
g_assert_false (flatpak_extension_matches_reason ("org.foo.nonono", "on-xdg-desktop-nosuchdesktop", TRUE));
g_assert_false (flatpak_extension_matches_reason ("org.foo.nonono", "active-gl-driver;active-gtk-theme", TRUE));
}
static void
test_valid_name (void)
{
g_assert_false (flatpak_is_valid_name ("", NULL));
g_assert_false (flatpak_is_valid_name ("org", NULL));
g_assert_false (flatpak_is_valid_name ("org.", NULL));
g_assert_false (flatpak_is_valid_name ("org..", NULL));
g_assert_false (flatpak_is_valid_name ("org..test", NULL));
g_assert_false (flatpak_is_valid_name ("org.flatpak", NULL));
g_assert_false (flatpak_is_valid_name ("org.1flatpak.test", NULL));
g_assert_false (flatpak_is_valid_name ("org.flat-pak.test", NULL));
g_assert_false (flatpak_is_valid_name ("org.-flatpak.test", NULL));
g_assert_false (flatpak_is_valid_name ("org.flat,pak.test", NULL));
g_assert_true (flatpak_is_valid_name ("org.flatpak.test", NULL));
g_assert_true (flatpak_is_valid_name ("org.FlatPak.TEST", NULL));
g_assert_true (flatpak_is_valid_name ("org0.f1atpak.test", NULL));
g_assert_true (flatpak_is_valid_name ("org.flatpak.-test", NULL));
g_assert_true (flatpak_is_valid_name ("org.flatpak._test", NULL));
g_assert_true (flatpak_is_valid_name ("org.flat_pak__.te--st", NULL));
}
typedef struct
{
const gchar *str;
guint base;
gint min;
gint max;
gint expected;
gboolean should_fail;
} TestData;
const TestData test_data[] = {
/* typical cases for unsigned */
{ "-1", 10, 0, 2, 0, TRUE },
{ "1", 10, 0, 2, 1, FALSE },
{ "+1", 10, 0, 2, 0, TRUE },
{ "0", 10, 0, 2, 0, FALSE },
{ "+0", 10, 0, 2, 0, TRUE },
{ "-0", 10, 0, 2, 0, TRUE },
{ "2", 10, 0, 2, 2, FALSE },
{ "+2", 10, 0, 2, 0, TRUE },
{ "3", 10, 0, 2, 0, TRUE },
{ "+3", 10, 0, 2, 0, TRUE },
/* min == max cases for unsigned */
{ "2", 10, 2, 2, 2, FALSE },
{ "3", 10, 2, 2, 0, TRUE },
{ "1", 10, 2, 2, 0, TRUE },
/* invalid inputs */
{ "", 10, 0, 2, 0, TRUE },
{ "a", 10, 0, 2, 0, TRUE },
{ "1a", 10, 0, 2, 0, TRUE },
/* leading/trailing whitespace */
{ " 1", 10, 0, 2, 0, TRUE },
{ "1 ", 10, 0, 2, 0, TRUE },
/* hexadecimal numbers */
{ "a", 16, 0, 15, 10, FALSE },
{ "0xa", 16, 0, 15, 0, TRUE },
{ "-0xa", 16, 0, 15, 0, TRUE },
{ "+0xa", 16, 0, 15, 0, TRUE },
{ "- 0xa", 16, 0, 15, 0, TRUE },
{ "+ 0xa", 16, 0, 15, 0, TRUE },
};
static void
test_string_to_unsigned (void)
{
gsize idx;
for (idx = 0; idx < G_N_ELEMENTS (test_data); ++idx)
{
GError *error = NULL;
const TestData *data = &test_data[idx];
gboolean result;
gint value;
guint64 value64 = 0;
result = flatpak_utils_ascii_string_to_unsigned (data->str,
data->base,
data->min,
data->max,
&value64,
&error);
value = value64;
g_assert_cmpint (value, ==, value64);
if (data->should_fail)
{
g_assert_false (result);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
g_clear_error (&error);
}
else
{
g_assert_true (result);
g_assert_no_error (error);
g_assert_cmpint (value, ==, data->expected);
}
}
}
typedef struct
{
const char *a;
const char *b;
int distance;
} Levenshtein;
static Levenshtein levenshtein_tests[] = {
{ "", "", 0 },
{ "abcdef", "abcdef", 0 },
{ "kitten", "sitting", 3 },
{ "Saturday", "Sunday", 3 }
};
static void
test_levenshtein (void)
{
gsize idx;
for (idx = 0; idx < G_N_ELEMENTS (levenshtein_tests); idx++)
{
Levenshtein *data = &levenshtein_tests[idx];
g_assert_cmpint (flatpak_levenshtein_distance (data->a, data->b), ==, data->distance);
g_assert_cmpint (flatpak_levenshtein_distance (data->b, data->a), ==, data->distance);
}
}
static GString *g_print_buffer;
static void
my_print_func (const char *string)
{
g_string_append (g_print_buffer, string);
}
static void
test_format_choices (void)
{
GPrintFunc print_func;
const char *choices[] = { "one", "two", "three", NULL };
const char *many_choices[] = {
"one", "two", "three", "four", "five", "six",
"seven", "eight", "nine", "ten", "eleven",
NULL
};
g_assert_null (g_print_buffer);
g_print_buffer = g_string_new ("");
print_func = g_set_print_handler (my_print_func);
flatpak_format_choices (choices, "A prompt for %d choices:", 3);
g_assert_cmpstr (g_print_buffer->str, ==,
"A prompt for 3 choices:\n\n"
" 1) one\n"
" 2) two\n"
" 3) three\n"
"\n");
g_string_truncate (g_print_buffer, 0);
flatpak_format_choices (many_choices, "A prompt for %d choices:", 11);
g_assert_cmpstr (g_print_buffer->str, ==,
"A prompt for 11 choices:\n\n"
" 1) one\n"
" 2) two\n"
" 3) three\n"
" 4) four\n"
" 5) five\n"
" 6) six\n"
" 7) seven\n"
" 8) eight\n"
" 9) nine\n"
" 10) ten\n"
" 11) eleven\n"
"\n");
g_string_truncate (g_print_buffer, 0);
g_set_print_handler (print_func);
g_set_print_handler (print_func);
g_string_free (g_print_buffer, TRUE);
g_print_buffer = NULL;
}
static void
test_yes_no_prompt (void)
{
GPrintFunc print_func;
gboolean ret;
g_assert_null (g_print_buffer);
g_print_buffer = g_string_new ("");
print_func = g_set_print_handler (my_print_func);
/* not a tty, so flatpak_yes_no_prompt will auto-answer 'n' */
ret = flatpak_yes_no_prompt (TRUE, "Prompt %d ?", 1);
g_assert_false (ret);
g_assert_cmpstr (g_print_buffer->str, ==, "Prompt 1 ? [Y/n]: n\n");
g_string_truncate (g_print_buffer, 0);
ret = flatpak_yes_no_prompt (FALSE, "Prompt %d ?", 2);
g_assert_false (ret);
g_assert_cmpstr (g_print_buffer->str, ==, "Prompt 2 ? [y/n]: n\n");
g_set_print_handler (print_func);
g_string_free (g_print_buffer, TRUE);
g_print_buffer = NULL;
}
static void
test_number_prompt (void)
{
GPrintFunc print_func;
gboolean ret;
g_assert_null (g_print_buffer);
g_print_buffer = g_string_new ("");
print_func = g_set_print_handler (my_print_func);
/* not a tty, so flatpak_number_prompt will auto-answer '0' */
ret = flatpak_number_prompt (TRUE, 0, 8, "Prompt %d ?", 1);
g_assert_false (ret);
g_assert_cmpstr (g_print_buffer->str, ==, "Prompt 1 ? [0-8]: 0\n");
g_string_truncate (g_print_buffer, 0);
ret = flatpak_number_prompt (FALSE, 1, 3, "Prompt %d ?", 2);
g_assert_false (ret);
g_assert_cmpstr (g_print_buffer->str, ==, "Prompt 2 ? [1-3]: 0\n");
g_set_print_handler (print_func);
g_string_free (g_print_buffer, TRUE);
g_print_buffer = NULL;
}
static void
assert_numbers (int *num, ...)
{
va_list args;
int n;
int i;
g_assert_nonnull (num);
va_start (args, num);
for (i = 0; num[i]; i++)
{
n = va_arg (args, int);
g_assert_true (n == num[i]);
}
n = va_arg (args, int);
g_assert_true (n == 0);
va_end (args);
}
static void
test_parse_numbers (void)
{
g_autofree int *numbers = NULL;
numbers = flatpak_parse_numbers ("", 0, 10);
assert_numbers (numbers, 0);
g_clear_pointer (&numbers, g_free);
numbers = flatpak_parse_numbers ("1", 0, 10);
assert_numbers (numbers, 1, 0);
g_clear_pointer (&numbers, g_free);
numbers = flatpak_parse_numbers ("1 3 2", 0, 10);
assert_numbers (numbers, 1, 3, 2, 0);
g_clear_pointer (&numbers, g_free);
numbers = flatpak_parse_numbers ("1-3", 0, 10);
assert_numbers (numbers, 1, 2, 3, 0);
g_clear_pointer (&numbers, g_free);
numbers = flatpak_parse_numbers ("1", 2, 4);
g_assert_null (numbers);
numbers = flatpak_parse_numbers ("2-6", 2, 4);
g_assert_null (numbers);
numbers = flatpak_parse_numbers ("1,2 2", 1, 4);
assert_numbers (numbers, 1, 2, 0);
g_clear_pointer (&numbers, g_free);
numbers = flatpak_parse_numbers ("1-3,2-4", 1, 4);
assert_numbers (numbers, 1, 2, 3, 4, 0);
g_clear_pointer (&numbers, g_free);
numbers = flatpak_parse_numbers ("-1", 1, 4);
g_assert_null (numbers);
}
static void
assert_strv_equal (char **strv1,
char **strv2)
{
if (strv1 == strv2)
return;
for (; *strv1 != NULL && *strv2 != NULL; strv1++, strv2++)
g_assert_true (g_str_equal (*strv1, *strv2));
g_assert_true (*strv1 == NULL && *strv2 == NULL);
}
static void
test_subpaths_merge (void)
{
char *empty[] = { NULL };
char *buba[] = { "bu", "ba", NULL };
char *bla[] = { "bla", "ba", NULL };
char *bla_sorted[] = { "ba", "bla", NULL };
char *bubabla[] = { "ba", "bla", "bu", NULL };
g_auto(GStrv) res = NULL;
res = flatpak_subpaths_merge (NULL, bla);
assert_strv_equal (res, bla_sorted);
g_clear_pointer (&res, g_strfreev);
res = flatpak_subpaths_merge (bla, NULL);
assert_strv_equal (res, bla_sorted);
g_clear_pointer (&res, g_strfreev);
res = flatpak_subpaths_merge (empty, bla);
assert_strv_equal (res, empty);
g_clear_pointer (&res, g_strfreev);
res = flatpak_subpaths_merge (bla, empty);
assert_strv_equal (res, empty);
g_clear_pointer (&res, g_strfreev);
res = flatpak_subpaths_merge (buba, bla);
assert_strv_equal (res, bubabla);
g_clear_pointer (&res, g_strfreev);
res = flatpak_subpaths_merge (bla, buba);
assert_strv_equal (res, bubabla);
g_clear_pointer (&res, g_strfreev);
res = flatpak_subpaths_merge (bla, bla);
assert_strv_equal (res, bla_sorted);
g_clear_pointer (&res, g_strfreev);
}
static void
test_lang_from_locale (void)
{
g_autofree char *lang = NULL;
lang = flatpak_get_lang_from_locale ("en_US.utf8");
g_assert_cmpstr (lang, ==, "en");
g_clear_pointer (&lang, g_free);
lang = flatpak_get_lang_from_locale ("sv_FI@euro");
g_assert_cmpstr (lang, ==, "sv");
}
static void
test_parse_appdata (void)
{
const char appdata1[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<components version=\"0.8\">\n"
" <component type=\"desktop\">\n"
" <id>org.test.Hello.desktop</id>\n"
" <name>Hello world test app: org.test.Hello</name>\n"
" <summary>Print a greeting</summary>\n"
" <description><p>This is a test app.</p></description>\n"
" <categories>\n"
" <category>Utility</category>\n"
" </categories>\n"
" <icon height=\"64\" width=\"64\" type=\"cached\">64x64/org.gnome.gedit.png</icon>\n"
" <releases>\n"
" <release timestamp=\"1525132800\" version=\"0.0.1\"/>\n" /* 01-05-2018 */
" </releases>\n"
" <content_rating type=\"oars-1.0\">\n"
" <content_attribute id=\"drugs-alcohol\">moderate</content_attribute>\n"
" <content_attribute id=\"language-humor\">mild</content_attribute>\n"
" <content_attribute id=\"violence-blood\">none</content_attribute>\n"
" </content_rating>\n"
" </component>\n"
"</components>";
const char appdata2[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<components version=\"0.8\">\n"
" <component type=\"desktop\">\n"
" <id>org.test.Hello.desktop</id>\n"
" <name>Hello world test app: org.test.Hello</name>\n"
" <name xml:lang=\"de\">Hallo Welt test app: org.test.Hello</name>\n"
" <summary>Print a greeting</summary>\n"
" <summary xml:lang=\"de\">Schreib mal was</summary>\n"
" <description><p>This is a test app.</p></description>\n"
" <categories>\n"
" <category>Utility</category>\n"
" </categories>\n"
" <icon height=\"64\" width=\"64\" type=\"cached\">64x64/org.gnome.gedit.png</icon>\n"
" <releases>\n"
" <release timestamp=\"1525132800\" version=\"0.1.0\"/>\n"
" <release timestamp=\"1525000800\" date=\"2018-05-02\" version=\"0.0.2\"/>\n"
" <release date=\"2017-05-02\" version=\"0.0.3\"/>\n"
" <release timestamp=\"1000000000\" version=\"0.0.1\" type=\"stable\" urgency=\"low\"/>\n"
" </releases>\n"
" <project_license>anything goes</project_license>\n"
" <content_rating type=\"oars-1.1\">\n"
" </content_rating>\n"
" </component>\n"
"</components>";
g_autoptr(GHashTable) names = NULL;
g_autoptr(GHashTable) comments = NULL;
g_autofree char *version = NULL;
g_autofree char *license = NULL;
g_autofree char *content_rating_type = NULL;
g_autoptr(GHashTable) content_rating = NULL;
gboolean res;
char *name;
char *comment;
res = flatpak_parse_appdata (appdata1, "org.test.Hello", &names, &comments, &version, &license, &content_rating_type, &content_rating);
g_assert_true (res);
g_assert_cmpstr (version, ==, "0.0.1");
g_assert_null (license);
g_assert_nonnull (names);
g_assert_nonnull (comments);
g_assert_cmpint (g_hash_table_size (names), ==, 1);
g_assert_cmpint (g_hash_table_size (comments), ==, 1);
name = g_hash_table_lookup (names, "C");
g_assert_cmpstr (name, ==, "Hello world test app: org.test.Hello");
comment = g_hash_table_lookup (comments, "C");
g_assert_cmpstr (comment, ==, "Print a greeting");
g_assert_cmpstr (content_rating_type, ==, "oars-1.0");
g_assert_cmpuint (g_hash_table_size (content_rating), ==, 3);
g_assert_cmpstr (g_hash_table_lookup (content_rating, "drugs-alcohol"), ==, "moderate");
g_assert_cmpstr (g_hash_table_lookup (content_rating, "language-humor"), ==, "mild");
g_assert_cmpstr (g_hash_table_lookup (content_rating, "violence-blood"), ==, "none");
g_clear_pointer (&names, g_hash_table_unref);
g_clear_pointer (&comments, g_hash_table_unref);
g_clear_pointer (&version, g_free);
g_clear_pointer (&license, g_free);
g_clear_pointer (&content_rating_type, g_free);
g_clear_pointer (&content_rating, g_hash_table_unref);
res = flatpak_parse_appdata (appdata2, "org.test.Hello", &names, &comments, &version, &license, &content_rating_type, &content_rating);
g_assert_true (res);
g_assert_cmpstr (version, ==, "0.1.0");
g_assert_cmpstr (license, ==, "anything goes");
g_assert_nonnull (names);
g_assert_nonnull (comments);
g_assert_cmpint (g_hash_table_size (names), ==, 2);
g_assert_cmpint (g_hash_table_size (comments), ==, 2);
name = g_hash_table_lookup (names, "C");
g_assert_cmpstr (name, ==, "Hello world test app: org.test.Hello");
name = g_hash_table_lookup (names, "de");
g_assert_cmpstr (name, ==, "Hallo Welt test app: org.test.Hello");
comment = g_hash_table_lookup (comments, "C");
g_assert_cmpstr (comment, ==, "Print a greeting");
comment = g_hash_table_lookup (comments, "de");
g_assert_cmpstr (comment, ==, "Schreib mal was");
g_assert_cmpstr (content_rating_type, ==, "oars-1.1");
g_assert_cmpuint (g_hash_table_size (content_rating), ==, 0);
}
static void
test_name_matching (void)
{
gboolean res;
/* examples from 8f428fd7683765dd706da06e9f376d3732ce5c0c */
res = flatpak_name_matches_one_wildcard_prefix ("org.sparkleshare.SparkleShare.Invites",
(const char *[]){"org.sparkleshare.SparkleShare.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("org.sparkleshare.SparkleShare-symbolic",
(const char *[]){"org.sparkleshare.SparkleShare.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("org.libreoffice.LibreOffice",
(const char *[]){"org.libreoffice.LibreOffice.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("org.libreoffice.LibreOffice-impress",
(const char *[]){"org.libreoffice.LibreOffice.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("org.libreoffice.LibreOffice-writer",
(const char *[]){"org.libreoffice.LibreOffice.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("org.libreoffice.LibreOffice-calc",
(const char *[]){"org.libreoffice.LibreOffice.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("com.github.bajoja.indicator-kdeconnect",
(const char *[]){"com.github.bajoja.indicator-kdeconnect.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("com.github.bajoja.indicator-kdeconnect.settings",
(const char *[]){"com.github.bajoja.indicator-kdeconnect.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("com.github.bajoja.indicator-kdeconnect.tablettrusted",
(const char *[]){"com.github.bajoja.indicator-kdeconnect.*", NULL},
FALSE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("org.gnome.Characters.BackgroundService",
(const char *[]){"org.gnome.Characters.*", NULL},
TRUE);
g_assert_true (res);
res = flatpak_name_matches_one_wildcard_prefix ("org.example.Example.Tracker1.Miner.Applications",
(const char *[]){"org.example.Example.*", NULL},
TRUE);
g_assert_true (res);
}
static void
test_looks_like_branch (void)
{
g_assert_false (looks_like_branch ("abc/d"));
g_assert_false (looks_like_branch ("ab.c.d"));
g_assert_true (looks_like_branch ("master"));
g_assert_true (looks_like_branch ("stable"));
g_assert_true (looks_like_branch ("3.30"));
}
static void
test_columns (void)
{
Column columns[] = {
{ "column1", "col1", "col1", 0, 0, 1, 1 },
{ "install", "install", "install", 0, 0, 0, 1 },
{ "helper", "helper", "helper", 0, 0, 1, 0 },
{ "column2", "col2", "col2", 0, 0, 0, 0 },
{ NULL, }
};
Column *cols;
g_autofree char *help = NULL;
g_autoptr(GError) error = NULL;
const char *args[3];
help = column_help (columns);
g_assert_cmpstr (help, ==,
"Available columns:\n"
" column1 col1\n"
" install install\n"
" helper helper\n"
" column2 col2\n"
" all Show all columns\n"
" help Show available columns\n"
"\n"
"Append :s[tart], :m[iddle], :e[nd] or :f[ull] to change ellipsization\n");
cols = handle_column_args (columns, FALSE, NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (cols[0].name, ==, "column1");
g_assert_cmpstr (cols[1].name, ==, "install");
g_assert_null (cols[2].name);
g_free (cols);
cols = handle_column_args (columns, TRUE, NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (cols[0].name, ==, "column1");
g_assert_cmpstr (cols[1].name, ==, "install");
g_assert_cmpstr (cols[2].name, ==, "helper");
g_assert_null (cols[3].name);
g_free (cols);
args[0] = "all";
args[1] = NULL;
cols = handle_column_args (columns, FALSE, args, &error);
g_assert_no_error (error);
g_assert_cmpstr (cols[0].name, ==, "column1");
g_assert_cmpstr (cols[1].name, ==, "install");
g_assert_cmpstr (cols[2].name, ==, "helper");
g_assert_null (cols[3].name);
g_free (cols);
args[0] = "column1,column2";
args[1] = "helper";
args[2] = NULL;
cols = handle_column_args (columns, FALSE, args, &error);
g_assert_no_error (error);
g_assert_cmpstr (cols[0].name, ==, "column1");
g_assert_cmpstr (cols[1].name, ==, "column2");
g_assert_cmpstr (cols[2].name, ==, "helper");
g_assert_null (cols[3].name);
g_free (cols);
args[0] = "column";
args[1] = NULL;
cols = handle_column_args (columns, FALSE, args, &error);
g_assert_null (cols);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
g_clear_error (&error);
args[0] = "app";
args[1] = NULL;
cols = handle_column_args (columns, FALSE, args, &error);
g_assert_null (cols);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
g_clear_error (&error);
}
typedef struct
{
const char *in;
int len;
FlatpakEllipsizeMode mode;
const char *out;
} EllipsizeData;
static EllipsizeData ellipsize[] = {
{ "abcdefghijklmnopqrstuvwxyz", 10, FLATPAK_ELLIPSIZE_MODE_NONE, "abcdefghijklmnopqrstuvwxyz" },
{ "abcdefghijklmnopqrstuvwxyz", 10, FLATPAK_ELLIPSIZE_MODE_END, "abcdefghi…" },
{ "abcdefghijklmnopqrstuvwxyz", 10, FLATPAK_ELLIPSIZE_MODE_MIDDLE, "abcde…wxyz" },
{ "abcdefghijklmnopqrstuvwxyz", 10, FLATPAK_ELLIPSIZE_MODE_START, "…rstuvwxyz" },
{ "ģ☢ab", 3, FLATPAK_ELLIPSIZE_MODE_START, "…ab" },
{ "ģ☢ab", 3, FLATPAK_ELLIPSIZE_MODE_MIDDLE, "ģ…b" },
{ "ģ☢ab", 3, FLATPAK_ELLIPSIZE_MODE_END, "ģ☢…" }
};
static void
test_string_ellipsize (void)
{
gsize idx;
for (idx = 0; idx < G_N_ELEMENTS (ellipsize); idx++)
{
EllipsizeData *data = &ellipsize[idx];
g_autofree char *ret = NULL;
ret = ellipsize_string_full (data->in, data->len, data->mode);
g_assert_cmpstr (ret, ==, data->out);
}
}
static void
test_table (void)
{
GPrintFunc print_func;
FlatpakTablePrinter *printer;
g_assert_null (g_print_buffer);
g_print_buffer = g_string_new ("");
print_func = g_set_print_handler (my_print_func);
flatpak_enable_fancy_output ();
printer = flatpak_table_printer_new ();
flatpak_table_printer_set_column_title (printer, 0, "Column1");
flatpak_table_printer_set_column_title (printer, 1, "Column2");
flatpak_table_printer_add_column (printer, "text1");
flatpak_table_printer_add_column (printer, "text2");
flatpak_table_printer_finish_row (printer);
flatpak_table_printer_add_column (printer, "text3");
flatpak_table_printer_add_column (printer, "text4");
flatpak_table_printer_finish_row (printer);
flatpak_table_printer_print (printer);
g_assert_cmpstr (g_print_buffer->str, ==,
FLATPAK_ANSI_BOLD_ON
"Column1 Column2" FLATPAK_ANSI_BOLD_OFF "\n"
"text1 text2\n"
"text3 text4\n");
g_string_truncate (g_print_buffer, 0);
flatpak_table_printer_set_cell (printer, 0, 0, "newtext1");
flatpak_table_printer_set_decimal_cell (printer, 0, 1, "0.123");
flatpak_table_printer_set_decimal_cell (printer, 1, 1, "123.0");
flatpak_table_printer_print (printer);
g_assert_cmpstr (g_print_buffer->str, ==,
FLATPAK_ANSI_BOLD_ON
"Column1 Column2" FLATPAK_ANSI_BOLD_OFF "\n"
"newtext1 0.123\n"
"text3 123.0\n");
g_string_truncate (g_print_buffer, 0);
flatpak_table_printer_free (printer);
flatpak_disable_fancy_output ();
g_set_print_handler (print_func);
g_string_free (g_print_buffer, TRUE);
g_print_buffer = NULL;
}
static void
test_table_expand (void)
{
GPrintFunc print_func;
FlatpakTablePrinter *printer;
int rows, cols;
g_assert_null (g_print_buffer);
g_print_buffer = g_string_new ("");
print_func = g_set_print_handler (my_print_func);
flatpak_enable_fancy_output ();
printer = flatpak_table_printer_new ();
flatpak_table_printer_set_column_title (printer, 0, "Column1");
flatpak_table_printer_set_column_title (printer, 1, "Column2");
flatpak_table_printer_set_column_title (printer, 2, "Column3");
flatpak_table_printer_add_column (printer, "text1");
flatpak_table_printer_add_column (printer, "text2");
flatpak_table_printer_add_column (printer, "text3");
flatpak_table_printer_finish_row (printer);
flatpak_table_printer_add_span (printer, "012345678901234567890234567890123456789");
flatpak_table_printer_finish_row (printer);
flatpak_table_printer_set_column_expand (printer, 0, TRUE);
flatpak_table_printer_print_full (printer, 0, 40, &rows, &cols);
g_assert_cmpint (rows, ==, 3);
g_assert_cmpint (cols, ==, 34);
g_assert_cmpstr (g_print_buffer->str, ==,
FLATPAK_ANSI_BOLD_ON
"Column1 Column2 Column3" FLATPAK_ANSI_BOLD_OFF "\n"
"text1 text2 text3" "\n"
"012345678901234567890234567890123456789");
g_string_truncate (g_print_buffer, 0);
flatpak_table_printer_set_column_expand (printer, 2, TRUE);
flatpak_table_printer_print_full (printer, 0, 40, &rows, &cols);
g_assert_cmpint (rows, ==, 3);
g_assert_cmpint (cols, ==, 34);
g_assert_cmpstr (g_print_buffer->str, ==,
FLATPAK_ANSI_BOLD_ON
"Column1 Column2 Column3" FLATPAK_ANSI_BOLD_OFF "\n"
"text1 text2 text3" "\n"
"012345678901234567890234567890123456789");
g_string_truncate (g_print_buffer, 0);
flatpak_table_printer_free (printer);
flatpak_disable_fancy_output ();
g_set_print_handler (print_func);
g_string_free (g_print_buffer, TRUE);
g_print_buffer = NULL;
}
static void
test_table_shrink (void)
{
GPrintFunc print_func;
FlatpakTablePrinter *printer;
int rows, cols;
g_assert_null (g_print_buffer);
g_print_buffer = g_string_new ("");
print_func = g_set_print_handler (my_print_func);
flatpak_enable_fancy_output ();
printer = flatpak_table_printer_new ();
flatpak_table_printer_set_column_title (printer, 0, "Column1");
flatpak_table_printer_set_column_title (printer, 1, "Column2");
flatpak_table_printer_set_column_title (printer, 2, "Column3");
flatpak_table_printer_add_column (printer, "a very long text");
flatpak_table_printer_add_column (printer, "text2");
flatpak_table_printer_add_column (printer, "long text too");
flatpak_table_printer_finish_row (printer);
flatpak_table_printer_add_column (printer, "short");
flatpak_table_printer_add_column (printer, "short");
flatpak_table_printer_add_column (printer, "short");
flatpak_table_printer_finish_row (printer);
flatpak_table_printer_add_span (printer, "0123456789012345678902345");
flatpak_table_printer_finish_row (printer);
flatpak_table_printer_set_column_ellipsize (printer, 0, FLATPAK_ELLIPSIZE_MODE_END);
flatpak_table_printer_print_full (printer, 0, 25, &rows, &cols);
g_assert_cmpint (rows, ==, 4);
g_assert_cmpint (cols, ==, 25);
g_assert_cmpstr (g_print_buffer->str, ==,
FLATPAK_ANSI_BOLD_ON
"Co… Column2 Column3" FLATPAK_ANSI_BOLD_OFF "\n"
"a … text2 long text too" "\n"
"sh… short short" "\n"
"0123456789012345678902345");
g_string_truncate (g_print_buffer, 0);
flatpak_table_printer_set_column_ellipsize (printer, 2, FLATPAK_ELLIPSIZE_MODE_MIDDLE);
flatpak_table_printer_print_full (printer, 0, 25, &rows, &cols);
g_assert_cmpint (rows, ==, 4);
g_assert_cmpint (cols, ==, 25);
g_assert_cmpstr (g_print_buffer->str, ==,
FLATPAK_ANSI_BOLD_ON
"Column1 Column2 Column3" FLATPAK_ANSI_BOLD_OFF "\n"
"a very … text2 long…too" "\n"
"short short short" "\n"
"0123456789012345678902345");
g_string_truncate (g_print_buffer, 0);
flatpak_table_printer_free (printer);
flatpak_disable_fancy_output ();
g_set_print_handler (print_func);
g_string_free (g_print_buffer, TRUE);
g_print_buffer = NULL;
}
static void
test_table_shrink_more (void)
{
GPrintFunc print_func;
FlatpakTablePrinter *printer;
int rows, cols;
g_assert_null (g_print_buffer);
g_print_buffer = g_string_new ("");
print_func = g_set_print_handler (my_print_func);
flatpak_enable_fancy_output ();
printer = flatpak_table_printer_new ();
flatpak_table_printer_set_column_title (printer, 0, "Column1");
flatpak_table_printer_set_column_title (printer, 1, "Column2");
flatpak_table_printer_set_column_title (printer, 2, "Column3");
flatpak_table_printer_add_column (printer, "a very long text");
flatpak_table_printer_add_column (printer, "midsize text");
flatpak_table_printer_add_column (printer, "another very long text");
flatpak_table_printer_finish_row (printer);
flatpak_table_printer_set_column_ellipsize (printer, 1, FLATPAK_ELLIPSIZE_MODE_END);
flatpak_table_printer_print_full (printer, 0, 25, &rows, &cols);
g_assert_cmpint (rows, ==, 4);
g_assert_cmpint (cols, ==, 40);
g_assert_cmpstr (g_print_buffer->str, ==,
FLATPAK_ANSI_BOLD_ON
"Column1 … Column3" FLATPAK_ANSI_BOLD_OFF "\n"
"a very long text … another very long text");
flatpak_table_printer_free (printer);
flatpak_disable_fancy_output ();
g_set_print_handler (print_func);
g_string_free (g_print_buffer, TRUE);
g_print_buffer = NULL;
}
static void
test_parse_datetime (void)
{
struct timespec ts;
struct timespec now;
gboolean ret;
g_autoptr(GDateTime) dt = NULL;
GTimeVal tv;
clock_gettime (CLOCK_REALTIME, &now);
ret = parse_datetime (&ts, "NOW", NULL);
g_assert_true (ret);
g_assert_true (ts.tv_sec == now.tv_sec); // close enough
ret = parse_datetime (&ts, "2018-10-29 00:19:07 +0000", NULL);
dt = g_date_time_new_utc (2018, 10, 29, 0, 19, 7);
g_date_time_to_timeval (dt, &tv);
g_assert_true (tv.tv_sec == ts.tv_sec &&
tv.tv_usec == ts.tv_nsec / 1000);
ret = parse_datetime (&ts, "nonsense", NULL);
g_assert_false (ret);
}
/* Test various syntax errors */
static void
test_filter_parser (void)
{
struct {
char *filter;
guint expected_error;
} filters[] = {
{
"foobar",
FLATPAK_ERROR_INVALID_DATA
},
{
"foobar *",
FLATPAK_ERROR_INVALID_DATA
},
{
"deny",
FLATPAK_ERROR_INVALID_DATA
},
{
"deny 23+123",
FLATPAK_ERROR_INVALID_DATA
},
{
"deny *\n"
"allow",
FLATPAK_ERROR_INVALID_DATA
},
{
"deny *\n"
"allow org.foo.bar extra\n",
FLATPAK_ERROR_INVALID_DATA
}
};
gboolean ret;
int i;
for (i = 0; i < G_N_ELEMENTS(filters); i++)
{
g_autoptr(GError) error = NULL;
g_autoptr(GRegex) allow_refs = NULL;
g_autoptr(GRegex) deny_refs = NULL;
ret = flatpak_parse_filters (filters[i].filter, &allow_refs, &deny_refs, &error);
g_assert_error (error, FLATPAK_ERROR, filters[i].expected_error);
g_assert_true (ret == FALSE);
g_assert_true (allow_refs == NULL);
g_assert_true (deny_refs == NULL);
}
}
static void
test_filter (void)
{
GError *error = NULL;
g_autoptr(GRegex) allow_refs = NULL;
g_autoptr(GRegex) deny_refs = NULL;
gboolean ret;
int i;
char *filter =
" # This is a comment\n"
"\tallow\t org.foo.*#comment\n"
" deny org.* # Comment\n"
" deny com.* # Comment\n"
" # another comment\n"
"allow com.foo.bar\n"
"allow app/com.bar.foo*/*/stable\n"
"allow app/com.armed.foo*/arm\n"
"allow runtime/com.gazonk\n"
"allow runtime/com.gazonk.*\t#comment*a*"; /* Note: lack of last newline to test */
struct {
char *ref;
gboolean expected_result;
} filter_refs[] = {
/* General denies (org/com)*/
{ "app/org.filter.this/x86_64/stable", FALSE },
{ "app/com.filter.this/arm/stable", FALSE },
/* But net. not denied */
{ "app/net.dont.filter.this/x86_64/stable", TRUE },
{ "runtime/net.dont.filter.this/x86_64/1.0", TRUE },
/* Special allow overrides */
/* allow com.foo.bar */
{ "app/com.foo.bar/x86_64/stable", TRUE },
{ "app/com.foo.bar/arm/foo", TRUE },
{ "runtime/com.foo.bar/x86_64/1.0", TRUE },
/* allow app/com.bar.foo* / * /stable */
{ "app/com.bar.foo/x86_64/stable", TRUE },
{ "app/com.bar.foo/arm/stable", TRUE },
{ "app/com.bar.foobar/x86_64/stable", TRUE },
{ "app/com.bar.foobar/arm/stable", TRUE },
{ "app/com.bar.foo.bar/x86_64/stable", TRUE },
{ "app/com.bar.foo.bar/arm/stable", TRUE },
{ "app/com.bar.foo/x86_64/unstable", FALSE },
{ "app/com.bar.foobar/x86_64/unstable", FALSE },
{ "runtime/com.bar.foo/x86_64/stable", FALSE },
/* allow app/com.armed.foo* /arm */
{ "app/com.armed.foo/arm/stable", TRUE },
{ "app/com.armed.foo/arm/unstable", TRUE },
{ "app/com.armed.foo/x86_64/stable", FALSE },
{ "app/com.armed.foo/x86_64/unstable", FALSE },
{ "app/com.armed.foobar/arm/stable", TRUE },
{ "app/com.armed.foobar/arm/unstable", TRUE },
{ "app/com.armed.foobar/x86_64/stable", FALSE },
{ "app/com.armed.foobar/x86_64/unstable", FALSE },
{ "runtime/com.armed.foo/arm/stable", FALSE },
{ "runtime/com.armed.foobar/arm/stable", FALSE },
{ "runtime/com.armed.foo/x86_64/stable", FALSE },
{ "runtime/com.armed.foobar/x86_64/stable", FALSE },
/* allow runtime/com.gazonk */
/* allow runtime/com.gazonk.* */
{ "runtime/com.gazonk/x86_64/1.0", TRUE },
{ "runtime/com.gazonk.Locale/x86_64/1.0", TRUE },
{ "runtime/com.gazonked/x86_64/1.0", FALSE },
{ "runtime/com.gazonk/arm/1.0", TRUE },
{ "runtime/com.gazonk.Locale/arm/1.0", TRUE },
{ "app/com.gazonk/x86_64/stable", FALSE },
{ "app/com.gazonk.Locale/x86_64/stable", FALSE },
};
ret = flatpak_parse_filters (filter, &allow_refs, &deny_refs, &error);
g_assert_no_error (error);
g_assert_true (ret == TRUE);
g_assert_true (allow_refs != NULL);
g_assert_true (deny_refs != NULL);
for (i = 0; i < G_N_ELEMENTS(filter_refs); i++)
g_assert_cmpint (flatpak_filters_allow_ref (allow_refs, deny_refs, filter_refs[i].ref), ==, filter_refs[i].expected_result);
}
static void
test_dconf_app_id (void)
{
struct {
const char *app_id;
const char *path;
} tests[] = {
{ "org.gnome.Builder", "/org/gnome/Builder/" },
{ "org.gnome.builder", "/org/gnome/builder/" },
{ "org.gnome.builder-2", "/org/gnome/builder-2/" },
};
int i;
for (i = 0; i < G_N_ELEMENTS (tests); i++)
{
g_autofree char *path = NULL;
path = flatpak_dconf_path_for_app_id (tests[i].app_id);
g_assert_cmpstr (path, ==, tests[i].path);
}
}
static void
test_dconf_paths (void)
{
struct {
const char *path1;
const char *path2;
gboolean result;
} tests[] = {
{ "/org/gnome/Builder/", "/org/gnome/builder/", 1 },
{ "/org/gnome/Builder-2/", "/org/gnome/Builder_2/", 1 },
{ "/org/gnome/Builder/", "/org/gnome/Builder", 0 },
{ "/org/gnome/Builder/", "/org/gnome/Buildex/", 0 },
{ "/org/gnome/Rhythmbox3/", "/org/gnome/rhythmbox/", 1 },
{ "/org/gnome/Rhythmbox3/", "/org/gnome/rhythmbox", 0 },
{ "/org/gnome1/Rhythmbox/", "/org/gnome/rhythmbox", 0 },
{ "/org/gnome1/Rhythmbox", "/org/gnome/rhythmbox/", 0 },
{ "/org/gnome/Rhythmbox3plus/", "/org/gnome/rhythmbox/", 0 },
{ "/org/gnome/SoundJuicer/", "/org/gnome/sound-juicer/", 1 },
{ "/org/gnome/Sound-Juicer/", "/org/gnome/sound-juicer/", 1 },
{ "/org/gnome/Soundjuicer/", "/org/gnome/sound-juicer/", 0 },
{ "/org/gnome/Soundjuicer/", "/org/gnome/soundjuicer/", 1 },
{ "/org/gnome/sound-juicer/", "/org/gnome/SoundJuicer/", 1 },
};
int i;
for (i = 0; i < G_N_ELEMENTS (tests); i++)
{
gboolean result;
result = flatpak_dconf_path_is_similar (tests[i].path1, tests[i].path2);
if (result != tests[i].result)
g_error ("Unexpected %s: flatpak_dconf_path_is_similar (%s, %s) = %d",
result ? "success" : "failure",
tests[i].path1,
tests[i].path2,
result);
}
}
int
main (int argc, char *argv[])
{
int res;
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/common/has-path-prefix", test_has_path_prefix);
g_test_add_func ("/common/path-match-prefix", test_path_match_prefix);
g_test_add_func ("/common/fancy-output", test_fancy_output);
g_test_add_func ("/common/arches", test_arches);
g_test_add_func ("/common/extension-matches", test_extension_matches);
g_test_add_func ("/common/valid-name", test_valid_name);
g_test_add_func ("/common/string-to-unsigned", test_string_to_unsigned);
g_test_add_func ("/common/levenshtein", test_levenshtein);
g_test_add_func ("/common/format-choices", test_format_choices);
g_test_add_func ("/common/yes-no-prompt", test_yes_no_prompt);
g_test_add_func ("/common/number-prompt", test_number_prompt);
g_test_add_func ("/common/parse-numbers", test_parse_numbers);
g_test_add_func ("/common/subpaths-merge", test_subpaths_merge);
g_test_add_func ("/common/lang-from-locale", test_lang_from_locale);
g_test_add_func ("/common/appdata", test_parse_appdata);
g_test_add_func ("/common/name-matching", test_name_matching);
g_test_add_func ("/common/filter_parser", test_filter_parser);
g_test_add_func ("/common/filter", test_filter);
g_test_add_func ("/common/dconf-app-id", test_dconf_app_id);
g_test_add_func ("/common/dconf-paths", test_dconf_paths);
g_test_add_func ("/app/looks-like-branch", test_looks_like_branch);
g_test_add_func ("/app/columns", test_columns);
g_test_add_func ("/app/string-ellipsize", test_string_ellipsize);
g_test_add_func ("/app/table", test_table);
g_test_add_func ("/app/table-expand", test_table_expand);
g_test_add_func ("/app/table-shrink", test_table_shrink);
g_test_add_func ("/app/table-shrink-more", test_table_shrink_more);
g_test_add_func ("/app/parse-datetime", test_parse_datetime);
res = g_test_run ();
return res;
}