aboutsummaryrefslogtreecommitdiff
path: root/tests/api/test-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/api/test-client.c')
-rw-r--r--tests/api/test-client.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/tests/api/test-client.c b/tests/api/test-client.c
new file mode 100644
index 000000000000..ae8889b658c8
--- /dev/null
+++ b/tests/api/test-client.c
@@ -0,0 +1,334 @@
+/*
+ * test-client.c
+ * Tests for the public libpkgconf client 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 void
+test_client_new_and_free(void)
+{
+ pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
+ pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL);
+ TEST_ASSERT_NONNULL(client);
+
+ pkgconf_client_free(client);
+}
+
+static void
+test_client_init_and_deinit_stack(void)
+{
+ /* Caller-allocated client, the path the CLI itself uses
+ * (pkgconf_cli_state_t embeds a pkgconf_client_t by value) */
+ pkgconf_client_t client = { 0 };
+ pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
+
+ pkgconf_client_init(&client, NULL, NULL, pers, NULL, NULL);
+ pkgconf_client_deinit(&client);
+}
+
+static void
+test_client_sysroot_dir(void)
+{
+ pkgconf_client_t *client = test_client_new();
+
+ pkgconf_client_set_sysroot_dir(client, "/tmp/sysroot");
+ TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_sysroot_dir(client), "/tmp/sysroot");
+
+ pkgconf_client_set_sysroot_dir(client, "/opt/sysroot");
+ TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_sysroot_dir(client), "/opt/sysroot");
+
+ pkgconf_client_free(client);
+}
+
+static void
+test_client_buildroot_dir(void)
+{
+ pkgconf_client_t *client = test_client_new();
+
+ pkgconf_client_set_buildroot_dir(client, "/tmp/buildroot");
+ TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_buildroot_dir(client), "/tmp/buildroot");
+
+ pkgconf_client_free(client);
+}
+
+static void
+test_client_flags(void)
+{
+ pkgconf_client_t *client = test_client_new();
+
+ pkgconf_client_set_flags(client, PKGCONF_PKG_PKGF_NO_CACHE | PKGCONF_PKG_PKGF_SKIP_CONFLICTS);
+
+ unsigned int flags = pkgconf_client_get_flags(client);
+ TEST_ASSERT_NE(flags & PKGCONF_PKG_PKGF_NO_CACHE, 0);
+ TEST_ASSERT_NE(flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS, 0);
+ TEST_ASSERT_EQ(flags & PKGCONF_PKG_PKGF_ENV_ONLY, 0);
+
+ pkgconf_client_free(client);
+}
+
+static void
+test_client_prefix_varname(void)
+{
+ pkgconf_client_t *client = test_client_new();
+
+ pkgconf_client_set_prefix_varname(client, "prefix");
+ TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_prefix_varname(client), "prefix");
+
+ pkgconf_client_set_prefix_varname(client, "custom_prefix");
+ TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_prefix_varname(client), "custom_prefix");
+
+ pkgconf_client_free(client);
+}
+
+/*
+ * Capture buffer for handler tests. Each handler writes the message
+ * into this buffer so the test can verify it fired with the expected
+ * content. Reset before each test that uses it.
+ */
+static char capture_buf[256];
+
+static bool
+capture_handler(const char *msg, const pkgconf_client_t *client, void *data)
+{
+ (void) client;
+ (void) data;
+
+ strncpy(capture_buf, msg, sizeof(capture_buf) - 1);
+ capture_buf[sizeof(capture_buf) - 1] = '\0';
+ return true;
+}
+
+static void
+capture_reset(void)
+{
+ memset(capture_buf, 0, sizeof(capture_buf));
+}
+
+static void
+test_client_error_handler_fires(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ capture_reset();
+
+ pkgconf_client_set_error_handler(client, capture_handler, NULL);
+
+ TEST_ASSERT_EQ(pkgconf_client_get_error_handler(client), capture_handler);
+
+ pkgconf_error(client, "test error: %d", 42);
+
+ TEST_ASSERT_NE(capture_buf[0], '\0');
+ TEST_ASSERT_STRSTR(capture_buf, "test error: 42");
+
+ pkgconf_client_free(client);
+}
+
+static void
+test_client_warn_handler_fires(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ capture_reset();
+
+ pkgconf_client_set_warn_handler(client, capture_handler, NULL);
+
+ TEST_ASSERT_EQ(pkgconf_client_get_warn_handler(client), capture_handler);
+
+ pkgconf_warn(client, "test warning: %s", "hello");
+
+ TEST_ASSERT_NE(capture_buf[0], '\0');
+ TEST_ASSERT_STRSTR(capture_buf, "test warning: hello");
+
+ pkgconf_client_free(client);
+}
+
+#ifndef PKGCONF_LITE
+static void
+test_client_trace_handler_fires(void)
+{
+ pkgconf_client_t *client = test_client_new();
+ capture_reset();
+
+ pkgconf_client_set_trace_handler(client, capture_handler, NULL);
+
+ TEST_ASSERT_EQ(pkgconf_client_get_trace_handler(client), capture_handler);
+
+ PKGCONF_TRACE(client, "trace message: %d", 7);
+
+ TEST_ASSERT_NE(capture_buf[0], '\0');
+ TEST_ASSERT_STRSTR(capture_buf, "trace message: 7");
+
+ pkgconf_client_free(client);
+}
+#endif
+
+static void
+unveil_capture_handler(const pkgconf_client_t *client, const char *path, const char *permissions)
+{
+ (void) client;
+ (void) permissions;
+
+ if (path != NULL)
+ {
+ strncpy(capture_buf, path, sizeof(capture_buf) - 1);
+ capture_buf[sizeof(capture_buf) - 1] = '\0';
+ }
+}
+
+static void
+test_client_unveil_handler_installation(void)
+{
+ pkgconf_client_t *client = test_client_new();
+
+ pkgconf_client_set_unveil_handler(client, unveil_capture_handler);
+ TEST_ASSERT_EQ(pkgconf_client_get_unveil_handler(client), unveil_capture_handler);
+
+ pkgconf_client_free(client);
+}
+
+/*
+ * Custom environ handler that returns canned values for known keys
+ * and NULL otherwise.
+ */
+static const char *
+canned_environ_handler(const pkgconf_client_t *client, const char *key)
+{
+ (void) client;
+
+ if (!strcmp(key, "PKG_TEST_VAR"))
+ return "the_value";
+ if (!strcmp(key, "EMPTY_VAR"))
+ return "";
+ if (!strcmp(key, "PKG_CONFIG_SYSTEM_INCLUDE_PATH"))
+ return "/custom/include";
+ if (!strcmp(key, "PKG_CONFIG_SYSTEM_LIBRARY_PATH"))
+ return "/custom/lib";
+
+ return NULL;
+}
+
+static void
+test_client_getenv_via_handler(void)
+{
+ pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
+ pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, canned_environ_handler);
+ TEST_ASSERT_NONNULL(client);
+
+ const char *v = pkgconf_client_getenv(client, "PKG_TEST_VAR");
+ TEST_ASSERT_NONNULL(v);
+ TEST_ASSERT_STRCMP_EQ(v, "the_value");
+
+ v = pkgconf_client_getenv(client, "EMPTY_VAR");
+ TEST_ASSERT_NONNULL(v);
+ TEST_ASSERT_STRCMP_EQ(v, "");
+
+ v = pkgconf_client_getenv(client, "UNDEFINED_VAR");
+ TEST_ASSERT_NULL(v);
+
+ pkgconf_client_free(client);
+}
+
+static void
+test_client_dir_list_build_smoke(void)
+{
+ pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
+ pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL);
+ TEST_ASSERT_NONNULL(client);
+
+ pkgconf_client_dir_list_build(client, pers);
+
+ /* The personality's default dir list comes from PKG_DEFAULT_PATH
+ * (set at compile time). After build, the client should have
+ * SOME directories registered; we don't assert specific paths
+ * since they vary by build configuration. */
+ TEST_ASSERT_NONNULL(client->dir_list.head);
+
+ pkgconf_client_free(client);
+}
+
+static void
+test_client_init_system_paths_from_environ(void)
+{
+ pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
+ pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, canned_environ_handler);
+ TEST_ASSERT_NONNULL(client);
+
+ /* With PKG_CONFIG_SYSTEM_{INCLUDE,LIBRARY}_PATH set, init builds the filter dirs from the
+ * environment instead of copying the personality's defaults. */
+ TEST_ASSERT_TRUE(pkgconf_path_match_list("/custom/include", &client->filter_includedirs));
+ TEST_ASSERT_TRUE(pkgconf_path_match_list("/custom/lib", &client->filter_libdirs));
+
+ pkgconf_client_free(client);
+}
+
+static void
+test_client_preload_from_environ(void)
+{
+ pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
+ pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL);
+ TEST_ASSERT_NONNULL(client);
+
+ /* preload_from_environ reads the named var via getenv directly.
+ * Point it at a dir; preload_path will try to load .pc files from there.
+ * An empty/nonexistent dir is fine; we're exercising the split-and-iterate path, not asserting
+ * loads. */
+ setenv("PKG_TEST_PRELOAD", "/nonexistent/dir", 1);
+
+ pkgconf_client_preload_from_environ(client, "PKG_TEST_PRELOAD");
+
+ unsetenv("PKG_TEST_PRELOAD");
+ pkgconf_client_free(client);
+}
+
+#ifndef PKGCONF_LITE
+static void
+test_client_trace_null_client(void)
+{
+ TEST_ASSERT_FALSE(pkgconf_trace(NULL, "test.c", 42, "func", "msg %d", 42));
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ (void) argc;
+ const char *basename = pkgconf_path_find_basename(argv[0]);
+
+ TEST_RUN(basename, test_client_new_and_free);
+ TEST_RUN(basename, test_client_init_and_deinit_stack);
+ TEST_RUN(basename, test_client_init_system_paths_from_environ);
+ TEST_RUN(basename, test_client_preload_from_environ);
+
+ TEST_RUN(basename, test_client_sysroot_dir);
+ TEST_RUN(basename, test_client_buildroot_dir);
+ TEST_RUN(basename, test_client_flags);
+ TEST_RUN(basename, test_client_prefix_varname);
+
+ TEST_RUN(basename, test_client_error_handler_fires);
+ TEST_RUN(basename, test_client_warn_handler_fires);
+#ifndef PKGCONF_LITE
+ TEST_RUN(basename, test_client_trace_handler_fires);
+#endif
+ TEST_RUN(basename, test_client_unveil_handler_installation);
+
+ TEST_RUN(basename, test_client_getenv_via_handler);
+
+ TEST_RUN(basename, test_client_dir_list_build_smoke);
+
+#ifndef PKGCONF_LITE
+ TEST_RUN(basename, test_client_trace_null_client);
+#endif
+
+ return EXIT_SUCCESS;
+}