diff options
author | Alexander Larsson <alexl@redhat.com> | 2020-10-28 10:08:21 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2020-10-28 17:10:09 +0100 |
commit | 9b2de3f75d9df734e5df42f105cca0c7e69ef91a (patch) | |
tree | d02087d7e84b2f6671c30e8170977f5d28fb2592 | |
parent | 8c49b48ee6a558a01512a48324400e54524e49cd (diff) | |
download | flatpak-9b2de3f75d9df734e5df42f105cca0c7e69ef91a.tar.gz |
utils: Add FlatpakDecomposed helper
This is a ref-counted version of a ref string that is guaranteed
to be in the proper form, and is pre-decomposed for efficient partial
matches.
-rw-r--r-- | common/flatpak-utils-private.h | 43 | ||||
-rw-r--r-- | common/flatpak-utils.c | 431 | ||||
-rw-r--r-- | tests/testcommon.c | 147 |
3 files changed, 620 insertions, 1 deletions
diff --git a/common/flatpak-utils-private.h b/common/flatpak-utils-private.h index dbd3816e..a4642ef0 100644 --- a/common/flatpak-utils-private.h +++ b/common/flatpak-utils-private.h @@ -216,6 +216,49 @@ char **flatpak_decompose_ref (const char *ref, char * flatpak_get_arch_for_ref (const char *ref); const char *flatpak_get_compat_arch_reverse (const char *compat_arch); + +typedef struct _FlatpakDecomposed FlatpakDecomposed; +FlatpakDecomposed *flatpak_decomposed_new_from_ref (const char *ref, + GError **error); +FlatpakDecomposed *flatpak_decomposed_new_from_refspec (const char *refspec, + GError **error); +FlatpakDecomposed *flatpak_decomposed_new_from_ref_take (char *ref, + GError **error); +FlatpakDecomposed *flatpak_decomposed_new_from_refspec_take (char *refspec, + GError **error); +FlatpakDecomposed *flatpak_decomposed_ref (FlatpakDecomposed *ref); +void flatpak_decomposed_unref (FlatpakDecomposed *ref); +const char * flatpak_decomposed_peek_ref (FlatpakDecomposed *ref); +const char * flatpak_decomposed_peek_refspec (FlatpakDecomposed *ref); +char * flatpak_decomposed_get_ref (FlatpakDecomposed *ref); +char * flatpak_decomposed_get_refspec (FlatpakDecomposed *ref); +char * flatpak_decomposed_get_remote (FlatpakDecomposed *ref); +gboolean flatpak_decomposed_equal (FlatpakDecomposed *ref_a, + FlatpakDecomposed *ref_b); +guint flatpak_decomposed_hash (FlatpakDecomposed *ref); +gboolean flatpak_decomposed_is_app (FlatpakDecomposed *ref); +gboolean flatpak_decomposed_is_runtime (FlatpakDecomposed *ref); +FlatpakKinds flatpak_decomposed_get_kind (FlatpakDecomposed *ref); +const char * flatpak_decomposed_peek_id (FlatpakDecomposed *ref); +char * flatpak_decomposed_get_id (FlatpakDecomposed *ref); +gboolean flatpak_decomposed_is_id (FlatpakDecomposed *ref, + const char *id); +gboolean flatpak_decomposed_is_id_fuzzy (FlatpakDecomposed *ref, + const char *id); +gboolean flatpak_decomposed_id_is_subref (FlatpakDecomposed *ref); +const char * flatpak_decomposed_peek_arch (FlatpakDecomposed *ref); +char * flatpak_decomposed_get_arch (FlatpakDecomposed *ref); +gboolean flatpak_decomposed_is_arch (FlatpakDecomposed *ref, + const char *arch); +gboolean flatpak_decomposed_is_arches (FlatpakDecomposed *ref, + const char **arches); +const char * flatpak_decomposed_peek_branch (FlatpakDecomposed *ref); +char * flatpak_decomposed_get_branch (FlatpakDecomposed *ref); +gboolean flatpak_decomposed_is_branch (FlatpakDecomposed *ref, + const char *branch); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakDecomposed, flatpak_decomposed_unref) + char * flatpak_filter_glob_to_regexp (const char *glob, gboolean runtime_only, GError **error); gboolean flatpak_parse_filters (const char *data, GRegex **allow_refs_out, diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c index ecd206ff..089bdd81 100644 --- a/common/flatpak-utils.c +++ b/common/flatpak-utils.c @@ -1113,7 +1113,7 @@ str_has_suffix (const gchar *str, gsize str_len, if (str_len < suffix_len) return FALSE; - return strcmp (str + str_len - suffix_len, suffix) == 0; + return strncmp (str + str_len - suffix_len, suffix, suffix_len) == 0; } @@ -1459,6 +1459,435 @@ flatpak_decompose_ref (const char *full_ref, return g_steal_pointer (&parts); } +struct _FlatpakDecomposed { + int ref_count; + guint16 ref_offset; + guint16 id_offset; + guint16 arch_offset; + guint16 branch_offset; + char *ref; +}; + +static gboolean +is_valid_initial_remote_name_character (gint c) +{ + return + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + (c == '_'); +} + +static gboolean +is_valid_remote_name_character (gint c) +{ + return + is_valid_initial_remote_name_character (c) || + c == '-' || + c == '.'; +} + +static gboolean +is_valid_remote_name (const char *remote, + gsize len) +{ + const char *end; + + if (len == 0) + return FALSE; + + end = remote + len; + + if (!is_valid_initial_remote_name_character (*remote++)) + return FALSE; + + while (remote < end) + { + char c = *remote++; + if (!is_valid_remote_name_character (c)) + return FALSE; + } + + return TRUE; +} + + +static FlatpakDecomposed * +_flatpak_decomposed_new (char *ref, + gboolean allow_refspec, + gboolean take, + GError **error) +{ + g_autoptr(GError) local_error = NULL; + const char *p; + const char *slash; + gsize ref_offset; + gsize id_offset; + gsize arch_offset; + gsize branch_offset; + gsize len; + FlatpakDecomposed *decomposed; + + /* We want to use uint16 to store offset, so fail on uselessly large refs */ + len = strlen (ref); + if (len > 0xffff) + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("Ref too long")); + return NULL; + } + + p = ref; + if (allow_refspec) + { + const char *colon = strchr (p, ':'); + if (colon != NULL) + { + if (!is_valid_remote_name (ref, colon - ref)) + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("Invalid remote name")); + return NULL; + } + p = colon + 1; + } + } + ref_offset = p - ref; + + if (g_str_has_prefix (p, "app/")) + p += strlen ("app/"); + else if (g_str_has_prefix (p, "runtime/")) + p += strlen ("runtime/"); + else + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("%s is not application or runtime"), ref); + return NULL; + } + + id_offset = p - ref; + + slash = strchr (p, '/'); + if (slash == NULL) + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("Wrong number of components in %s"), ref); + return NULL; + } + + if (!flatpak_is_valid_name (p, slash - p, &local_error)) + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("Invalid name %.*s: %s"), (int)(slash - p), p, local_error->message); + return NULL; + } + + p = slash + 1; + + arch_offset = p - ref; + + slash = strchr (p, '/'); + if (slash == NULL) + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("Wrong number of components in %s"), ref); + return NULL; + } + + if (slash - p == 0) /* empty arch */ + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("Invalid arch %.*s"), (int)(slash - p), p); + return NULL; + } + + p = slash + 1; + branch_offset = p - ref; + + slash = strchr (p, '/'); + if (slash != NULL) + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("Wrong number of components in %s"), ref); + return NULL; + } + + if (!flatpak_is_valid_branch (p, -1, &local_error)) + { + flatpak_fail_error (error, FLATPAK_ERROR_INVALID_REF, _("Invalid branch %s: %s"), p, local_error->message); + return NULL; + } + + decomposed = g_malloc (sizeof (struct _FlatpakDecomposed) + len); /* len == strlen, and then the terminating zero fits in data[1] */ + decomposed->ref_count = 1; + decomposed->ref_offset = (guint16)ref_offset; + decomposed->id_offset = (guint16)id_offset; + decomposed->arch_offset = (guint16)arch_offset; + decomposed->branch_offset = (guint16)branch_offset; + decomposed->ref = take ? ref : g_strdup (ref); + + return decomposed; +} + +FlatpakDecomposed * +flatpak_decomposed_new_from_ref (const char *ref, + GError **error) +{ + return _flatpak_decomposed_new ((char *)ref, FALSE, FALSE, error); +} + +FlatpakDecomposed * +flatpak_decomposed_new_from_refspec (const char *refspec, + GError **error) +{ + return _flatpak_decomposed_new ((char *)refspec, TRUE, FALSE, error); +} + +FlatpakDecomposed * +flatpak_decomposed_new_from_ref_take (char *ref, + GError **error) +{ + return _flatpak_decomposed_new (ref, FALSE, TRUE, error); +} + +FlatpakDecomposed * +flatpak_decomposed_new_from_refspec_take (char *refspec, + GError **error) +{ + return _flatpak_decomposed_new (refspec, TRUE, TRUE, error); +} + +FlatpakDecomposed * +flatpak_decomposed_ref (FlatpakDecomposed *ref) +{ + g_atomic_int_inc (&ref->ref_count); + return ref; +} + +void +flatpak_decomposed_unref (FlatpakDecomposed *ref) +{ + if (g_atomic_int_dec_and_test (&ref->ref_count)) + { + g_free (ref->ref); + g_free (ref); + } +} + +const char * +flatpak_decomposed_peek_ref (FlatpakDecomposed *ref) +{ + return (const char *)&ref->ref[ref->ref_offset]; +} + +char * +flatpak_decomposed_get_ref (FlatpakDecomposed *ref) +{ + return g_strdup (flatpak_decomposed_peek_ref (ref)); +} + +const char * +flatpak_decomposed_peek_refspec (FlatpakDecomposed *ref) +{ + return (const char *)&ref->ref[0]; +} + +char * +flatpak_decomposed_get_refspec (FlatpakDecomposed *ref) +{ + return g_strdup (flatpak_decomposed_peek_refspec (ref)); +} + +char * +flatpak_decomposed_get_remote (FlatpakDecomposed *ref) +{ + if (ref->ref_offset == 0) + return NULL; + + return g_strndup (ref->ref, ref->ref_offset - 1); +} + +gboolean +flatpak_decomposed_equal (FlatpakDecomposed *ref_a, + FlatpakDecomposed *ref_b) +{ + return strcmp (ref_a->ref, ref_b->ref) == 0; +} + +guint +flatpak_decomposed_hash (FlatpakDecomposed *ref) +{ + return g_str_hash (ref->ref); +} + +gboolean +flatpak_decomposed_is_app (FlatpakDecomposed *ref) +{ + return ref->ref[0] == 'a'; +} + +gboolean +flatpak_decomposed_is_runtime (FlatpakDecomposed *ref) +{ + return ref->ref[0] == 'r'; +} + +FlatpakKinds +flatpak_decomposed_get_kind (FlatpakDecomposed *ref) +{ + if (flatpak_decomposed_is_app (ref)) + return FLATPAK_KINDS_APP; + else + return FLATPAK_KINDS_RUNTIME; +} + +/* A slashed string ends at '/' instead of nul */ +static gboolean +slashed_str_equal (const char *slashed_str, const char *str) +{ + char c; + while ((c = *str) != 0) + { + char s_c = *slashed_str; + if (s_c == '/') + return FALSE; /* slashed_str stopped early */ + + if (s_c != c) + return FALSE; /* slashed_str not same */ + + str++; + slashed_str++; + } + + if (*slashed_str != '/') /* str stopped early */ + return FALSE; + + return TRUE; +} + +/* These are for refs, so ascii case only */ +static gboolean +slashed_str_strcasestr (const char *haystack, + gsize haystack_len, + const char *needle) +{ + gssize needle_len = strlen (needle); + + if (needle_len > haystack_len) + return FALSE; + + if (needle_len == 0) + return TRUE; + + for (gssize i = 0; i <= haystack_len - needle_len; i++) + { + if (g_ascii_strncasecmp (haystack + i, needle, needle_len) == 0) + return TRUE; + } + + return FALSE; +} + +const char * +flatpak_decomposed_peek_id (FlatpakDecomposed *ref) +{ + return &ref->ref[ref->id_offset]; +} + +char * +flatpak_decomposed_get_id (FlatpakDecomposed *ref) +{ + const char *ref_id = flatpak_decomposed_peek_id (ref); + + return g_strndup (ref_id, ref->arch_offset - ref->id_offset - 1); +} + +gboolean +flatpak_decomposed_is_id (FlatpakDecomposed *ref, + const char *id) +{ + const char *ref_id = flatpak_decomposed_peek_id (ref); + + return slashed_str_equal (ref_id, id); +} + +/* See if the given id looks similar to this ref. The + * Levenshtein distance constant was chosen pretty arbitrarily. */ +gboolean +flatpak_decomposed_is_id_fuzzy (FlatpakDecomposed *ref, + const char *id) +{ + const char *ref_id = flatpak_decomposed_peek_id (ref); + gsize ref_id_len = ref->arch_offset - ref->id_offset - 1; + + if (slashed_str_strcasestr (ref_id, ref_id_len, id)) + return TRUE; + + return flatpak_levenshtein_distance (id, -1, ref_id, ref_id_len) <= 2; +} + +gboolean +flatpak_decomposed_id_is_subref (FlatpakDecomposed *ref) +{ + const char *ref_id = flatpak_decomposed_peek_id (ref); + gsize ref_id_len = ref->arch_offset - ref->id_offset - 1; + + return flatpak_id_has_subref_suffix (ref_id, ref_id_len); +} + +const char * +flatpak_decomposed_peek_arch (FlatpakDecomposed *ref) +{ + return &ref->ref[ref->arch_offset]; +} + +char * +flatpak_decomposed_get_arch (FlatpakDecomposed *ref) +{ + const char *ref_arch = flatpak_decomposed_peek_arch (ref); + + return g_strndup (ref_arch, ref->branch_offset - ref->arch_offset - 1); +} + +gboolean +flatpak_decomposed_is_arch (FlatpakDecomposed *ref, + const char *arch) +{ + const char *ref_arch = flatpak_decomposed_peek_arch (ref); + + return slashed_str_equal (ref_arch, arch); +} + +gboolean +flatpak_decomposed_is_arches (FlatpakDecomposed *ref, + const char **arches) +{ + const char *ref_arch = flatpak_decomposed_peek_arch (ref); + + for (int i = 0; arches[i] != NULL; i++) + { + if (slashed_str_equal (ref_arch, arches[i])) + return TRUE; + } + + return FALSE; +} + +const char * +flatpak_decomposed_peek_branch (FlatpakDecomposed *ref) +{ + return &ref->ref[ref->branch_offset]; +} + +char * +flatpak_decomposed_get_branch (FlatpakDecomposed *ref) +{ + const char *ref_branch = flatpak_decomposed_peek_branch (ref); + + return g_strdup (ref_branch); +} + +gboolean +flatpak_decomposed_is_branch (FlatpakDecomposed *ref, + const char *branch) +{ + const char *ref_branch = flatpak_decomposed_peek_branch (ref); + + return strcmp (ref_branch, branch) == 0; +} + static const char * next_element (const char **partial_ref) { diff --git a/tests/testcommon.c b/tests/testcommon.c index 21df877b..b28cda04 100644 --- a/tests/testcommon.c +++ b/tests/testcommon.c @@ -100,6 +100,152 @@ test_valid_name (void) 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; + + g_assert_null (flatpak_decomposed_new_from_ref ("app/wrong/x86_64/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/x86_64/@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/x86_64/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/x86_64/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/x86_64", &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/x86_64/master", &error); + g_assert (runtime_ref != NULL); + g_assert_null (error); + + g_assert_cmpstr (flatpak_decomposed_peek_ref (runtime_ref), ==, "runtime/org.the.runtime/x86_64/master"); + g_assert_cmpstr (flatpak_decomposed_peek_refspec (runtime_ref), ==, "runtime/org.the.runtime/x86_64/master"); + g_assert (flatpak_decomposed_equal (runtime_ref, runtime_ref)); + g_assert (flatpak_decomposed_hash (runtime_ref) == g_str_hash ("runtime/org.the.runtime/x86_64/master")); + g_assert (!flatpak_decomposed_is_app (runtime_ref)); + g_assert (flatpak_decomposed_is_runtime (runtime_ref)); + g_assert (flatpak_decomposed_get_kind (runtime_ref) == FLATPAK_KINDS_RUNTIME); + + g_assert_cmpstr (flatpak_decomposed_peek_id (runtime_ref), ==, "org.the.runtime/x86_64/master"); + runtime_id = flatpak_decomposed_get_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), ==, "x86_64/master"); + runtime_arch = flatpak_decomposed_get_arch (runtime_ref); + g_assert_cmpstr (runtime_arch, ==, "x86_64"); + g_assert (flatpak_decomposed_is_arch (runtime_ref, "x86_64")); + g_assert (!flatpak_decomposed_is_arch (runtime_ref, "x86_6")); + g_assert (!flatpak_decomposed_is_arch (runtime_ref, "x86_644")); + + g_assert_cmpstr (flatpak_decomposed_peek_branch (runtime_ref), ==, "master"); + runtime_branch = flatpak_decomposed_get_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/x86_64/master", &error); + g_assert (app_ref != NULL); + g_assert_null (error); + + g_assert_cmpstr (flatpak_decomposed_peek_ref (app_ref), ==, "app/org.the.app/x86_64/master"); + g_assert_cmpstr (flatpak_decomposed_peek_refspec (app_ref), ==, "app/org.the.app/x86_64/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/x86_64/master")); + g_assert (flatpak_decomposed_is_app (app_ref)); + g_assert (!flatpak_decomposed_is_runtime (app_ref)); + g_assert (flatpak_decomposed_get_kind (app_ref) == FLATPAK_KINDS_APP); + + g_assert_cmpstr (flatpak_decomposed_peek_id (app_ref), ==, "org.the.app/x86_64/master"); + app_id = flatpak_decomposed_get_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), ==, "x86_64/master"); + app_arch = flatpak_decomposed_get_arch (app_ref); + g_assert_cmpstr (app_arch, ==, "x86_64"); + g_assert (flatpak_decomposed_is_arch (app_ref, "x86_64")); + g_assert (!flatpak_decomposed_is_arch (app_ref, "x86_6")); + g_assert (!flatpak_decomposed_is_arch (app_ref, "x86_644")); + + g_assert_cmpstr (flatpak_decomposed_peek_branch (app_ref), ==, "master"); + app_branch = flatpak_decomposed_get_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/x86_64/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/x86_64/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/x86_64/master", &error); + g_assert (refspec != NULL); + g_assert_null (error); + + g_assert_cmpstr (flatpak_decomposed_peek_ref (refspec), ==, "app/org.the.app/x86_64/master"); + g_assert_cmpstr (flatpak_decomposed_peek_refspec (refspec), ==, "remote:app/org.the.app/x86_64/master"); + g_autofree char *refspec_remote = flatpak_decomposed_get_remote (refspec); + g_assert_cmpstr (refspec_remote, ==, "remote"); + g_autofree char *refspec_ref = flatpak_decomposed_get_ref (refspec); + g_assert_cmpstr (refspec_ref, ==, "app/org.the.app/x86_64/master"); + g_autofree char *refspec_refspec = flatpak_decomposed_get_refspec (refspec); + g_assert_cmpstr (refspec_refspec, ==, "remote:app/org.the.app/x86_64/master"); +} + + typedef struct { const gchar *str; @@ -1202,6 +1348,7 @@ main (int argc, char *argv[]) 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 ("/app/looks-like-branch", test_looks_like_branch); g_test_add_func ("/app/columns", test_columns); |