xref: /freebsd/contrib/pkgconf/tests/api/test-tuple.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1*592efe25SPierre Pronchery /*
2*592efe25SPierre Pronchery  * test-tuple.c
3*592efe25SPierre Pronchery  * Tests for the public libpkgconf tuple 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 static void
test_tuple_add_and_find(void)23*592efe25SPierre Pronchery test_tuple_add_and_find(void)
24*592efe25SPierre Pronchery {
25*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
26*592efe25SPierre Pronchery 	pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER;
27*592efe25SPierre Pronchery 
28*592efe25SPierre Pronchery 	/* parse=false means store the value verbatim, no bytecode compile.
29*592efe25SPierre Pronchery 	 * That's the right mode for storing already-evaluated values. */
30*592efe25SPierre Pronchery 	pkgconf_tuple_t *t = pkgconf_tuple_add(client, &tuples, "prefix", "/opt/foo", false, 0);
31*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(t);
32*592efe25SPierre Pronchery 
33*592efe25SPierre Pronchery 	const char *found = pkgconf_tuple_find(client, &tuples, "prefix");
34*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(found);
35*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(found, "/opt/foo");
36*592efe25SPierre Pronchery 
37*592efe25SPierre Pronchery 	pkgconf_tuple_free(&tuples);
38*592efe25SPierre Pronchery 	pkgconf_client_free(client);
39*592efe25SPierre Pronchery }
40*592efe25SPierre Pronchery 
41*592efe25SPierre Pronchery static void
test_tuple_find_absent(void)42*592efe25SPierre Pronchery test_tuple_find_absent(void)
43*592efe25SPierre Pronchery {
44*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
45*592efe25SPierre Pronchery 	pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER;
46*592efe25SPierre Pronchery 
47*592efe25SPierre Pronchery 	const char *found = pkgconf_tuple_find(client, &tuples, "nonexistent");
48*592efe25SPierre Pronchery 	TEST_ASSERT_EMPTY_STRING(found);
49*592efe25SPierre Pronchery 
50*592efe25SPierre Pronchery 	pkgconf_tuple_free(&tuples);
51*592efe25SPierre Pronchery 	pkgconf_client_free(client);
52*592efe25SPierre Pronchery }
53*592efe25SPierre Pronchery 
54*592efe25SPierre Pronchery static void
test_tuple_add_multiple(void)55*592efe25SPierre Pronchery test_tuple_add_multiple(void)
56*592efe25SPierre Pronchery {
57*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
58*592efe25SPierre Pronchery 	pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER;
59*592efe25SPierre Pronchery 
60*592efe25SPierre Pronchery 	pkgconf_tuple_add(client, &tuples, "prefix", "/usr", false, 0);
61*592efe25SPierre Pronchery 	pkgconf_tuple_add(client, &tuples, "exec_prefix", "/usr/local", false, 0);
62*592efe25SPierre Pronchery 	pkgconf_tuple_add(client, &tuples, "libdir", "/usr/lib", false, 0);
63*592efe25SPierre Pronchery 
64*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find(client, &tuples, "prefix"), "/usr");
65*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find(client, &tuples, "exec_prefix"), "/usr/local");
66*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find(client, &tuples, "libdir"), "/usr/lib");
67*592efe25SPierre Pronchery 	TEST_ASSERT_EMPTY_STRING(pkgconf_tuple_find(client, &tuples, "datadir"));
68*592efe25SPierre Pronchery 
69*592efe25SPierre Pronchery 	pkgconf_tuple_free(&tuples);
70*592efe25SPierre Pronchery 	pkgconf_client_free(client);
71*592efe25SPierre Pronchery }
72*592efe25SPierre Pronchery 
73*592efe25SPierre Pronchery static void
test_tuple_global_add_and_find(void)74*592efe25SPierre Pronchery test_tuple_global_add_and_find(void)
75*592efe25SPierre Pronchery {
76*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
77*592efe25SPierre Pronchery 
78*592efe25SPierre Pronchery 	pkgconf_tuple_add_global(client, "PKG_TEST_KEY", "test_value");
79*592efe25SPierre Pronchery 
80*592efe25SPierre Pronchery 	const char *found = pkgconf_tuple_find_global(client, "PKG_TEST_KEY");
81*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(found);
82*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(found, "test_value");
83*592efe25SPierre Pronchery 
84*592efe25SPierre Pronchery 	pkgconf_tuple_free_global(client);
85*592efe25SPierre Pronchery 	pkgconf_client_free(client);
86*592efe25SPierre Pronchery }
87*592efe25SPierre Pronchery 
88*592efe25SPierre Pronchery static void
test_tuple_global_find_absent(void)89*592efe25SPierre Pronchery test_tuple_global_find_absent(void)
90*592efe25SPierre Pronchery {
91*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
92*592efe25SPierre Pronchery 
93*592efe25SPierre Pronchery 	const char *found = pkgconf_tuple_find_global(client, "DOES_NOT_EXIST");
94*592efe25SPierre Pronchery 	TEST_ASSERT_EMPTY_STRING(found);
95*592efe25SPierre Pronchery 
96*592efe25SPierre Pronchery 	pkgconf_client_free(client);
97*592efe25SPierre Pronchery }
98*592efe25SPierre Pronchery 
99*592efe25SPierre Pronchery static void
test_tuple_define_global_kv_form(void)100*592efe25SPierre Pronchery test_tuple_define_global_kv_form(void)
101*592efe25SPierre Pronchery {
102*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
103*592efe25SPierre Pronchery 
104*592efe25SPierre Pronchery 	/* This is the exact path --define-variable=KEY=VALUE takes
105*592efe25SPierre Pronchery 	 * pkgconf_tuple_define_global parses the "key=value" form and inserts it as a global tuple. */
106*592efe25SPierre Pronchery 	pkgconf_tuple_define_global(client, "myvar=myvalue");
107*592efe25SPierre Pronchery 
108*592efe25SPierre Pronchery 	const char *found = pkgconf_tuple_find_global(client, "myvar");
109*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(found);
110*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(found, "myvalue");
111*592efe25SPierre Pronchery 
112*592efe25SPierre Pronchery 	pkgconf_tuple_free_global(client);
113*592efe25SPierre Pronchery 	pkgconf_client_free(client);
114*592efe25SPierre Pronchery }
115*592efe25SPierre Pronchery 
116*592efe25SPierre Pronchery static void
test_tuple_define_global_with_equals_in_value(void)117*592efe25SPierre Pronchery test_tuple_define_global_with_equals_in_value(void)
118*592efe25SPierre Pronchery {
119*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
120*592efe25SPierre Pronchery 
121*592efe25SPierre Pronchery 	// Only the first '=' should split key from value; subsequent '=' characters belong to the value.
122*592efe25SPierre Pronchery 	pkgconf_tuple_define_global(client, "CFLAGS=-DFOO=bar");
123*592efe25SPierre Pronchery 
124*592efe25SPierre Pronchery 	const char *found = pkgconf_tuple_find_global(client, "CFLAGS");
125*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(found);
126*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(found, "-DFOO=bar");
127*592efe25SPierre Pronchery 
128*592efe25SPierre Pronchery 	pkgconf_tuple_free_global(client);
129*592efe25SPierre Pronchery 	pkgconf_client_free(client);
130*592efe25SPierre Pronchery }
131*592efe25SPierre Pronchery 
132*592efe25SPierre Pronchery static void
test_tuple_global_multiple(void)133*592efe25SPierre Pronchery test_tuple_global_multiple(void)
134*592efe25SPierre Pronchery {
135*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
136*592efe25SPierre Pronchery 
137*592efe25SPierre Pronchery 	pkgconf_tuple_define_global(client, "a=1");
138*592efe25SPierre Pronchery 	pkgconf_tuple_define_global(client, "b=2");
139*592efe25SPierre Pronchery 	pkgconf_tuple_define_global(client, "c=3");
140*592efe25SPierre Pronchery 
141*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find_global(client, "a"), "1");
142*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find_global(client, "b"), "2");
143*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(pkgconf_tuple_find_global(client, "c"), "3");
144*592efe25SPierre Pronchery 
145*592efe25SPierre Pronchery 	pkgconf_tuple_free_global(client);
146*592efe25SPierre Pronchery 	pkgconf_client_free(client);
147*592efe25SPierre Pronchery }
148*592efe25SPierre Pronchery 
149*592efe25SPierre Pronchery static void
test_tuple_global_free_resets(void)150*592efe25SPierre Pronchery test_tuple_global_free_resets(void)
151*592efe25SPierre Pronchery {
152*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
153*592efe25SPierre Pronchery 
154*592efe25SPierre Pronchery 	pkgconf_tuple_define_global(client, "temp=value");
155*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(pkgconf_tuple_find_global(client, "temp"));
156*592efe25SPierre Pronchery 
157*592efe25SPierre Pronchery 	pkgconf_tuple_free_global(client);
158*592efe25SPierre Pronchery 	TEST_ASSERT_EMPTY_STRING(pkgconf_tuple_find_global(client, "temp"));
159*592efe25SPierre Pronchery 
160*592efe25SPierre Pronchery 	pkgconf_client_free(client);
161*592efe25SPierre Pronchery }
162*592efe25SPierre Pronchery 
163*592efe25SPierre Pronchery static void
test_tuple_free_empty(void)164*592efe25SPierre Pronchery test_tuple_free_empty(void)
165*592efe25SPierre Pronchery {
166*592efe25SPierre Pronchery 	pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER;
167*592efe25SPierre Pronchery 
168*592efe25SPierre Pronchery 	// Freeing an empty list should be a no-op. Mostly an ASan/leak check smoke test.
169*592efe25SPierre Pronchery 	pkgconf_tuple_free(&tuples);
170*592efe25SPierre Pronchery }
171*592efe25SPierre Pronchery 
172*592efe25SPierre Pronchery static void
test_tuple_define_variable_end_to_end(void)173*592efe25SPierre Pronchery test_tuple_define_variable_end_to_end(void)
174*592efe25SPierre Pronchery {
175*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
176*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
177*592efe25SPierre Pronchery 	bool saw_sysroot = false;
178*592efe25SPierre Pronchery 
179*592efe25SPierre Pronchery 	pkgconf_tuple_define_global(client, "myprefix=/opt/custom");
180*592efe25SPierre Pronchery 
181*592efe25SPierre Pronchery 	char *out = pkgconf_bytecode_eval_str(client, &vars, "-I${myprefix}/include", &saw_sysroot);
182*592efe25SPierre Pronchery 
183*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(out);
184*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(out, "-I/opt/custom/include");
185*592efe25SPierre Pronchery 
186*592efe25SPierre Pronchery 	free(out);
187*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
188*592efe25SPierre Pronchery 	pkgconf_tuple_free_global(client);
189*592efe25SPierre Pronchery 	pkgconf_client_free(client);
190*592efe25SPierre Pronchery }
191*592efe25SPierre Pronchery 
192*592efe25SPierre Pronchery static void
test_tuple_define_variable_overrides_local(void)193*592efe25SPierre Pronchery test_tuple_define_variable_overrides_local(void)
194*592efe25SPierre Pronchery {
195*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
196*592efe25SPierre Pronchery 	pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER;
197*592efe25SPierre Pronchery 	bool saw_sysroot = false;
198*592efe25SPierre Pronchery 
199*592efe25SPierre Pronchery 	pkgconf_variable_t *v = pkgconf_variable_get_or_create(&vars, "prefix");
200*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(v);
201*592efe25SPierre Pronchery 	pkgconf_buffer_reset(&v->bcbuf);
202*592efe25SPierre Pronchery 	pkgconf_bytecode_compile(&v->bcbuf, "/usr");
203*592efe25SPierre Pronchery 	pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf);
204*592efe25SPierre Pronchery 
205*592efe25SPierre Pronchery 	// Simulate user passing --define-variable=prefix=/custom.
206*592efe25SPierre Pronchery 	pkgconf_tuple_define_global(client, "prefix=/custom");
207*592efe25SPierre Pronchery 
208*592efe25SPierre Pronchery 	char *out = pkgconf_bytecode_eval_str(client, &vars, "${prefix}/lib", &saw_sysroot);
209*592efe25SPierre Pronchery 
210*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(out);
211*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(out, "/custom/lib");
212*592efe25SPierre Pronchery 
213*592efe25SPierre Pronchery 	free(out);
214*592efe25SPierre Pronchery 	pkgconf_variable_list_free(&vars);
215*592efe25SPierre Pronchery 	pkgconf_tuple_free_global(client);
216*592efe25SPierre Pronchery 	pkgconf_client_free(client);
217*592efe25SPierre Pronchery }
218*592efe25SPierre Pronchery 
219*592efe25SPierre Pronchery static void
test_tuple_escaped_quote(void)220*592efe25SPierre Pronchery test_tuple_escaped_quote(void)
221*592efe25SPierre Pronchery {
222*592efe25SPierre Pronchery 	pkgconf_client_t *client = test_client_new();
223*592efe25SPierre Pronchery 	pkgconf_list_t tuples = PKGCONF_LIST_INITIALIZER;
224*592efe25SPierre Pronchery 
225*592efe25SPierre Pronchery 	// A double-quoted value containing an escaped double-quote
226*592efe25SPierre Pronchery 	pkgconf_tuple_t *t = pkgconf_tuple_add(client, &tuples, "key", "\"a\\\"b\"", true, 0);
227*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(t);
228*592efe25SPierre Pronchery 
229*592efe25SPierre Pronchery 	const char *found = pkgconf_tuple_find(client, &tuples, "key");
230*592efe25SPierre Pronchery 	TEST_ASSERT_NONNULL(found);
231*592efe25SPierre Pronchery 	TEST_ASSERT_STRCMP_EQ(found, "a\"b");
232*592efe25SPierre Pronchery 
233*592efe25SPierre Pronchery 	pkgconf_tuple_free(&tuples);
234*592efe25SPierre Pronchery 	pkgconf_client_free(client);
235*592efe25SPierre Pronchery }
236*592efe25SPierre Pronchery 
237*592efe25SPierre Pronchery int
main(int argc,char * argv[])238*592efe25SPierre Pronchery main(int argc, char *argv[])
239*592efe25SPierre Pronchery {
240*592efe25SPierre Pronchery 	(void) argc;
241*592efe25SPierre Pronchery 	const char *basename = pkgconf_path_find_basename(argv[0]);
242*592efe25SPierre Pronchery 
243*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_add_and_find);
244*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_find_absent);
245*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_add_multiple);
246*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_free_empty);
247*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_global_add_and_find);
248*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_global_find_absent);
249*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_define_global_kv_form);
250*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_define_global_with_equals_in_value);
251*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_global_multiple);
252*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_global_free_resets);
253*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_define_variable_end_to_end);
254*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_define_variable_overrides_local);
255*592efe25SPierre Pronchery 	TEST_RUN(basename, test_tuple_escaped_quote);
256*592efe25SPierre Pronchery 
257*592efe25SPierre Pronchery 	return EXIT_SUCCESS;
258*592efe25SPierre Pronchery }
259