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