aboutsummaryrefslogtreecommitdiff
path: root/tests/api/test-fragment.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/api/test-fragment.c')
-rw-r--r--tests/api/test-fragment.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/tests/api/test-fragment.c b/tests/api/test-fragment.c
new file mode 100644
index 000000000000..3d49145ae518
--- /dev/null
+++ b/tests/api/test-fragment.c
@@ -0,0 +1,376 @@
+/*
+ * test-fragment.c
+ * Tests for the public libpkgconf fragment API.
+ *
+ * SPDX-License-Identifier: pkgconf
+ *
+ * Copyright (c) 2026 pkgconf authors (see AUTHORS).
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * This software is provided 'as is' and without any warranty, express or
+ * implied. In no event shall the authors be liable for any damages arising
+ * from the use of this software.
+ */
+
+#include "test-api.h"
+
+static size_t
+fragment_count(const pkgconf_list_t *list)
+{
+ size_t n = 0;
+ const pkgconf_node_t *iter;
+
+ PKGCONF_FOREACH_LIST_ENTRY(list->head, iter)
+ {
+ n++;
+ }
+
+ return n;
+}
+
+static const pkgconf_fragment_t *
+fragment_at(const pkgconf_list_t *list, size_t index)
+{
+ const pkgconf_node_t *iter;
+ size_t i = 0;
+
+ PKGCONF_FOREACH_LIST_ENTRY(list->head, iter)
+ {
+ if (i++ == index)
+ return iter->data;
+ }
+
+ return NULL;
+}
+
+/*
+ * Render a fragment list to a newly-allocated C string for assertions.
+ * Caller frees.
+ */
+static char *
+render_to_string(const pkgconf_list_t *list)
+{
+ pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
+ pkgconf_fragment_render_buf(list, &buf, false, NULL, ' ');
+
+ if (pkgconf_buffer_str(&buf) == NULL)
+ return strdup("");
+
+ char *out = strdup(pkgconf_buffer_str(&buf));
+ pkgconf_buffer_finalize(&buf);
+ return out;
+}
+
+static void
+test_fragment_parse_cflags(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ TEST_ASSERT_TRUE(pkgconf_fragment_parse(client, &frags, &vars, "-I/usr/include -DFOO=1", 0));
+ TEST_ASSERT_EQ(fragment_count(&frags), 2);
+
+ const pkgconf_fragment_t *first = fragment_at(&frags, 0);
+ TEST_ASSERT_NONNULL(first);
+ TEST_ASSERT_EQ(first->type, 'I');
+ TEST_ASSERT_STRCMP_EQ(first->data, "/usr/include");
+
+ pkgconf_fragment_free(&frags);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_parse_libs(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ TEST_ASSERT_TRUE(pkgconf_fragment_parse(client, &frags, &vars, "-L/usr/lib -lfoo -lbar", 0));
+ TEST_ASSERT_EQ(fragment_count(&frags), 3);
+
+ const pkgconf_fragment_t *f0 = fragment_at(&frags, 0);
+ const pkgconf_fragment_t *f1 = fragment_at(&frags, 1);
+ const pkgconf_fragment_t *f2 = fragment_at(&frags, 2);
+
+ TEST_ASSERT_NONNULL(f0);
+ TEST_ASSERT_NONNULL(f1);
+ TEST_ASSERT_NONNULL(f2);
+
+ TEST_ASSERT_EQ(f0->type, 'L');
+ TEST_ASSERT_STRCMP_EQ(f0->data, "/usr/lib");
+ TEST_ASSERT_EQ(f1->type, 'l');
+ TEST_ASSERT_STRCMP_EQ(f1->data, "foo");
+ TEST_ASSERT_EQ(f2->type, 'l');
+ TEST_ASSERT_STRCMP_EQ(f2->data, "bar");
+
+ pkgconf_fragment_free(&frags);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_parse_empty(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ TEST_ASSERT_TRUE(pkgconf_fragment_parse(client, &frags, &vars, "", 0));
+ TEST_ASSERT_EQ(fragment_count(&frags), 0);
+
+ pkgconf_fragment_free(&frags);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_add_single(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_fragment_add(client, &frags, &vars, "-I/opt/include", 0);
+
+ TEST_ASSERT_EQ(fragment_count(&frags), 1);
+
+ const pkgconf_fragment_t *f = fragment_at(&frags, 0);
+ TEST_ASSERT_NONNULL(f);
+ TEST_ASSERT_EQ(f->type, 'I');
+ TEST_ASSERT_STRCMP_EQ(f->data, "/opt/include");
+
+ pkgconf_fragment_free(&frags);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_render_cflags(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_fragment_parse(client, &frags, &vars, "-I/usr/include -I/opt/include", 0);
+
+ char *rendered = render_to_string(&frags);
+ TEST_ASSERT_NONNULL(rendered);
+ TEST_ASSERT_STRCMP_EQ(rendered, "-I/usr/include -I/opt/include");
+
+ free(rendered);
+ pkgconf_fragment_free(&frags);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_render_libs(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_fragment_parse(client, &frags, &vars, "-L/usr/lib -lfoo", 0);
+
+ char *rendered = render_to_string(&frags);
+ TEST_ASSERT_NONNULL(rendered);
+ TEST_ASSERT_STRCMP_EQ(rendered, "-L/usr/lib -lfoo");
+
+ free(rendered);
+ pkgconf_fragment_free(&frags);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_render_empty(void)
+{
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+
+ char *rendered = render_to_string(&frags);
+ TEST_ASSERT_NONNULL(rendered);
+ TEST_ASSERT_EMPTY_STRING(rendered);
+
+ free(rendered);
+}
+
+// Filter predicate: keep only -I (include) fragments.
+static bool
+filter_only_includes(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data)
+{
+ (void) client;
+ (void) data;
+ return frag->type == 'I';
+}
+
+// Filter predicate: keep only -l (library name) fragments.
+static bool
+filter_only_libnames(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data)
+{
+ (void) client;
+ (void) data;
+ return frag->type == 'l';
+}
+
+// Filter predicate: keep nothing.
+static bool
+filter_nothing(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data)
+{
+ (void) client;
+ (void) frag;
+ (void) data;
+ return false;
+}
+
+static void
+test_fragment_filter_only_includes(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t src = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_fragment_parse(client, &src, &vars, "-I/usr/include -L/usr/lib -lfoo -I/opt/include", 0);
+
+ pkgconf_fragment_filter(client, &dst, &src, filter_only_includes, NULL);
+ TEST_ASSERT_EQ(fragment_count(&dst), 2);
+
+ const pkgconf_fragment_t *f0 = fragment_at(&dst, 0);
+ const pkgconf_fragment_t *f1 = fragment_at(&dst, 1);
+ TEST_ASSERT_NONNULL(f0);
+ TEST_ASSERT_NONNULL(f1);
+ TEST_ASSERT_EQ(f0->type, 'I');
+ TEST_ASSERT_STRCMP_EQ(f0->data, "/usr/include");
+ TEST_ASSERT_EQ(f1->type, 'I');
+ TEST_ASSERT_STRCMP_EQ(f1->data, "/opt/include");
+
+ pkgconf_fragment_free(&dst);
+ pkgconf_fragment_free(&src);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_filter_only_libnames(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t src = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_fragment_parse(client, &src, &vars, "-L/usr/lib -lfoo -lbar -I/usr/include", 0);
+
+ pkgconf_fragment_filter(client, &dst, &src, filter_only_libnames, NULL);
+
+ TEST_ASSERT_EQ(fragment_count(&dst), 2);
+
+ const pkgconf_fragment_t *f0 = fragment_at(&dst, 0);
+ const pkgconf_fragment_t *f1 = fragment_at(&dst, 1);
+ TEST_ASSERT_NONNULL(f0);
+ TEST_ASSERT_NONNULL(f1);
+ TEST_ASSERT_EQ(f0->type, 'l');
+ TEST_ASSERT_STRCMP_EQ(f0->data, "foo");
+ TEST_ASSERT_EQ(f1->type, 'l');
+ TEST_ASSERT_STRCMP_EQ(f1->data, "bar");
+
+ pkgconf_fragment_free(&dst);
+ pkgconf_fragment_free(&src);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_filter_keeps_nothing(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t src = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_fragment_parse(client, &src, &vars, "-I/usr/include -lfoo", 0);
+
+ pkgconf_fragment_filter(client, &dst, &src, filter_nothing, NULL);
+
+ TEST_ASSERT_EQ(fragment_count(&dst), 0);
+
+ pkgconf_fragment_free(&dst);
+ pkgconf_fragment_free(&src);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_has_system_dir_matches(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_path_add("/usr/include", &client->filter_includedirs, false);
+
+ pkgconf_fragment_parse(client, &frags, &vars, "-I/usr/include -I/opt/include", 0);
+
+ const pkgconf_fragment_t *system = fragment_at(&frags, 0);
+ const pkgconf_fragment_t *other = fragment_at(&frags, 1);
+ TEST_ASSERT_NONNULL(system);
+ TEST_ASSERT_NONNULL(other);
+
+ TEST_ASSERT_TRUE(pkgconf_fragment_has_system_dir(client, system));
+ TEST_ASSERT_FALSE(pkgconf_fragment_has_system_dir(client, other));
+
+ pkgconf_fragment_free(&frags);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_fragment_has_system_dir_libs(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_path_add("/usr/lib", &client->filter_libdirs, false);
+
+ pkgconf_fragment_parse(client, &frags, &vars, "-L/usr/lib -L/opt/lib", 0);
+
+ const pkgconf_fragment_t *system = fragment_at(&frags, 0);
+ const pkgconf_fragment_t *other = fragment_at(&frags, 1);
+ TEST_ASSERT_NONNULL(system);
+ TEST_ASSERT_NONNULL(other);
+
+ TEST_ASSERT_TRUE(pkgconf_fragment_has_system_dir(client, system));
+ TEST_ASSERT_FALSE(pkgconf_fragment_has_system_dir(client, other));
+
+ pkgconf_fragment_free(&frags);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+int
+main(int argc, char *argv[])
+{
+ (void) argc;
+ const char *basename = pkgconf_path_find_basename(argv[0]);
+
+ TEST_RUN(basename, test_fragment_parse_empty);
+ TEST_RUN(basename, test_fragment_parse_cflags);
+ TEST_RUN(basename, test_fragment_parse_libs);
+ TEST_RUN(basename, test_fragment_add_single);
+ TEST_RUN(basename, test_fragment_render_empty);
+ TEST_RUN(basename, test_fragment_render_cflags);
+ TEST_RUN(basename, test_fragment_render_libs);
+ TEST_RUN(basename, test_fragment_filter_only_includes);
+ TEST_RUN(basename, test_fragment_filter_only_libnames);
+ TEST_RUN(basename, test_fragment_filter_keeps_nothing);
+ TEST_RUN(basename, test_fragment_has_system_dir_matches);
+ TEST_RUN(basename, test_fragment_has_system_dir_libs);
+
+ return EXIT_SUCCESS;
+}