#include "config.h" #include #include #include #include #include "flatpak.h" #include "flatpak-utils-private.h" #include "flatpak-appdata-private.h" #include "flatpak-run-private.h" #include "flatpak-run-x11-private.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_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 ("", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org.", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org..", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org..test", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org.flatpak", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org.1flatpak.test", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org.flat-pak.test", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org.-flatpak.test", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org.flat,pak.test", -1, NULL)); g_assert_false (flatpak_is_valid_name ("org.flatpak.test", 0, NULL)); g_assert_false (flatpak_is_valid_name ("org.flatpak.test", 3, NULL)); g_assert_false (flatpak_is_valid_name ("org.flatpak.test", 4, NULL)); g_assert_true (flatpak_is_valid_name ("org.flatpak.test", -1, NULL)); g_assert_true (flatpak_is_valid_name ("org.flatpak.test", strlen("org.flatpak.test"), NULL)); g_assert_true (flatpak_is_valid_name ("org.FlatPak.TEST", -1, NULL)); g_assert_true (flatpak_is_valid_name ("org0.f1atpak.test", -1, NULL)); g_assert_true (flatpak_is_valid_name ("org.flatpak.-test", -1, NULL)); g_assert_true (flatpak_is_valid_name ("org.flatpak._test", -1, NULL)); g_assert_true (flatpak_is_valid_name ("org.flat_pak__.te--st", -1, NULL)); } static void test_decompose (void) { g_autoptr(FlatpakDecomposed) app_ref = NULL; g_autoptr(FlatpakDecomposed) runtime_ref = NULL; g_autoptr(FlatpakDecomposed) refspec = NULL; g_autoptr(GError) error = NULL; g_autofree char *app_id = NULL; g_autofree char *app_arch = NULL; g_autofree char *app_branch = NULL; g_autofree char *runtime_id = NULL; g_autofree char *runtime_arch = NULL; g_autofree char *runtime_branch = NULL; gsize len, len2; g_assert_null (flatpak_decomposed_new_from_ref ("app/wrong/mips64/master", &error)); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); g_assert_null (flatpak_decomposed_new_from_ref ("app/org.the.app//master", &error)); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); g_assert_null (flatpak_decomposed_new_from_ref ("app/org.the.app/mips64/@foo", &error)); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); g_assert_null (flatpak_decomposed_new_from_ref ("wrong/org.the.wrong/mips64/master", &error)); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); g_assert_null (flatpak_decomposed_new_from_ref ("app/org.the.app/mips64/master/extra", &error)); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); g_assert_null (flatpak_decomposed_new_from_ref ("app/org.the.app/mips64", &error)); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); runtime_ref = flatpak_decomposed_new_from_ref ("runtime/org.the.runtime/mips64/master", &error); g_assert (runtime_ref != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (runtime_ref), ==, "runtime/org.the.runtime/mips64/master"); g_assert_cmpstr (flatpak_decomposed_get_refspec (runtime_ref), ==, "runtime/org.the.runtime/mips64/master"); g_assert (flatpak_decomposed_equal (runtime_ref, runtime_ref)); g_assert (flatpak_decomposed_hash (runtime_ref) == g_str_hash ("runtime/org.the.runtime/mips64/master")); g_assert (!flatpak_decomposed_is_app (runtime_ref)); g_assert (flatpak_decomposed_is_runtime (runtime_ref)); g_assert (flatpak_decomposed_get_kinds (runtime_ref) == FLATPAK_KINDS_RUNTIME); g_assert (flatpak_decomposed_get_kind (runtime_ref) == FLATPAK_REF_KIND_RUNTIME); g_assert_cmpstr (flatpak_decomposed_peek_id (runtime_ref, &len), ==, "org.the.runtime/mips64/master"); g_assert (len == strlen("org.the.runtime")); runtime_id = flatpak_decomposed_dup_id (runtime_ref); g_assert_cmpstr (runtime_id, ==, "org.the.runtime"); g_assert (flatpak_decomposed_is_id (runtime_ref, "org.the.runtime")); g_assert (!flatpak_decomposed_is_id (runtime_ref, "org.the.runtim")); g_assert (!flatpak_decomposed_is_id (runtime_ref, "org.the.runtimee")); g_assert_cmpstr (flatpak_decomposed_peek_arch (runtime_ref, &len), ==, "mips64/master"); g_assert (len == strlen ("mips64")); runtime_arch = flatpak_decomposed_dup_arch (runtime_ref); g_assert_cmpstr (runtime_arch, ==, "mips64"); g_assert (flatpak_decomposed_is_arch (runtime_ref, "mips64")); g_assert (!flatpak_decomposed_is_arch (runtime_ref, "mips6")); g_assert (!flatpak_decomposed_is_arch (runtime_ref, "mips644")); g_assert_cmpstr (flatpak_decomposed_peek_branch (runtime_ref, &len), ==, "master"); g_assert (len == strlen ("master")); runtime_branch = flatpak_decomposed_dup_branch (runtime_ref); g_assert_cmpstr (runtime_branch, ==, "master"); g_assert (flatpak_decomposed_is_branch (runtime_ref, "master")); g_assert (!flatpak_decomposed_is_arch (runtime_ref, "maste")); g_assert (!flatpak_decomposed_is_arch (runtime_ref, "masterr")); app_ref = flatpak_decomposed_new_from_ref ("app/org.the.app/mips64/master", &error); g_assert (app_ref != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (app_ref), ==, "app/org.the.app/mips64/master"); g_assert_cmpstr (flatpak_decomposed_get_refspec (app_ref), ==, "app/org.the.app/mips64/master"); g_assert (flatpak_decomposed_equal (app_ref, app_ref)); g_assert (!flatpak_decomposed_equal (app_ref, runtime_ref)); g_assert (flatpak_decomposed_hash (app_ref) == g_str_hash ("app/org.the.app/mips64/master")); g_assert (flatpak_decomposed_is_app (app_ref)); g_assert (!flatpak_decomposed_is_runtime (app_ref)); g_assert (flatpak_decomposed_get_kinds (app_ref) == FLATPAK_KINDS_APP); g_assert (flatpak_decomposed_get_kind (app_ref) == FLATPAK_REF_KIND_APP); g_assert_cmpstr (flatpak_decomposed_peek_id (app_ref, &len), ==, "org.the.app/mips64/master"); g_assert (len == strlen ("org.the.app")); app_id = flatpak_decomposed_dup_id (app_ref); g_assert_cmpstr (app_id, ==, "org.the.app"); g_assert (flatpak_decomposed_is_id (app_ref, "org.the.app")); g_assert (!flatpak_decomposed_is_id (app_ref, "org.the.ap")); g_assert (!flatpak_decomposed_is_id (app_ref, "org.the.appp")); g_assert_cmpstr (flatpak_decomposed_peek_arch (app_ref, &len), ==, "mips64/master"); g_assert (len == strlen ("mips64")); app_arch = flatpak_decomposed_dup_arch (app_ref); g_assert_cmpstr (app_arch, ==, "mips64"); g_assert (flatpak_decomposed_is_arch (app_ref, "mips64")); g_assert (!flatpak_decomposed_is_arch (app_ref, "mips6")); g_assert (!flatpak_decomposed_is_arch (app_ref, "mips644")); g_assert_cmpstr (flatpak_decomposed_get_branch (app_ref), ==, "master"); g_assert_cmpstr (flatpak_decomposed_peek_branch (app_ref, &len), ==, "master"); g_assert (len == strlen ("master")); app_branch = flatpak_decomposed_dup_branch (app_ref); g_assert_cmpstr (app_branch, ==, "master"); g_assert (flatpak_decomposed_is_branch (app_ref, "master")); g_assert (!flatpak_decomposed_is_arch (app_ref, "maste")); g_assert (!flatpak_decomposed_is_arch (app_ref, "masterr")); refspec = flatpak_decomposed_new_from_ref ("remote:app/org.the.app/mips64/master", &error); g_assert (refspec == NULL); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); refspec = flatpak_decomposed_new_from_refspec ("remote/broken:app/org.the.app/mips64/master", &error); g_assert (refspec == NULL); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); refspec = flatpak_decomposed_new_from_refspec ("remote:app/org.the.app/mips64/master", &error); g_assert (refspec != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (refspec), ==, "app/org.the.app/mips64/master"); g_assert_cmpstr (flatpak_decomposed_get_refspec (refspec), ==, "remote:app/org.the.app/mips64/master"); g_autofree char *refspec_remote = flatpak_decomposed_dup_remote (refspec); g_assert_cmpstr (refspec_remote, ==, "remote"); g_autofree char *refspec_ref = flatpak_decomposed_dup_ref (refspec); g_assert_cmpstr (refspec_ref, ==, "app/org.the.app/mips64/master"); g_autofree char *refspec_refspec = flatpak_decomposed_dup_refspec (refspec); g_assert_cmpstr (refspec_refspec, ==, "remote:app/org.the.app/mips64/master"); { FlatpakDecomposed *old = runtime_ref; g_autoptr(FlatpakDecomposed) new = flatpak_decomposed_new_from_decomposed (old, 0, NULL, NULL, NULL, &error); g_assert (new != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (new), ==, flatpak_decomposed_get_ref (old)); g_assert_cmpstr (flatpak_decomposed_peek_id (new, &len), ==, flatpak_decomposed_peek_id (old, &len2)); g_assert (len == len2); g_assert_cmpstr (flatpak_decomposed_peek_arch (new, &len), ==, flatpak_decomposed_peek_arch (old, &len2)); g_assert (len == len2); g_assert_cmpstr (flatpak_decomposed_peek_branch (new, &len), ==, flatpak_decomposed_peek_branch (old, &len2)); g_assert (len == len2); } { FlatpakDecomposed *old = app_ref; g_autoptr(FlatpakDecomposed) new = flatpak_decomposed_new_from_decomposed (old, 0, NULL, NULL, NULL, &error); g_assert (new != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (new), ==, flatpak_decomposed_get_ref (old)); g_assert_cmpstr (flatpak_decomposed_peek_id (new, &len), ==, flatpak_decomposed_peek_id (old, &len2)); g_assert (len == len2); g_assert_cmpstr (flatpak_decomposed_peek_arch (new, &len), ==, flatpak_decomposed_peek_arch (old, &len2)); g_assert (len == len2); g_assert_cmpstr (flatpak_decomposed_peek_branch (new, &len), ==, flatpak_decomposed_peek_branch (old, &len2)); g_assert (len == len2); } { FlatpakDecomposed *old = app_ref; g_autofree gchar *new_id = NULL; g_autoptr(FlatpakDecomposed) new = flatpak_decomposed_new_from_decomposed (old, FLATPAK_KINDS_RUNTIME, "org.new.app", NULL, NULL, &error); g_assert (new != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (new), ==, "runtime/org.new.app/mips64/master"); g_assert (flatpak_decomposed_get_kinds (new) == FLATPAK_KINDS_RUNTIME); new_id = flatpak_decomposed_dup_id (new); g_assert_cmpstr (new_id, ==, "org.new.app"); g_assert_cmpstr (flatpak_decomposed_peek_arch (new, &len), ==, flatpak_decomposed_peek_arch (old, &len2)); g_assert (len == len2); g_assert_cmpstr (flatpak_decomposed_peek_branch (new, &len), ==, flatpak_decomposed_peek_branch (old, &len2)); g_assert (len == len2); } { FlatpakDecomposed *old = app_ref; g_autofree gchar *old_id = NULL; g_autofree gchar *new_id = NULL; g_autofree gchar *new_arch = NULL; g_autofree gchar *old_branch = NULL; g_autofree gchar *new_branch = NULL; g_autoptr(FlatpakDecomposed) new = flatpak_decomposed_new_from_decomposed (old, 0, NULL, "m68k", NULL, &error); g_assert (new != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (new), ==, "app/org.the.app/m68k/master"); g_assert (flatpak_decomposed_get_kinds (new) == FLATPAK_KINDS_APP); new_id = flatpak_decomposed_dup_id (new); old_id = flatpak_decomposed_dup_id (old); g_assert_cmpstr (new_id, ==, old_id); new_arch = flatpak_decomposed_dup_arch (new); g_assert_cmpstr (new_arch, ==, "m68k"); new_branch = flatpak_decomposed_dup_branch (new); old_branch = flatpak_decomposed_dup_branch (old); g_assert_cmpstr (new_branch, ==, old_branch); } { FlatpakDecomposed *old = app_ref; g_autofree gchar *old_id = NULL; g_autofree gchar *new_id = NULL; g_autofree gchar *new_arch = NULL; g_autofree gchar *old_arch = NULL; g_autofree gchar *new_branch = NULL; g_autoptr(FlatpakDecomposed) new = flatpak_decomposed_new_from_decomposed (old, 0, NULL, NULL, "beta", &error); g_assert (new != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (new), ==, "app/org.the.app/mips64/beta"); g_assert (flatpak_decomposed_get_kinds (new) == FLATPAK_KINDS_APP); new_id = flatpak_decomposed_dup_id (new); old_id = flatpak_decomposed_dup_id (old); g_assert_cmpstr (new_id, ==, old_id); new_arch = flatpak_decomposed_dup_arch (new); old_arch = flatpak_decomposed_dup_arch (old); g_assert_cmpstr (new_arch, ==, old_arch); new_branch = flatpak_decomposed_dup_branch (new); g_assert_cmpstr (new_branch, ==, "beta"); } { FlatpakDecomposed *old = app_ref; g_autofree gchar *new_id = NULL; g_autofree gchar *new_arch = NULL; g_autofree gchar *new_branch = NULL; g_autoptr(FlatpakDecomposed) new = flatpak_decomposed_new_from_decomposed (old, FLATPAK_KINDS_RUNTIME, "org.new.app", "m68k", "beta", &error); g_assert (new != NULL); g_assert_null (error); g_assert_cmpstr (flatpak_decomposed_get_ref (new), ==, "runtime/org.new.app/m68k/beta"); g_assert (flatpak_decomposed_get_kinds (new) == FLATPAK_KINDS_RUNTIME); new_id = flatpak_decomposed_dup_id (new); g_assert_cmpstr (new_id, ==, "org.new.app"); new_arch = flatpak_decomposed_dup_arch (new); g_assert_cmpstr (new_arch, ==, "m68k"); new_branch = flatpak_decomposed_dup_branch (new); g_assert_cmpstr (new_branch, ==, "beta"); } { g_autoptr(FlatpakDecomposed) pref = NULL; g_autofree gchar *id = NULL; g_autofree gchar *arch = NULL; g_autofree gchar *branch = NULL; pref = flatpak_decomposed_new_from_pref (FLATPAK_KINDS_RUNTIME, "org.the.@pp.Locale/mips64/master", &error); g_assert_null (pref); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); pref = flatpak_decomposed_new_from_pref (FLATPAK_KINDS_RUNTIME, "org.the.app.Locale/x86@64/master", &error); g_assert_null (pref); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); pref = flatpak_decomposed_new_from_pref (FLATPAK_KINDS_RUNTIME, "org.the.app.Locale//master", &error); g_assert_null (pref); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); pref = flatpak_decomposed_new_from_pref (FLATPAK_KINDS_RUNTIME, "org.the.app.Locale/mips64", &error); g_assert_null (pref); g_assert (error != NULL); g_assert (error->domain == FLATPAK_ERROR); g_assert (error->code == FLATPAK_ERROR_INVALID_REF); g_clear_error (&error); pref = flatpak_decomposed_new_from_pref (FLATPAK_KINDS_RUNTIME, "org.the.app.Locale/mips64/master", &error); if (error) g_print ("XXXXXXXX error: %s\n", error->message); g_assert_nonnull (pref); g_assert (error == NULL); g_assert_cmpstr (flatpak_decomposed_get_ref (pref), ==, "runtime/org.the.app.Locale/mips64/master"); g_assert (flatpak_decomposed_get_kinds (pref) == FLATPAK_KINDS_RUNTIME); id = flatpak_decomposed_dup_id (pref); g_assert_cmpstr (id, ==, "org.the.app.Locale"); arch = flatpak_decomposed_dup_arch (pref); g_assert_cmpstr (arch, ==, "mips64"); branch = flatpak_decomposed_dup_branch (pref); g_assert_cmpstr (branch, ==, "master"); } { g_autoptr(FlatpakDecomposed) a = flatpak_decomposed_new_from_ref ("app/org.app.A/mips64/master", NULL); g_autoptr(FlatpakDecomposed) a_l = flatpak_decomposed_new_from_ref ("runtime/org.app.A.Locale/mips64/master", NULL); g_autoptr(FlatpakDecomposed) b = flatpak_decomposed_new_from_ref ("app/org.app.B/mips64/master", NULL); g_autoptr(FlatpakDecomposed) b_l = flatpak_decomposed_new_from_ref ("runtime/org.app.B.Locale/mips64/master", NULL); g_autoptr(FlatpakDecomposed) c = flatpak_decomposed_new_from_ref ("app/org.app.A/m68k/master", NULL); g_autoptr(FlatpakDecomposed) c_l = flatpak_decomposed_new_from_ref ("runtime/org.app.A.Locale/m68k/master", NULL); g_autoptr(FlatpakDecomposed) d = flatpak_decomposed_new_from_ref ("app/org.app.A/mips64/beta", NULL); g_autoptr(FlatpakDecomposed) d_l = flatpak_decomposed_new_from_ref ("runtime/org.app.A.Locale/mips64/beta", NULL); g_assert (flatpak_decomposed_id_is_subref_of (a_l, a)); g_assert (!flatpak_decomposed_id_is_subref_of (b_l, a)); g_assert (!flatpak_decomposed_id_is_subref_of (c_l, a)); g_assert (!flatpak_decomposed_id_is_subref_of (d_l, a)); g_assert (!flatpak_decomposed_id_is_subref_of (a, a)); g_assert (!flatpak_decomposed_id_is_subref_of (b, a)); g_assert (!flatpak_decomposed_id_is_subref_of (c, a)); g_assert (!flatpak_decomposed_id_is_subref_of (d, a)); g_assert (!flatpak_decomposed_id_is_subref_of (a_l, b)); g_assert (flatpak_decomposed_id_is_subref_of (b_l, b)); g_assert (!flatpak_decomposed_id_is_subref_of (c_l, b)); g_assert (!flatpak_decomposed_id_is_subref_of (d_l, b)); g_assert (!flatpak_decomposed_id_is_subref_of (a, b)); g_assert (!flatpak_decomposed_id_is_subref_of (b, b)); g_assert (!flatpak_decomposed_id_is_subref_of (c, b)); g_assert (!flatpak_decomposed_id_is_subref_of (d, b)); g_assert (!flatpak_decomposed_id_is_subref_of (a_l, c)); g_assert (!flatpak_decomposed_id_is_subref_of (b_l, c)); g_assert (flatpak_decomposed_id_is_subref_of (c_l, c)); g_assert (!flatpak_decomposed_id_is_subref_of (d_l, c)); g_assert (!flatpak_decomposed_id_is_subref_of (a, c)); g_assert (!flatpak_decomposed_id_is_subref_of (b, c)); g_assert (!flatpak_decomposed_id_is_subref_of (c, c)); g_assert (!flatpak_decomposed_id_is_subref_of (d, c)); g_assert (!flatpak_decomposed_id_is_subref_of (a_l, d)); g_assert (!flatpak_decomposed_id_is_subref_of (b_l, d)); g_assert (!flatpak_decomposed_id_is_subref_of (c_l, d)); g_assert (flatpak_decomposed_id_is_subref_of (d_l, d)); g_assert (!flatpak_decomposed_id_is_subref_of (a, d)); g_assert (!flatpak_decomposed_id_is_subref_of (b, d)); g_assert (!flatpak_decomposed_id_is_subref_of (c, d)); g_assert (!flatpak_decomposed_id_is_subref_of (d, d)); } } typedef struct { const gchar *str; guint base; gint min; gint max; gint expected; gboolean should_fail; GNumberParserError code; } TestData; const TestData test_data[] = { /* typical cases for unsigned */ { "-1", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "1", 10, 0, 2, 1, FALSE, 0}, { "+1", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "0", 10, 0, 2, 0, FALSE, 0}, { "+0", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "-0", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "2", 10, 0, 2, 2, FALSE, 0}, { "+2", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "3", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS }, { "+3", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, /* min == max cases for unsigned */ { "2", 10, 2, 2, 2, FALSE, 0 }, { "3", 10, 2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS }, { "1", 10, 2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS }, /* invalid inputs */ { "", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "a", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "1a", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, /* leading/trailing whitespace */ { " 1", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "1 ", 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, /* hexadecimal numbers */ { "a", 16, 0, 15, 10, FALSE, 0 }, { "0xa", 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "-0xa", 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "+0xa", 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "- 0xa", 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, { "+ 0xa", 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID }, }; 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 = g_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_NUMBER_PARSER_ERROR, data->code); g_clear_error (&error); } else { g_assert_true (result); g_assert_no_error (error); g_assert_cmpint (value, ==, data->expected); g_assert_cmpint (data->code, ==, 0); } } } 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, -1, data->b, -1), ==, data->distance); g_assert_cmpint (flatpak_levenshtein_distance (data->b, -1, data->a, -1), ==, data->distance); } } 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_parse_appdata (void) { const char appdata1[] = "\n" "\n" " \n" " org.test.Hello.desktop\n" " Hello world test app: org.test.Hello\n" " Print a greeting\n" "

