summaryrefslogtreecommitdiff
path: root/tests/api/test-variable.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/api/test-variable.c')
-rw-r--r--tests/api/test-variable.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/tests/api/test-variable.c b/tests/api/test-variable.c
new file mode 100644
index 000000000000..ec65df3ae5a8
--- /dev/null
+++ b/tests/api/test-variable.c
@@ -0,0 +1,247 @@
+/*
+ * test-variable.c
+ * Tests for the public libpkgconf variable API.
+ *
+ * SPDX-License-Identifier: pkgconf
+ *
+ * Copyright (c) 2025 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 <libpkgconf/stdinc.h>
+#include <libpkgconf/libpkgconf.h>
+#include "test-api.h"
+
+/*
+ * Install a value on a variable by compiling it as bytecode.
+ * Mirrors what the parser does when it reads a .pc field.
+ */
+static void
+seed_variable(pkgconf_list_t *vars, const char *key, const char *value)
+{
+ pkgconf_variable_t *v = pkgconf_variable_get_or_create(vars, key);
+ TEST_ASSERT_NONNULL(v);
+
+ pkgconf_buffer_reset(&v->bcbuf);
+ pkgconf_bytecode_compile(&v->bcbuf, value);
+ pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf);
+}
+
+static void
+test_variable_new_and_free(void)
+{
+ pkgconf_variable_t *v = pkgconf_variable_new("prefix");
+
+ TEST_ASSERT_NONNULL(v);
+ TEST_ASSERT_STRCMP_EQ(v->key, "prefix");
+
+ pkgconf_variable_free(v);
+}
+
+static void
+test_variable_get_or_create_creates(void)
+{
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "prefix");
+ TEST_ASSERT_NONNULL(v);
+ TEST_ASSERT_STRCMP_EQ(v->key, "prefix");
+
+ pkgconf_variable_list_free(&vars);
+}
+
+static void
+test_variable_get_or_create_returns_existing(void)
+{
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_variable_t *first = pkgconf_variable_get_or_create(&vars, "libdir");
+ TEST_ASSERT_NONNULL(first);
+
+ // A second call with the same key should return the same object, not create a duplicate.
+ pkgconf_variable_t *second = pkgconf_variable_get_or_create(&vars, "libdir");
+ TEST_ASSERT_NONNULL(second);
+ TEST_ASSERT_EQ(first, second);
+
+ pkgconf_variable_list_free(&vars);
+}
+
+static void
+test_variable_find_present(void)
+{
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_variable_t *created = pkgconf_variable_get_or_create(&vars, "prefix");
+ TEST_ASSERT_NONNULL(created);
+
+ pkgconf_variable_t *found = pkgconf_variable_find(&vars, "prefix");
+ TEST_ASSERT_NONNULL(found);
+ TEST_ASSERT_EQ(created, found);
+
+ pkgconf_variable_list_free(&vars);
+}
+
+static void
+test_variable_find_absent(void)
+{
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_variable_t *found = pkgconf_variable_find(&vars, "nonexistent");
+ TEST_ASSERT_NULL(found);
+
+ pkgconf_variable_list_free(&vars);
+}
+
+static void
+test_variable_find_among_many(void)
+{
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_variable_get_or_create(&vars, "prefix");
+ pkgconf_variable_get_or_create(&vars, "exec_prefix");
+ pkgconf_variable_get_or_create(&vars, "libdir");
+ pkgconf_variable_get_or_create(&vars, "includedir");
+
+ TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "prefix"));
+ TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "exec_prefix"));
+ TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "libdir"));
+ TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "includedir"));
+ TEST_ASSERT_NULL(pkgconf_variable_find(&vars, "notpresent"));
+
+ pkgconf_variable_list_free(&vars);
+}
+
+static void
+test_variable_delete(void)
+{
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "prefix");
+ TEST_ASSERT_NONNULL(v);
+ TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "prefix"));
+
+ pkgconf_variable_delete(&vars, v);
+ TEST_ASSERT_NULL(pkgconf_variable_find(&vars, "prefix"));
+
+ pkgconf_variable_list_free(&vars);
+}
+
+static void
+test_variable_eval_str_plain(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+ bool saw_sysroot = false;
+
+ seed_variable(&vars, "version", "1.2.3");
+
+ pkgconf_variable_t *v = pkgconf_variable_find(&vars, "version");
+ TEST_ASSERT_NONNULL(v);
+
+ char *out = pkgconf_variable_eval_str(client, &vars, v, &saw_sysroot);
+ TEST_ASSERT_NONNULL(out);
+ TEST_ASSERT_STRCMP_EQ(out, "1.2.3");
+
+ free(out);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_variable_eval_str_with_reference(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+ bool saw_sysroot = false;
+
+ // Standard pkg-config layout: libdir is derived from prefix.
+ seed_variable(&vars, "prefix", "/opt/foo");
+ seed_variable(&vars, "libdir", "${prefix}/lib");
+
+ pkgconf_variable_t *libdir = pkgconf_variable_find(&vars, "libdir");
+ TEST_ASSERT_NONNULL(libdir);
+
+ char *out = pkgconf_variable_eval_str(client, &vars, libdir, &saw_sysroot);
+ TEST_ASSERT_NONNULL(out);
+ TEST_ASSERT_STRCMP_EQ(out, "/opt/foo/lib");
+
+ free(out);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_variable_eval_str_chained(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+ bool saw_sysroot = false;
+
+ seed_variable(&vars, "prefix", "/usr/local");
+ seed_variable(&vars, "exec_prefix", "${prefix}");
+ seed_variable(&vars, "includedir", "${exec_prefix}/include");
+
+ pkgconf_variable_t *includedir = pkgconf_variable_find(&vars, "includedir");
+ TEST_ASSERT_NONNULL(includedir);
+
+ char *out = pkgconf_variable_eval_str(client, &vars, includedir, &saw_sysroot);
+ TEST_ASSERT_NONNULL(out);
+ TEST_ASSERT_STRCMP_EQ(out, "/usr/local/include");
+
+ free(out);
+ pkgconf_variable_list_free(&vars);
+ pkgconf_client_free(client);
+}
+
+static void
+test_variable_list_free_handles_empty(void)
+{
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ // Freeing an empty list should be a no-op and not crash. Mostly an ASan/leak smoke test.
+ pkgconf_variable_list_free(&vars);
+}
+
+static void
+test_variable_list_free_handles_many(void)
+{
+ pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
+
+ /* Add a mix of bare and value-carrying variables, then free the whole list at once.
+ * Mostly an ASan/leak smoke test. */
+ pkgconf_variable_get_or_create(&vars, "a");
+ seed_variable(&vars, "b", "/path/b");
+ pkgconf_variable_get_or_create(&vars, "c");
+ seed_variable(&vars, "d", "${b}/sub");
+
+ pkgconf_variable_list_free(&vars);
+}
+
+int
+main(int argc, char *argv[])
+{
+ (void) argc;
+ const char *basename = pkgconf_path_find_basename(argv[0]);
+
+ TEST_RUN(basename, test_variable_new_and_free);
+ TEST_RUN(basename, test_variable_get_or_create_creates);
+ TEST_RUN(basename, test_variable_get_or_create_returns_existing);
+ TEST_RUN(basename, test_variable_find_present);
+ TEST_RUN(basename, test_variable_find_absent);
+ TEST_RUN(basename, test_variable_find_among_many);
+ TEST_RUN(basename, test_variable_delete);
+ TEST_RUN(basename, test_variable_eval_str_plain);
+ TEST_RUN(basename, test_variable_eval_str_with_reference);
+ TEST_RUN(basename, test_variable_eval_str_chained);
+ TEST_RUN(basename, test_variable_list_free_handles_empty);
+ TEST_RUN(basename, test_variable_list_free_handles_many);
+
+ return EXIT_SUCCESS;
+}