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 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 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 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 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 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 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 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 115 capture_reset(void) 116 { 117 memset(capture_buf, 0, sizeof(capture_buf)); 118 } 119 120 static 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 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 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 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 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 * 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 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 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 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 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 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 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