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