1*592efe25SPierre Pronchery /*
2*592efe25SPierre Pronchery * test-client.c
3*592efe25SPierre Pronchery * Tests for the public libpkgconf client API.
4*592efe25SPierre Pronchery *
5*592efe25SPierre Pronchery * SPDX-License-Identifier: pkgconf
6*592efe25SPierre Pronchery *
7*592efe25SPierre Pronchery * Copyright (c) 2026 pkgconf authors (see AUTHORS).
8*592efe25SPierre Pronchery *
9*592efe25SPierre Pronchery * Permission to use, copy, modify, and/or distribute this software for any
10*592efe25SPierre Pronchery * purpose with or without fee is hereby granted, provided that the above
11*592efe25SPierre Pronchery * copyright notice and this permission notice appear in all copies.
12*592efe25SPierre Pronchery *
13*592efe25SPierre Pronchery * This software is provided 'as is' and without any warranty, express or
14*592efe25SPierre Pronchery * implied. In no event shall the authors be liable for any damages arising
15*592efe25SPierre Pronchery * from the use of this software.
16*592efe25SPierre Pronchery */
17*592efe25SPierre Pronchery
18*592efe25SPierre Pronchery #include "test-api.h"
19*592efe25SPierre Pronchery
20*592efe25SPierre Pronchery static void
test_client_new_and_free(void)21*592efe25SPierre Pronchery test_client_new_and_free(void)
22*592efe25SPierre Pronchery {
23*592efe25SPierre Pronchery pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
24*592efe25SPierre Pronchery pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL);
25*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(client);
26*592efe25SPierre Pronchery
27*592efe25SPierre Pronchery pkgconf_client_free(client);
28*592efe25SPierre Pronchery }
29*592efe25SPierre Pronchery
30*592efe25SPierre Pronchery static void
test_client_init_and_deinit_stack(void)31*592efe25SPierre Pronchery test_client_init_and_deinit_stack(void)
32*592efe25SPierre Pronchery {
33*592efe25SPierre Pronchery /* Caller-allocated client, the path the CLI itself uses
34*592efe25SPierre Pronchery * (pkgconf_cli_state_t embeds a pkgconf_client_t by value) */
35*592efe25SPierre Pronchery pkgconf_client_t client = { 0 };
36*592efe25SPierre Pronchery pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
37*592efe25SPierre Pronchery
38*592efe25SPierre Pronchery pkgconf_client_init(&client, NULL, NULL, pers, NULL, NULL);
39*592efe25SPierre Pronchery pkgconf_client_deinit(&client);
40*592efe25SPierre Pronchery }
41*592efe25SPierre Pronchery
42*592efe25SPierre Pronchery static void
test_client_sysroot_dir(void)43*592efe25SPierre Pronchery test_client_sysroot_dir(void)
44*592efe25SPierre Pronchery {
45*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
46*592efe25SPierre Pronchery
47*592efe25SPierre Pronchery pkgconf_client_set_sysroot_dir(client, "/tmp/sysroot");
48*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_sysroot_dir(client), "/tmp/sysroot");
49*592efe25SPierre Pronchery
50*592efe25SPierre Pronchery pkgconf_client_set_sysroot_dir(client, "/opt/sysroot");
51*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_sysroot_dir(client), "/opt/sysroot");
52*592efe25SPierre Pronchery
53*592efe25SPierre Pronchery pkgconf_client_free(client);
54*592efe25SPierre Pronchery }
55*592efe25SPierre Pronchery
56*592efe25SPierre Pronchery static void
test_client_buildroot_dir(void)57*592efe25SPierre Pronchery test_client_buildroot_dir(void)
58*592efe25SPierre Pronchery {
59*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
60*592efe25SPierre Pronchery
61*592efe25SPierre Pronchery pkgconf_client_set_buildroot_dir(client, "/tmp/buildroot");
62*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_buildroot_dir(client), "/tmp/buildroot");
63*592efe25SPierre Pronchery
64*592efe25SPierre Pronchery pkgconf_client_free(client);
65*592efe25SPierre Pronchery }
66*592efe25SPierre Pronchery
67*592efe25SPierre Pronchery static void
test_client_flags(void)68*592efe25SPierre Pronchery test_client_flags(void)
69*592efe25SPierre Pronchery {
70*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
71*592efe25SPierre Pronchery
72*592efe25SPierre Pronchery pkgconf_client_set_flags(client, PKGCONF_PKG_PKGF_NO_CACHE | PKGCONF_PKG_PKGF_SKIP_CONFLICTS);
73*592efe25SPierre Pronchery
74*592efe25SPierre Pronchery unsigned int flags = pkgconf_client_get_flags(client);
75*592efe25SPierre Pronchery TEST_ASSERT_NE(flags & PKGCONF_PKG_PKGF_NO_CACHE, 0);
76*592efe25SPierre Pronchery TEST_ASSERT_NE(flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS, 0);
77*592efe25SPierre Pronchery TEST_ASSERT_EQ(flags & PKGCONF_PKG_PKGF_ENV_ONLY, 0);
78*592efe25SPierre Pronchery
79*592efe25SPierre Pronchery pkgconf_client_free(client);
80*592efe25SPierre Pronchery }
81*592efe25SPierre Pronchery
82*592efe25SPierre Pronchery static void
test_client_prefix_varname(void)83*592efe25SPierre Pronchery test_client_prefix_varname(void)
84*592efe25SPierre Pronchery {
85*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
86*592efe25SPierre Pronchery
87*592efe25SPierre Pronchery pkgconf_client_set_prefix_varname(client, "prefix");
88*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_prefix_varname(client), "prefix");
89*592efe25SPierre Pronchery
90*592efe25SPierre Pronchery pkgconf_client_set_prefix_varname(client, "custom_prefix");
91*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(pkgconf_client_get_prefix_varname(client), "custom_prefix");
92*592efe25SPierre Pronchery
93*592efe25SPierre Pronchery pkgconf_client_free(client);
94*592efe25SPierre Pronchery }
95*592efe25SPierre Pronchery
96*592efe25SPierre Pronchery /*
97*592efe25SPierre Pronchery * Capture buffer for handler tests. Each handler writes the message
98*592efe25SPierre Pronchery * into this buffer so the test can verify it fired with the expected
99*592efe25SPierre Pronchery * content. Reset before each test that uses it.
100*592efe25SPierre Pronchery */
101*592efe25SPierre Pronchery static char capture_buf[256];
102*592efe25SPierre Pronchery
103*592efe25SPierre Pronchery static bool
capture_handler(const char * msg,const pkgconf_client_t * client,void * data)104*592efe25SPierre Pronchery capture_handler(const char *msg, const pkgconf_client_t *client, void *data)
105*592efe25SPierre Pronchery {
106*592efe25SPierre Pronchery (void) client;
107*592efe25SPierre Pronchery (void) data;
108*592efe25SPierre Pronchery
109*592efe25SPierre Pronchery strncpy(capture_buf, msg, sizeof(capture_buf) - 1);
110*592efe25SPierre Pronchery capture_buf[sizeof(capture_buf) - 1] = '\0';
111*592efe25SPierre Pronchery return true;
112*592efe25SPierre Pronchery }
113*592efe25SPierre Pronchery
114*592efe25SPierre Pronchery static void
capture_reset(void)115*592efe25SPierre Pronchery capture_reset(void)
116*592efe25SPierre Pronchery {
117*592efe25SPierre Pronchery memset(capture_buf, 0, sizeof(capture_buf));
118*592efe25SPierre Pronchery }
119*592efe25SPierre Pronchery
120*592efe25SPierre Pronchery static void
test_client_error_handler_fires(void)121*592efe25SPierre Pronchery test_client_error_handler_fires(void)
122*592efe25SPierre Pronchery {
123*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
124*592efe25SPierre Pronchery capture_reset();
125*592efe25SPierre Pronchery
126*592efe25SPierre Pronchery pkgconf_client_set_error_handler(client, capture_handler, NULL);
127*592efe25SPierre Pronchery
128*592efe25SPierre Pronchery TEST_ASSERT_EQ(pkgconf_client_get_error_handler(client), capture_handler);
129*592efe25SPierre Pronchery
130*592efe25SPierre Pronchery pkgconf_error(client, "test error: %d", 42);
131*592efe25SPierre Pronchery
132*592efe25SPierre Pronchery TEST_ASSERT_NE(capture_buf[0], '\0');
133*592efe25SPierre Pronchery TEST_ASSERT_STRSTR(capture_buf, "test error: 42");
134*592efe25SPierre Pronchery
135*592efe25SPierre Pronchery pkgconf_client_free(client);
136*592efe25SPierre Pronchery }
137*592efe25SPierre Pronchery
138*592efe25SPierre Pronchery static void
test_client_warn_handler_fires(void)139*592efe25SPierre Pronchery test_client_warn_handler_fires(void)
140*592efe25SPierre Pronchery {
141*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
142*592efe25SPierre Pronchery capture_reset();
143*592efe25SPierre Pronchery
144*592efe25SPierre Pronchery pkgconf_client_set_warn_handler(client, capture_handler, NULL);
145*592efe25SPierre Pronchery
146*592efe25SPierre Pronchery TEST_ASSERT_EQ(pkgconf_client_get_warn_handler(client), capture_handler);
147*592efe25SPierre Pronchery
148*592efe25SPierre Pronchery pkgconf_warn(client, "test warning: %s", "hello");
149*592efe25SPierre Pronchery
150*592efe25SPierre Pronchery TEST_ASSERT_NE(capture_buf[0], '\0');
151*592efe25SPierre Pronchery TEST_ASSERT_STRSTR(capture_buf, "test warning: hello");
152*592efe25SPierre Pronchery
153*592efe25SPierre Pronchery pkgconf_client_free(client);
154*592efe25SPierre Pronchery }
155*592efe25SPierre Pronchery
156*592efe25SPierre Pronchery #ifndef PKGCONF_LITE
157*592efe25SPierre Pronchery static void
test_client_trace_handler_fires(void)158*592efe25SPierre Pronchery test_client_trace_handler_fires(void)
159*592efe25SPierre Pronchery {
160*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
161*592efe25SPierre Pronchery capture_reset();
162*592efe25SPierre Pronchery
163*592efe25SPierre Pronchery pkgconf_client_set_trace_handler(client, capture_handler, NULL);
164*592efe25SPierre Pronchery
165*592efe25SPierre Pronchery TEST_ASSERT_EQ(pkgconf_client_get_trace_handler(client), capture_handler);
166*592efe25SPierre Pronchery
167*592efe25SPierre Pronchery PKGCONF_TRACE(client, "trace message: %d", 7);
168*592efe25SPierre Pronchery
169*592efe25SPierre Pronchery TEST_ASSERT_NE(capture_buf[0], '\0');
170*592efe25SPierre Pronchery TEST_ASSERT_STRSTR(capture_buf, "trace message: 7");
171*592efe25SPierre Pronchery
172*592efe25SPierre Pronchery pkgconf_client_free(client);
173*592efe25SPierre Pronchery }
174*592efe25SPierre Pronchery #endif
175*592efe25SPierre Pronchery
176*592efe25SPierre Pronchery static void
unveil_capture_handler(const pkgconf_client_t * client,const char * path,const char * permissions)177*592efe25SPierre Pronchery unveil_capture_handler(const pkgconf_client_t *client, const char *path, const char *permissions)
178*592efe25SPierre Pronchery {
179*592efe25SPierre Pronchery (void) client;
180*592efe25SPierre Pronchery (void) permissions;
181*592efe25SPierre Pronchery
182*592efe25SPierre Pronchery if (path != NULL)
183*592efe25SPierre Pronchery {
184*592efe25SPierre Pronchery strncpy(capture_buf, path, sizeof(capture_buf) - 1);
185*592efe25SPierre Pronchery capture_buf[sizeof(capture_buf) - 1] = '\0';
186*592efe25SPierre Pronchery }
187*592efe25SPierre Pronchery }
188*592efe25SPierre Pronchery
189*592efe25SPierre Pronchery static void
test_client_unveil_handler_installation(void)190*592efe25SPierre Pronchery test_client_unveil_handler_installation(void)
191*592efe25SPierre Pronchery {
192*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
193*592efe25SPierre Pronchery
194*592efe25SPierre Pronchery pkgconf_client_set_unveil_handler(client, unveil_capture_handler);
195*592efe25SPierre Pronchery TEST_ASSERT_EQ(pkgconf_client_get_unveil_handler(client), unveil_capture_handler);
196*592efe25SPierre Pronchery
197*592efe25SPierre Pronchery pkgconf_client_free(client);
198*592efe25SPierre Pronchery }
199*592efe25SPierre Pronchery
200*592efe25SPierre Pronchery /*
201*592efe25SPierre Pronchery * Custom environ handler that returns canned values for known keys
202*592efe25SPierre Pronchery * and NULL otherwise.
203*592efe25SPierre Pronchery */
204*592efe25SPierre Pronchery static const char *
canned_environ_handler(const pkgconf_client_t * client,const char * key)205*592efe25SPierre Pronchery canned_environ_handler(const pkgconf_client_t *client, const char *key)
206*592efe25SPierre Pronchery {
207*592efe25SPierre Pronchery (void) client;
208*592efe25SPierre Pronchery
209*592efe25SPierre Pronchery if (!strcmp(key, "PKG_TEST_VAR"))
210*592efe25SPierre Pronchery return "the_value";
211*592efe25SPierre Pronchery if (!strcmp(key, "EMPTY_VAR"))
212*592efe25SPierre Pronchery return "";
213*592efe25SPierre Pronchery if (!strcmp(key, "PKG_CONFIG_SYSTEM_INCLUDE_PATH"))
214*592efe25SPierre Pronchery return "/custom/include";
215*592efe25SPierre Pronchery if (!strcmp(key, "PKG_CONFIG_SYSTEM_LIBRARY_PATH"))
216*592efe25SPierre Pronchery return "/custom/lib";
217*592efe25SPierre Pronchery
218*592efe25SPierre Pronchery return NULL;
219*592efe25SPierre Pronchery }
220*592efe25SPierre Pronchery
221*592efe25SPierre Pronchery static void
test_client_getenv_via_handler(void)222*592efe25SPierre Pronchery test_client_getenv_via_handler(void)
223*592efe25SPierre Pronchery {
224*592efe25SPierre Pronchery pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
225*592efe25SPierre Pronchery pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, canned_environ_handler);
226*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(client);
227*592efe25SPierre Pronchery
228*592efe25SPierre Pronchery const char *v = pkgconf_client_getenv(client, "PKG_TEST_VAR");
229*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(v);
230*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(v, "the_value");
231*592efe25SPierre Pronchery
232*592efe25SPierre Pronchery v = pkgconf_client_getenv(client, "EMPTY_VAR");
233*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(v);
234*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(v, "");
235*592efe25SPierre Pronchery
236*592efe25SPierre Pronchery v = pkgconf_client_getenv(client, "UNDEFINED_VAR");
237*592efe25SPierre Pronchery TEST_ASSERT_NULL(v);
238*592efe25SPierre Pronchery
239*592efe25SPierre Pronchery pkgconf_client_free(client);
240*592efe25SPierre Pronchery }
241*592efe25SPierre Pronchery
242*592efe25SPierre Pronchery static void
test_client_dir_list_build_smoke(void)243*592efe25SPierre Pronchery test_client_dir_list_build_smoke(void)
244*592efe25SPierre Pronchery {
245*592efe25SPierre Pronchery pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
246*592efe25SPierre Pronchery pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL);
247*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(client);
248*592efe25SPierre Pronchery
249*592efe25SPierre Pronchery pkgconf_client_dir_list_build(client, pers);
250*592efe25SPierre Pronchery
251*592efe25SPierre Pronchery /* The personality's default dir list comes from PKG_DEFAULT_PATH
252*592efe25SPierre Pronchery * (set at compile time). After build, the client should have
253*592efe25SPierre Pronchery * SOME directories registered; we don't assert specific paths
254*592efe25SPierre Pronchery * since they vary by build configuration. */
255*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(client->dir_list.head);
256*592efe25SPierre Pronchery
257*592efe25SPierre Pronchery pkgconf_client_free(client);
258*592efe25SPierre Pronchery }
259*592efe25SPierre Pronchery
260*592efe25SPierre Pronchery static void
test_client_init_system_paths_from_environ(void)261*592efe25SPierre Pronchery test_client_init_system_paths_from_environ(void)
262*592efe25SPierre Pronchery {
263*592efe25SPierre Pronchery pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
264*592efe25SPierre Pronchery pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, canned_environ_handler);
265*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(client);
266*592efe25SPierre Pronchery
267*592efe25SPierre Pronchery /* With PKG_CONFIG_SYSTEM_{INCLUDE,LIBRARY}_PATH set, init builds the filter dirs from the
268*592efe25SPierre Pronchery * environment instead of copying the personality's defaults. */
269*592efe25SPierre Pronchery TEST_ASSERT_TRUE(pkgconf_path_match_list("/custom/include", &client->filter_includedirs));
270*592efe25SPierre Pronchery TEST_ASSERT_TRUE(pkgconf_path_match_list("/custom/lib", &client->filter_libdirs));
271*592efe25SPierre Pronchery
272*592efe25SPierre Pronchery pkgconf_client_free(client);
273*592efe25SPierre Pronchery }
274*592efe25SPierre Pronchery
275*592efe25SPierre Pronchery static void
test_client_preload_from_environ(void)276*592efe25SPierre Pronchery test_client_preload_from_environ(void)
277*592efe25SPierre Pronchery {
278*592efe25SPierre Pronchery pkgconf_cross_personality_t *pers = pkgconf_cross_personality_default();
279*592efe25SPierre Pronchery pkgconf_client_t *client = pkgconf_client_new(NULL, NULL, pers, NULL, NULL);
280*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(client);
281*592efe25SPierre Pronchery
282*592efe25SPierre Pronchery /* preload_from_environ reads the named var via getenv directly.
283*592efe25SPierre Pronchery * Point it at a dir; preload_path will try to load .pc files from there.
284*592efe25SPierre Pronchery * An empty/nonexistent dir is fine; we're exercising the split-and-iterate path, not asserting
285*592efe25SPierre Pronchery * loads. */
286*592efe25SPierre Pronchery setenv("PKG_TEST_PRELOAD", "/nonexistent/dir", 1);
287*592efe25SPierre Pronchery
288*592efe25SPierre Pronchery pkgconf_client_preload_from_environ(client, "PKG_TEST_PRELOAD");
289*592efe25SPierre Pronchery
290*592efe25SPierre Pronchery unsetenv("PKG_TEST_PRELOAD");
291*592efe25SPierre Pronchery pkgconf_client_free(client);
292*592efe25SPierre Pronchery }
293*592efe25SPierre Pronchery
294*592efe25SPierre Pronchery #ifndef PKGCONF_LITE
295*592efe25SPierre Pronchery static void
test_client_trace_null_client(void)296*592efe25SPierre Pronchery test_client_trace_null_client(void)
297*592efe25SPierre Pronchery {
298*592efe25SPierre Pronchery TEST_ASSERT_FALSE(pkgconf_trace(NULL, "test.c", 42, "func", "msg %d", 42));
299*592efe25SPierre Pronchery }
300*592efe25SPierre Pronchery #endif
301*592efe25SPierre Pronchery
302*592efe25SPierre Pronchery int
main(int argc,char * argv[])303*592efe25SPierre Pronchery main(int argc, char *argv[])
304*592efe25SPierre Pronchery {
305*592efe25SPierre Pronchery (void) argc;
306*592efe25SPierre Pronchery const char *basename = pkgconf_path_find_basename(argv[0]);
307*592efe25SPierre Pronchery
308*592efe25SPierre Pronchery TEST_RUN(basename, test_client_new_and_free);
309*592efe25SPierre Pronchery TEST_RUN(basename, test_client_init_and_deinit_stack);
310*592efe25SPierre Pronchery TEST_RUN(basename, test_client_init_system_paths_from_environ);
311*592efe25SPierre Pronchery TEST_RUN(basename, test_client_preload_from_environ);
312*592efe25SPierre Pronchery
313*592efe25SPierre Pronchery TEST_RUN(basename, test_client_sysroot_dir);
314*592efe25SPierre Pronchery TEST_RUN(basename, test_client_buildroot_dir);
315*592efe25SPierre Pronchery TEST_RUN(basename, test_client_flags);
316*592efe25SPierre Pronchery TEST_RUN(basename, test_client_prefix_varname);
317*592efe25SPierre Pronchery
318*592efe25SPierre Pronchery TEST_RUN(basename, test_client_error_handler_fires);
319*592efe25SPierre Pronchery TEST_RUN(basename, test_client_warn_handler_fires);
320*592efe25SPierre Pronchery #ifndef PKGCONF_LITE
321*592efe25SPierre Pronchery TEST_RUN(basename, test_client_trace_handler_fires);
322*592efe25SPierre Pronchery #endif
323*592efe25SPierre Pronchery TEST_RUN(basename, test_client_unveil_handler_installation);
324*592efe25SPierre Pronchery
325*592efe25SPierre Pronchery TEST_RUN(basename, test_client_getenv_via_handler);
326*592efe25SPierre Pronchery
327*592efe25SPierre Pronchery TEST_RUN(basename, test_client_dir_list_build_smoke);
328*592efe25SPierre Pronchery
329*592efe25SPierre Pronchery #ifndef PKGCONF_LITE
330*592efe25SPierre Pronchery TEST_RUN(basename, test_client_trace_null_client);
331*592efe25SPierre Pronchery #endif
332*592efe25SPierre Pronchery
333*592efe25SPierre Pronchery return EXIT_SUCCESS;
334*592efe25SPierre Pronchery }
335