This is a test app.

\n" " \n" " Utility\n" " \n" " 64x64/org.gnome.gedit.png\n" " \n" " \n" /* 01-05-2018 */ " \n" " \n" " moderate\n" " mild\n" " none\n" " \n" "
\n" "
"; const char appdata2[] = "\n" "\n" " \n" " org.test.Hello.desktop\n" " Hello world test app: org.test.Hello\n" " Hallo Welt test app: org.test.Hello\n" " Print a greeting\n" " Schreib mal was\n" "

This is a test app.

\n" " \n" " Utility\n" " \n" " 64x64/org.gnome.gedit.png\n" " \n" " \n" " \n" " \n" " \n" " \n" " anything goes\n" " \n" " \n" "
\n" "
"; 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); } /* Test various syntax errors */ static void test_filter_parser (void) { struct { const 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; const 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 { const char *ref; gboolean expected_result; } filter_refs[] = { /* General denies (org/com)*/ { "app/org.filter.this/mips64/stable", FALSE }, { "app/com.filter.this/arm/stable", FALSE }, /* But net. not denied */ { "app/net.dont.filter.this/mips64/stable", TRUE }, { "runtime/net.dont.filter.this/mips64/1.0", TRUE }, /* Special allow overrides */ /* allow com.foo.bar */ { "app/com.foo.bar/mips64/stable", TRUE }, { "app/com.foo.bar/arm/foo", TRUE }, { "runtime/com.foo.bar/mips64/1.0", TRUE }, /* allow app/com.bar.foo* / * /stable */ { "app/com.bar.foo/mips64/stable", TRUE }, { "app/com.bar.foo/arm/stable", TRUE }, { "app/com.bar.foobar/mips64/stable", TRUE }, { "app/com.bar.foobar/arm/stable", TRUE }, { "app/com.bar.foo.bar/mips64/stable", TRUE }, { "app/com.bar.foo.bar/arm/stable", TRUE }, { "app/com.bar.foo/mips64/unstable", FALSE }, { "app/com.bar.foobar/mips64/unstable", FALSE }, { "runtime/com.bar.foo/mips64/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/mips64/stable", FALSE }, { "app/com.armed.foo/mips64/unstable", FALSE }, { "app/com.armed.foobar/arm/stable", TRUE }, { "app/com.armed.foobar/arm/unstable", TRUE }, { "app/com.armed.foobar/mips64/stable", FALSE }, { "app/com.armed.foobar/mips64/unstable", FALSE }, { "runtime/com.armed.foo/arm/stable", FALSE }, { "runtime/com.armed.foobar/arm/stable", FALSE }, { "runtime/com.armed.foo/mips64/stable", FALSE }, { "runtime/com.armed.foobar/mips64/stable", FALSE }, /* allow runtime/com.gazonk */ /* allow runtime/com.gazonk.* */ { "runtime/com.gazonk/mips64/1.0", TRUE }, { "runtime/com.gazonk.Locale/mips64/1.0", TRUE }, { "runtime/com.gazonked/mips64/1.0", FALSE }, { "runtime/com.gazonk/arm/1.0", TRUE }, { "runtime/com.gazonk.Locale/arm/1.0", TRUE }, { "app/com.gazonk/mips64/stable", FALSE }, { "app/com.gazonk.Locale/mips64/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); } } static void test_envp_cmp (void) { static const char * const unsorted[] = { "SAME_NAME=2", "EARLY_NAME=a", "SAME_NAME=222", "Z_LATE_NAME=b", "SUFFIX_ADDED=23", "SAME_NAME=1", "SAME_NAME=", "SUFFIX=42", "SAME_NAME=3", "SAME_NAME", }; static const char * const sorted[] = { "EARLY_NAME=a", "SAME_NAME", "SAME_NAME=", "SAME_NAME=1", "SAME_NAME=2", "SAME_NAME=222", "SAME_NAME=3", "SUFFIX=42", "SUFFIX_ADDED=23", "Z_LATE_NAME=b", }; const char **sort_this = NULL; gsize i, j; G_STATIC_ASSERT (G_N_ELEMENTS (sorted) == G_N_ELEMENTS (unsorted)); for (i = 0; i < G_N_ELEMENTS (sorted); i++) { g_autofree gchar *copy = g_strdup (sorted[i]); g_test_message ("%s == %s", copy, sorted[i]); g_assert_cmpint (flatpak_envp_cmp (©, &sorted[i]), ==, 0); g_assert_cmpint (flatpak_envp_cmp (&sorted[i], ©), ==, 0); for (j = i + 1; j < G_N_ELEMENTS (sorted); j++) { g_test_message ("%s < %s", sorted[i], sorted[j]); g_assert_cmpint (flatpak_envp_cmp (&sorted[i], &sorted[j]), <, 0); g_assert_cmpint (flatpak_envp_cmp (&sorted[j], &sorted[i]), >, 0); } } sort_this = g_new0 (const char *, G_N_ELEMENTS (unsorted)); for (i = 0; i < G_N_ELEMENTS (unsorted); i++) sort_this[i] = unsorted[i]; qsort (sort_this, G_N_ELEMENTS (unsorted), sizeof (char *), flatpak_envp_cmp); for (i = 0; i < G_N_ELEMENTS (sorted); i++) g_assert_cmpstr (sorted[i], ==, sort_this[i]); g_free (sort_this); } static void test_needs_quoting (void) { static const char * const needs_quoting[] = { "", "$var", "{}", "()", "[]", "*", "?", "`exec`", "has space", "quoted-\"", "quoted-'", "back\\slash", "control\001char", }; static const char * const does_not_need_quoting[] = { "foo", "--foo=bar", "-x", "foo@bar:/srv/big_files", "~smcv", "7-zip.org", }; gsize i; for (i = 0; i < G_N_ELEMENTS (needs_quoting); i++) { const char *orig = needs_quoting[i]; g_autoptr(GError) error = NULL; g_autofree char *quoted = NULL; int argc = -1; g_auto(GStrv) argv = NULL; gboolean ok; g_assert_true (flatpak_argument_needs_quoting (orig)); quoted = flatpak_quote_argv (&orig, 1); g_test_message ("Unquoted: \"%s\"", orig); g_test_message (" Quoted: \"%s\"", quoted); g_assert_cmpstr (quoted, !=, orig); ok = g_shell_parse_argv (quoted, &argc, &argv, &error); g_assert_no_error (error); g_assert_true (ok); g_assert_cmpint (argc, ==, 1); g_assert_nonnull (argv); g_assert_cmpstr (argv[0], ==, orig); g_assert_cmpstr (argv[1], ==, NULL); } for (i = 0; i < G_N_ELEMENTS (does_not_need_quoting); i++) { const char *orig = does_not_need_quoting[i]; g_autoptr(GError) error = NULL; g_autofree char *quoted = NULL; int argc = -1; g_auto(GStrv) argv = NULL; gboolean ok; g_assert_false (flatpak_argument_needs_quoting (orig)); quoted = flatpak_quote_argv (&orig, 1); g_assert_cmpstr (quoted, ==, orig); ok = g_shell_parse_argv (quoted, &argc, &argv, &error); g_assert_no_error (error); g_assert_true (ok); g_assert_cmpint (argc, ==, 1); g_assert_nonnull (argv); g_assert_cmpstr (argv[0], ==, orig); g_assert_cmpstr (argv[1], ==, NULL); } } static void test_quote_argv (void) { static const char * const orig[] = { "foo", "--bar", "", "baz", NULL }; gsize i; g_autofree char *quoted = NULL; g_autoptr(GError) error = NULL; int argc = -1; g_auto(GStrv) argv = NULL; gboolean ok; quoted = flatpak_quote_argv ((const char **) orig, -1); ok = g_shell_parse_argv (quoted, &argc, &argv, &error); g_assert_no_error (error); g_assert_true (ok); g_assert_cmpint (argc, >, 0); g_assert_cmpuint ((gsize) argc, ==, G_N_ELEMENTS (orig) - 1); g_assert_nonnull (argv); for (i = 0; i < G_N_ELEMENTS (orig); i++) g_assert_cmpstr (argv[i], ==, orig[i]); g_clear_pointer ("ed, g_free); g_clear_pointer (&argv, g_strfreev); quoted = flatpak_quote_argv ((const char **) orig, 3); ok = g_shell_parse_argv (quoted, &argc, &argv, &error); g_assert_no_error (error); g_assert_true (ok); g_assert_cmpint (argc, ==, 3); g_assert_nonnull (argv); for (i = 0; i < 3; i++) g_assert_cmpstr (argv[i], ==, orig[i]); g_assert_cmpstr (argv[i], ==, NULL); } static void test_str_is_integer (void) { g_assert_true (flatpak_str_is_integer ("0")); g_assert_true (flatpak_str_is_integer ("1234567890987654356765432121245674")); g_assert_false (flatpak_str_is_integer (NULL)); g_assert_false (flatpak_str_is_integer ("")); g_assert_false (flatpak_str_is_integer ("0.0")); g_assert_false (flatpak_str_is_integer ("0e0")); g_assert_false (flatpak_str_is_integer ("bees")); g_assert_false (flatpak_str_is_integer ("1234a")); g_assert_false (flatpak_str_is_integer ("a1234")); } /* These are part of the X11 protocol, so we can safely hard-code them here */ #define FamilyInternet6 6 #define FamilyLocal 256 #define FamilyWild 65535 typedef struct { const char *display; int family; const char *x11_socket; const char *remote_host; const char *display_number; } DisplayTest; static const DisplayTest x11_display_tests[] = { /* Valid test-cases */ { ":0", FamilyLocal, "/tmp/.X11-unix/X0", NULL, "0" }, { ":0.0", FamilyLocal, "/tmp/.X11-unix/X0", NULL, "0" }, { ":42.0", FamilyLocal, "/tmp/.X11-unix/X42", NULL, "42" }, { "unix:42", FamilyLocal, "/tmp/.X11-unix/X42", NULL, "42" }, { "othermachine:23", FamilyWild, NULL, "othermachine", "23" }, { "bees.example.com:23", FamilyWild, NULL, "bees.example.com", "23" }, { "[::1]:0", FamilyInternet6, NULL, "::1", "0" }, /* Invalid test-cases */ { "", 0 }, { "nope", 0 }, { ":!", 0 }, { "othermachine::" }, }; static void test_parse_x11_display (void) { gsize i; for (i = 0; i < G_N_ELEMENTS (x11_display_tests); i++) { const DisplayTest *test = &x11_display_tests[i]; int family = -1; g_autofree char *x11_socket = NULL; g_autofree char *remote_host = NULL; g_autofree char *display_number = NULL; gboolean ok; g_autoptr(GError) error = NULL; g_test_message ("%s", test->display); ok = flatpak_run_parse_x11_display (test->display, &family, &x11_socket, &remote_host, &display_number, &error); if (test->family == 0) { g_assert_nonnull (error); g_assert_false (ok); g_assert_null (x11_socket); g_assert_null (remote_host); g_assert_null (display_number); g_test_message ("-> could not parse: %s", error->message); } else { g_assert_no_error (error); g_assert_true (ok); g_assert_cmpint (family, ==, test->family); g_assert_cmpstr (x11_socket, ==, test->x11_socket); g_assert_cmpstr (remote_host, ==, test->remote_host); g_assert_cmpstr (display_number, ==, test->display_number); g_test_message ("-> successfully parsed"); } } } typedef struct { const char *in; FlatpakEscapeFlags flags; const char *out; } EscapeData; static EscapeData escapes[] = { {"abc def", FLATPAK_ESCAPE_DEFAULT, "abc def"}, {"やあ", FLATPAK_ESCAPE_DEFAULT, "やあ"}, {"\033[;1m", FLATPAK_ESCAPE_DEFAULT, "'\\x1B[;1m'"}, /* U+061C ARABIC LETTER MARK, non-printable */ {"\u061C", FLATPAK_ESCAPE_DEFAULT, "'\\u061C'"}, /* U+1343F EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE, non-printable and * outside BMP */ {"\xF0\x93\x90\xBF", FLATPAK_ESCAPE_DEFAULT, "'\\U0001343F'"}, /* invalid utf-8 */ {"\xD8\1", FLATPAK_ESCAPE_DEFAULT, "'\\xD8\\x01'"}, {"\b \n abc ' \\", FLATPAK_ESCAPE_DEFAULT, "'\\x08 \\x0A abc \\' \\\\'"}, {"\b \n abc ' \\", FLATPAK_ESCAPE_DO_NOT_QUOTE, "\\x08 \\x0A abc ' \\\\"}, {"abc\tdef\n\033[;1m ghi\b", FLATPAK_ESCAPE_ALLOW_NEWLINES | FLATPAK_ESCAPE_DO_NOT_QUOTE, "abc\\x09def\n\\x1B[;1m ghi\\x08"}, }; /* CVE-2023-28101 */ static void test_string_escape (void) { gsize idx; for (idx = 0; idx < G_N_ELEMENTS (escapes); idx++) { EscapeData *data = &escapes[idx]; g_autofree char *ret = NULL; ret = flatpak_escape_string (data->in, data->flags); g_assert_cmpstr (ret, ==, data->out); } } typedef struct { const char *path; gboolean ret; } PathValidityData; static PathValidityData paths[] = { {"/a/b/../c.def", TRUE}, {"やあ", TRUE}, /* U+061C ARABIC LETTER MARK, non-printable */ {"\u061C", FALSE}, /* U+1343F EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE, non-printable and * outside BMP */ {"\xF0\x93\x90\xBF", FALSE}, /* invalid utf-8 */ {"\xD8\1", FALSE}, }; /* CVE-2023-28101 */ static void test_validate_path_characters (void) { gsize idx; for (idx = 0; idx < G_N_ELEMENTS (paths); idx++) { PathValidityData *data = &paths[idx]; gboolean ret = FALSE; ret = flatpak_validate_path_characters (data->path, NULL); g_assert_cmpint (ret, ==, data->ret); } } 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/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/subpaths-merge", test_subpaths_merge); 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 ("/common/decompose-ref", test_decompose); g_test_add_func ("/common/envp-cmp", test_envp_cmp); g_test_add_func ("/common/needs-quoting", test_needs_quoting); g_test_add_func ("/common/quote-argv", test_quote_argv); g_test_add_func ("/common/str-is-integer", test_str_is_integer); g_test_add_func ("/common/parse-x11-display", test_parse_x11_display); g_test_add_func ("/common/string-escape", test_string_escape); g_test_add_func ("/common/validate-path-characters", test_validate_path_characters); res = g_test_run (); return res; }