xref: /freebsd/contrib/pkgconf/tests/api/test-variable.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1*592efe25SPierre Pronchery /*
2*592efe25SPierre Pronchery  * test-variable.c
3*592efe25SPierre Pronchery  * Tests for the public libpkgconf variable API.
4*592efe25SPierre Pronchery  *
5*592efe25SPierre Pronchery  * SPDX-License-Identifier: pkgconf
6*592efe25SPierre Pronchery  *
7*592efe25SPierre Pronchery  * Copyright (c) 2025 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 <libpkgconf/stdinc.h>
19*592efe25SPierre Pronchery #include <libpkgconf/libpkgconf.h>
20*592efe25SPierre Pronchery #include "test-api.h"
21*592efe25SPierre Pronchery 
22*592efe25SPierre Pronchery /*
23*592efe25SPierre Pronchery  * Install a value on a variable by compiling it as bytecode.
24*592efe25SPierre Pronchery  * Mirrors what the parser does when it reads a .pc field.
25*592efe25SPierre Pronchery  */
26*592efe25SPierre Pronchery static void
seed_variable(pkgconf_list_t * vars,const char * key,const char * value)27*592efe25SPierre Pronchery seed_variable(pkgconf_list_t *vars, const char *key, const char *value)
28*592efe25SPierre Pronchery {
29*592efe25SPierre Pronchery 	pkgconf_variable_t *v = pkgconf_variable_get_or_create(vars, key);
30*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(v);
31*592efe25SPierre Pronchery 
32*592efe25SPierre Pronchery 	pkgconf_buffer_reset(&v->bcbuf);
33*592efe25SPierre Pronchery 	pkgconf_bytecode_compile(&v->bcbuf, value);
34*592efe25SPierre Pronchery 	pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf);
35*592efe25SPierre Pronchery }
36*592efe25SPierre Pronchery 
37*592efe25SPierre Pronchery static void
test_variable_new_and_free(void)38*592efe25SPierre Pronchery test_variable_new_and_free(void)
39*592efe25SPierre Pronchery {
40*592efe25SPierre Pronchery 	pkgconf_variable_t *v = pkgconf_variable_new("prefix");
41*592efe25SPierre Pronchery 
42*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(v);
43*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(v->key, "prefix");
44*592efe25SPierre Pronchery 
45*592efe25SPierre Pronchery 	pkgconf_variable_free(v);
46*592efe25SPierre Pronchery }
47*592efe25SPierre Pronchery 
48*592efe25SPierre Pronchery static void
test_variable_get_or_create_creates(void)49*592efe25SPierre Pronchery test_variable_get_or_create_creates(void)
50*592efe25SPierre Pronchery {
51*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
52*592efe25SPierre Pronchery 
53*592efe25SPierre Pronchery 	pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "prefix");
54*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(v);
55*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(v->key, "prefix");
56*592efe25SPierre Pronchery 
57*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
58*592efe25SPierre Pronchery }
59*592efe25SPierre Pronchery 
60*592efe25SPierre Pronchery static void
test_variable_get_or_create_returns_existing(void)61*592efe25SPierre Pronchery test_variable_get_or_create_returns_existing(void)
62*592efe25SPierre Pronchery {
63*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
64*592efe25SPierre Pronchery 
65*592efe25SPierre Pronchery 	pkgconf_variable_t *first = pkgconf_variable_get_or_create(&vars, "libdir");
66*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(first);
67*592efe25SPierre Pronchery 
68*592efe25SPierre Pronchery 	// A second call with the same key should return the same object, not create a duplicate.
69*592efe25SPierre Pronchery 	pkgconf_variable_t *second = pkgconf_variable_get_or_create(&vars, "libdir");
70*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(second);
71*592efe25SPierre Pronchery 	TEST_ASSERT_EQ(first, second);
72*592efe25SPierre Pronchery 
73*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
74*592efe25SPierre Pronchery }
75*592efe25SPierre Pronchery 
76*592efe25SPierre Pronchery static void
test_variable_find_present(void)77*592efe25SPierre Pronchery test_variable_find_present(void)
78*592efe25SPierre Pronchery {
79*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
80*592efe25SPierre Pronchery 
81*592efe25SPierre Pronchery 	pkgconf_variable_t *created = pkgconf_variable_get_or_create(&vars, "prefix");
82*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(created);
83*592efe25SPierre Pronchery 
84*592efe25SPierre Pronchery 	pkgconf_variable_t *found = pkgconf_variable_find(&vars, "prefix");
85*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(found);
86*592efe25SPierre Pronchery 	TEST_ASSERT_EQ(created, found);
87*592efe25SPierre Pronchery 
88*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
89*592efe25SPierre Pronchery }
90*592efe25SPierre Pronchery 
91*592efe25SPierre Pronchery static void
test_variable_find_absent(void)92*592efe25SPierre Pronchery test_variable_find_absent(void)
93*592efe25SPierre Pronchery {
94*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
95*592efe25SPierre Pronchery 
96*592efe25SPierre Pronchery 	pkgconf_variable_t *found = pkgconf_variable_find(&vars, "nonexistent");
97*592efe25SPierre Pronchery 	TEST_ASSERT_NULL(found);
98*592efe25SPierre Pronchery 
99*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
100*592efe25SPierre Pronchery }
101*592efe25SPierre Pronchery 
102*592efe25SPierre Pronchery static void
test_variable_find_among_many(void)103*592efe25SPierre Pronchery test_variable_find_among_many(void)
104*592efe25SPierre Pronchery {
105*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
106*592efe25SPierre Pronchery 
107*592efe25SPierre Pronchery 	pkgconf_variable_get_or_create(&vars, "prefix");
108*592efe25SPierre Pronchery 	pkgconf_variable_get_or_create(&vars, "exec_prefix");
109*592efe25SPierre Pronchery 	pkgconf_variable_get_or_create(&vars, "libdir");
110*592efe25SPierre Pronchery 	pkgconf_variable_get_or_create(&vars, "includedir");
111*592efe25SPierre Pronchery 
112*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "prefix"));
113*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "exec_prefix"));
114*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "libdir"));
115*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "includedir"));
116*592efe25SPierre Pronchery 	TEST_ASSERT_NULL(pkgconf_variable_find(&vars, "notpresent"));
117*592efe25SPierre Pronchery 
118*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
119*592efe25SPierre Pronchery }
120*592efe25SPierre Pronchery 
121*592efe25SPierre Pronchery static void
test_variable_delete(void)122*592efe25SPierre Pronchery test_variable_delete(void)
123*592efe25SPierre Pronchery {
124*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
125*592efe25SPierre Pronchery 
126*592efe25SPierre Pronchery 	pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "prefix");
127*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(v);
128*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(pkgconf_variable_find(&vars, "prefix"));
129*592efe25SPierre Pronchery 
130*592efe25SPierre Pronchery 	pkgconf_variable_delete(&vars, v);
131*592efe25SPierre Pronchery 	TEST_ASSERT_NULL(pkgconf_variable_find(&vars, "prefix"));
132*592efe25SPierre Pronchery 
133*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
134*592efe25SPierre Pronchery }
135*592efe25SPierre Pronchery 
136*592efe25SPierre Pronchery static void
test_variable_eval_str_plain(void)137*592efe25SPierre Pronchery test_variable_eval_str_plain(void)
138*592efe25SPierre Pronchery {
139*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
140*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
141*592efe25SPierre Pronchery 	bool saw_sysroot = false;
142*592efe25SPierre Pronchery 
143*592efe25SPierre Pronchery 	seed_variable(&vars, "version", "1.2.3");
144*592efe25SPierre Pronchery 
145*592efe25SPierre Pronchery 	pkgconf_variable_t *v = pkgconf_variable_find(&vars, "version");
146*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(v);
147*592efe25SPierre Pronchery 
148*592efe25SPierre Pronchery 	char *out = pkgconf_variable_eval_str(client, &vars, v, &saw_sysroot);
149*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(out);
150*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(out, "1.2.3");
151*592efe25SPierre Pronchery 
152*592efe25SPierre Pronchery 	free(out);
153*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
154*592efe25SPierre Pronchery 	pkgconf_client_free(client);
155*592efe25SPierre Pronchery }
156*592efe25SPierre Pronchery 
157*592efe25SPierre Pronchery static void
test_variable_eval_str_with_reference(void)158*592efe25SPierre Pronchery test_variable_eval_str_with_reference(void)
159*592efe25SPierre Pronchery {
160*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
161*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
162*592efe25SPierre Pronchery 	bool saw_sysroot = false;
163*592efe25SPierre Pronchery 
164*592efe25SPierre Pronchery 	// Standard pkg-config layout: libdir is derived from prefix.
165*592efe25SPierre Pronchery 	seed_variable(&vars, "prefix", "/opt/foo");
166*592efe25SPierre Pronchery 	seed_variable(&vars, "libdir", "${prefix}/lib");
167*592efe25SPierre Pronchery 
168*592efe25SPierre Pronchery 	pkgconf_variable_t *libdir = pkgconf_variable_find(&vars, "libdir");
169*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(libdir);
170*592efe25SPierre Pronchery 
171*592efe25SPierre Pronchery 	char *out = pkgconf_variable_eval_str(client, &vars, libdir, &saw_sysroot);
172*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(out);
173*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(out, "/opt/foo/lib");
174*592efe25SPierre Pronchery 
175*592efe25SPierre Pronchery 	free(out);
176*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
177*592efe25SPierre Pronchery 	pkgconf_client_free(client);
178*592efe25SPierre Pronchery }
179*592efe25SPierre Pronchery 
180*592efe25SPierre Pronchery static void
test_variable_eval_str_chained(void)181*592efe25SPierre Pronchery test_variable_eval_str_chained(void)
182*592efe25SPierre Pronchery {
183*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
184*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
185*592efe25SPierre Pronchery 	bool saw_sysroot = false;
186*592efe25SPierre Pronchery 
187*592efe25SPierre Pronchery 	seed_variable(&vars, "prefix", "/usr/local");
188*592efe25SPierre Pronchery 	seed_variable(&vars, "exec_prefix", "${prefix}");
189*592efe25SPierre Pronchery 	seed_variable(&vars, "includedir", "${exec_prefix}/include");
190*592efe25SPierre Pronchery 
191*592efe25SPierre Pronchery 	pkgconf_variable_t *includedir = pkgconf_variable_find(&vars, "includedir");
192*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(includedir);
193*592efe25SPierre Pronchery 
194*592efe25SPierre Pronchery 	char *out = pkgconf_variable_eval_str(client, &vars, includedir, &saw_sysroot);
195*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(out);
196*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(out, "/usr/local/include");
197*592efe25SPierre Pronchery 
198*592efe25SPierre Pronchery 	free(out);
199*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
200*592efe25SPierre Pronchery 	pkgconf_client_free(client);
201*592efe25SPierre Pronchery }
202*592efe25SPierre Pronchery 
203*592efe25SPierre Pronchery static void
test_variable_list_free_handles_empty(void)204*592efe25SPierre Pronchery test_variable_list_free_handles_empty(void)
205*592efe25SPierre Pronchery {
206*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
207*592efe25SPierre Pronchery 
208*592efe25SPierre Pronchery 	// Freeing an empty list should be a no-op and not crash. Mostly an ASan/leak smoke test.
209*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
210*592efe25SPierre Pronchery }
211*592efe25SPierre Pronchery 
212*592efe25SPierre Pronchery static void
test_variable_list_free_handles_many(void)213*592efe25SPierre Pronchery test_variable_list_free_handles_many(void)
214*592efe25SPierre Pronchery {
215*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
216*592efe25SPierre Pronchery 
217*592efe25SPierre Pronchery 	/* Add a mix of bare and value-carrying variables, then free the whole list at once.
218*592efe25SPierre Pronchery 	 * Mostly an ASan/leak smoke test. */
219*592efe25SPierre Pronchery 	pkgconf_variable_get_or_create(&vars, "a");
220*592efe25SPierre Pronchery 	seed_variable(&vars, "b", "/path/b");
221*592efe25SPierre Pronchery 	pkgconf_variable_get_or_create(&vars, "c");
222*592efe25SPierre Pronchery 	seed_variable(&vars, "d", "${b}/sub");
223*592efe25SPierre Pronchery 
224*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
225*592efe25SPierre Pronchery }
226*592efe25SPierre Pronchery 
227*592efe25SPierre Pronchery int
main(int argc,char * argv[])228*592efe25SPierre Pronchery main(int argc, char *argv[])
229*592efe25SPierre Pronchery {
230*592efe25SPierre Pronchery 	(void) argc;
231*592efe25SPierre Pronchery 	const char *basename = pkgconf_path_find_basename(argv[0]);
232*592efe25SPierre Pronchery 
233*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_new_and_free);
234*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_get_or_create_creates);
235*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_get_or_create_returns_existing);
236*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_find_present);
237*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_find_absent);
238*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_find_among_many);
239*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_delete);
240*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_eval_str_plain);
241*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_eval_str_with_reference);
242*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_eval_str_chained);
243*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_list_free_handles_empty);
244*592efe25SPierre Pronchery 	TEST_RUN(basename, test_variable_list_free_handles_many);
245*592efe25SPierre Pronchery 
246*592efe25SPierre Pronchery 	return EXIT_SUCCESS;
247*592efe25SPierre Pronchery }
248