1*592efe25SPierre Pronchery /*
2*592efe25SPierre Pronchery * test-license.c
3*592efe25SPierre Pronchery * Tests for the public libpkgconf license API.
4*592efe25SPierre Pronchery *
5*592efe25SPierre Pronchery * SPDX-License-Identifier: pkgconf
6*592efe25SPierre Pronchery *
7*592efe25SPierre Pronchery * Copyright (c) 2026 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 "test-api.h"
19*592efe25SPierre Pronchery
20*592efe25SPierre Pronchery static size_t
license_count(const pkgconf_list_t * list)21*592efe25SPierre Pronchery license_count(const pkgconf_list_t *list)
22*592efe25SPierre Pronchery {
23*592efe25SPierre Pronchery size_t n = 0;
24*592efe25SPierre Pronchery const pkgconf_node_t *iter;
25*592efe25SPierre Pronchery
26*592efe25SPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(list->head, iter)
27*592efe25SPierre Pronchery {
28*592efe25SPierre Pronchery n++;
29*592efe25SPierre Pronchery }
30*592efe25SPierre Pronchery
31*592efe25SPierre Pronchery return n;
32*592efe25SPierre Pronchery }
33*592efe25SPierre Pronchery
34*592efe25SPierre Pronchery static char *
render_to_string(pkgconf_client_t * client,const pkgconf_list_t * list)35*592efe25SPierre Pronchery render_to_string(pkgconf_client_t *client, const pkgconf_list_t *list)
36*592efe25SPierre Pronchery {
37*592efe25SPierre Pronchery pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
38*592efe25SPierre Pronchery pkgconf_license_render(client, list, &buf);
39*592efe25SPierre Pronchery
40*592efe25SPierre Pronchery char *out = strdup(pkgconf_buffer_str_or_empty(&buf));
41*592efe25SPierre Pronchery pkgconf_buffer_finalize(&buf);
42*592efe25SPierre Pronchery return out;
43*592efe25SPierre Pronchery }
44*592efe25SPierre Pronchery
45*592efe25SPierre Pronchery static void
test_license_insert_and_free(void)46*592efe25SPierre Pronchery test_license_insert_and_free(void)
47*592efe25SPierre Pronchery {
48*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
49*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
50*592efe25SPierre Pronchery
51*592efe25SPierre Pronchery pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "BSD-3-Clause");
52*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&licenses), 1);
53*592efe25SPierre Pronchery
54*592efe25SPierre Pronchery const pkgconf_license_t *l = licenses.head->data;
55*592efe25SPierre Pronchery TEST_ASSERT_NONNULL(l);
56*592efe25SPierre Pronchery TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION);
57*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause");
58*592efe25SPierre Pronchery
59*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
60*592efe25SPierre Pronchery pkgconf_client_free(client);
61*592efe25SPierre Pronchery }
62*592efe25SPierre Pronchery
63*592efe25SPierre Pronchery static void
test_license_free_empty(void)64*592efe25SPierre Pronchery test_license_free_empty(void)
65*592efe25SPierre Pronchery {
66*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
67*592efe25SPierre Pronchery
68*592efe25SPierre Pronchery // Freeing an empty list is a no-op. Smoke test.
69*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
70*592efe25SPierre Pronchery
71*592efe25SPierre Pronchery // Smoke test
72*592efe25SPierre Pronchery pkgconf_license_free(NULL);
73*592efe25SPierre Pronchery }
74*592efe25SPierre Pronchery
75*592efe25SPierre Pronchery static void
test_license_evaluate_single(void)76*592efe25SPierre Pronchery test_license_evaluate_single(void)
77*592efe25SPierre Pronchery {
78*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
79*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
80*592efe25SPierre Pronchery
81*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0);
82*592efe25SPierre Pronchery
83*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&licenses), 1);
84*592efe25SPierre Pronchery const pkgconf_license_t *l = licenses.head->data;
85*592efe25SPierre Pronchery TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION);
86*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause");
87*592efe25SPierre Pronchery
88*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
89*592efe25SPierre Pronchery pkgconf_client_free(client);
90*592efe25SPierre Pronchery }
91*592efe25SPierre Pronchery
92*592efe25SPierre Pronchery static void
test_license_evaluate_or(void)93*592efe25SPierre Pronchery test_license_evaluate_or(void)
94*592efe25SPierre Pronchery {
95*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
96*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
97*592efe25SPierre Pronchery
98*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "MIT OR ISC", 0);
99*592efe25SPierre Pronchery
100*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&licenses), 3);
101*592efe25SPierre Pronchery
102*592efe25SPierre Pronchery char *rendered = render_to_string(client, &licenses);
103*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(rendered, "MIT OR ISC");
104*592efe25SPierre Pronchery free(rendered);
105*592efe25SPierre Pronchery
106*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
107*592efe25SPierre Pronchery pkgconf_client_free(client);
108*592efe25SPierre Pronchery }
109*592efe25SPierre Pronchery
110*592efe25SPierre Pronchery static void
test_license_evaluate_and(void)111*592efe25SPierre Pronchery test_license_evaluate_and(void)
112*592efe25SPierre Pronchery {
113*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
114*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
115*592efe25SPierre Pronchery
116*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "LGPL-2.1-only AND MIT", 0);
117*592efe25SPierre Pronchery
118*592efe25SPierre Pronchery char *rendered = render_to_string(client, &licenses);
119*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(rendered, "LGPL-2.1-only AND MIT");
120*592efe25SPierre Pronchery free(rendered);
121*592efe25SPierre Pronchery
122*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
123*592efe25SPierre Pronchery pkgconf_client_free(client);
124*592efe25SPierre Pronchery }
125*592efe25SPierre Pronchery
126*592efe25SPierre Pronchery static void
test_license_evaluate_multiple_keys_implicit_and(void)127*592efe25SPierre Pronchery test_license_evaluate_multiple_keys_implicit_and(void)
128*592efe25SPierre Pronchery {
129*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
130*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
131*592efe25SPierre Pronchery
132*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0);
133*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "BSD-2-Clause", 0);
134*592efe25SPierre Pronchery
135*592efe25SPierre Pronchery char *rendered = render_to_string(client, &licenses);
136*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(rendered, "BSD-3-Clause AND BSD-2-Clause");
137*592efe25SPierre Pronchery free(rendered);
138*592efe25SPierre Pronchery
139*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
140*592efe25SPierre Pronchery pkgconf_client_free(client);
141*592efe25SPierre Pronchery }
142*592efe25SPierre Pronchery
143*592efe25SPierre Pronchery static void
test_license_evaluate_brackets(void)144*592efe25SPierre Pronchery test_license_evaluate_brackets(void)
145*592efe25SPierre Pronchery {
146*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
147*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
148*592efe25SPierre Pronchery
149*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "ISC AND (BSD-3-Clause AND BSD-2-Clause)", 0);
150*592efe25SPierre Pronchery
151*592efe25SPierre Pronchery char *rendered = render_to_string(client, &licenses);
152*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(rendered, "ISC AND (BSD-3-Clause AND BSD-2-Clause)");
153*592efe25SPierre Pronchery free(rendered);
154*592efe25SPierre Pronchery
155*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
156*592efe25SPierre Pronchery pkgconf_client_free(client);
157*592efe25SPierre Pronchery }
158*592efe25SPierre Pronchery
159*592efe25SPierre Pronchery static void
test_license_evaluate_empty(void)160*592efe25SPierre Pronchery test_license_evaluate_empty(void)
161*592efe25SPierre Pronchery {
162*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
163*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
164*592efe25SPierre Pronchery
165*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "", 0);
166*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&licenses), 0);
167*592efe25SPierre Pronchery
168*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
169*592efe25SPierre Pronchery pkgconf_client_free(client);
170*592efe25SPierre Pronchery }
171*592efe25SPierre Pronchery
172*592efe25SPierre Pronchery static void
test_license_evaluate_sanitizes(void)173*592efe25SPierre Pronchery test_license_evaluate_sanitizes(void)
174*592efe25SPierre Pronchery {
175*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
176*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
177*592efe25SPierre Pronchery
178*592efe25SPierre Pronchery /* The sanitiser strips characters outside the allowed set
179*592efe25SPierre Pronchery * (alnum, '-', '+', '(', ')', '.', ':'). A token of pure
180*592efe25SPierre Pronchery * junk should sanitise to empty and be skipped. */
181*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0);
182*592efe25SPierre Pronchery
183*592efe25SPierre Pronchery const pkgconf_license_t *l = licenses.head->data;
184*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause");
185*592efe25SPierre Pronchery
186*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
187*592efe25SPierre Pronchery pkgconf_client_free(client);
188*592efe25SPierre Pronchery }
189*592efe25SPierre Pronchery
190*592efe25SPierre Pronchery static void
test_license_render_empty(void)191*592efe25SPierre Pronchery test_license_render_empty(void)
192*592efe25SPierre Pronchery {
193*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
194*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
195*592efe25SPierre Pronchery
196*592efe25SPierre Pronchery char *rendered = render_to_string(client, &licenses);
197*592efe25SPierre Pronchery TEST_ASSERT_EMPTY_STRING(rendered);
198*592efe25SPierre Pronchery free(rendered);
199*592efe25SPierre Pronchery
200*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
201*592efe25SPierre Pronchery pkgconf_client_free(client);
202*592efe25SPierre Pronchery }
203*592efe25SPierre Pronchery
204*592efe25SPierre Pronchery static void
test_license_render_single(void)205*592efe25SPierre Pronchery test_license_render_single(void)
206*592efe25SPierre Pronchery {
207*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
208*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
209*592efe25SPierre Pronchery
210*592efe25SPierre Pronchery pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "MIT");
211*592efe25SPierre Pronchery
212*592efe25SPierre Pronchery char *rendered = render_to_string(client, &licenses);
213*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(rendered, "MIT");
214*592efe25SPierre Pronchery free(rendered);
215*592efe25SPierre Pronchery
216*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
217*592efe25SPierre Pronchery pkgconf_client_free(client);
218*592efe25SPierre Pronchery }
219*592efe25SPierre Pronchery
220*592efe25SPierre Pronchery static void
test_license_copy_list(void)221*592efe25SPierre Pronchery test_license_copy_list(void)
222*592efe25SPierre Pronchery {
223*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
224*592efe25SPierre Pronchery pkgconf_list_t src = PKGCONF_LIST_INITIALIZER;
225*592efe25SPierre Pronchery pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER;
226*592efe25SPierre Pronchery
227*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &src, "MIT OR ISC", 0);
228*592efe25SPierre Pronchery size_t src_count = license_count(&src);
229*592efe25SPierre Pronchery
230*592efe25SPierre Pronchery pkgconf_license_copy_list(client, &dst, &src);
231*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&dst), src_count);
232*592efe25SPierre Pronchery
233*592efe25SPierre Pronchery /* The copy is independent: freeing the source must not affect
234*592efe25SPierre Pronchery * the destination's rendered output. */
235*592efe25SPierre Pronchery pkgconf_license_free(&src);
236*592efe25SPierre Pronchery
237*592efe25SPierre Pronchery char *rendered = render_to_string(client, &dst);
238*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(rendered, "MIT OR ISC");
239*592efe25SPierre Pronchery free(rendered);
240*592efe25SPierre Pronchery
241*592efe25SPierre Pronchery pkgconf_license_free(&dst);
242*592efe25SPierre Pronchery pkgconf_client_free(client);
243*592efe25SPierre Pronchery }
244*592efe25SPierre Pronchery
245*592efe25SPierre Pronchery static void
test_license_evaluate_long_sanitized_token(void)246*592efe25SPierre Pronchery test_license_evaluate_long_sanitized_token(void)
247*592efe25SPierre Pronchery {
248*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
249*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
250*592efe25SPierre Pronchery
251*592efe25SPierre Pronchery char token[512];
252*592efe25SPierre Pronchery token[0] = 'A';
253*592efe25SPierre Pronchery memset(token + 1, '_', 400);
254*592efe25SPierre Pronchery token[401] = '\0';
255*592efe25SPierre Pronchery
256*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, token, 0);
257*592efe25SPierre Pronchery
258*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&licenses), 1);
259*592efe25SPierre Pronchery const pkgconf_license_t *l = licenses.head->data;
260*592efe25SPierre Pronchery TEST_ASSERT_EQ(l->type, PKGCONF_LICENSE_EXPRESSION);
261*592efe25SPierre Pronchery TEST_ASSERT_STRCMP_EQ(l->data, "A");
262*592efe25SPierre Pronchery
263*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
264*592efe25SPierre Pronchery pkgconf_client_free(client);
265*592efe25SPierre Pronchery }
266*592efe25SPierre Pronchery
267*592efe25SPierre Pronchery static void
test_license_evaluate_unterminated_quote(void)268*592efe25SPierre Pronchery test_license_evaluate_unterminated_quote(void)
269*592efe25SPierre Pronchery {
270*592efe25SPierre Pronchery pkgconf_client_t *client = test_client_new();
271*592efe25SPierre Pronchery pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER;
272*592efe25SPierre Pronchery
273*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "\"", 0);
274*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&licenses), 0);
275*592efe25SPierre Pronchery
276*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "MIT \"unterminated", 0);
277*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&licenses), 0);
278*592efe25SPierre Pronchery
279*592efe25SPierre Pronchery pkgconf_license_evaluate_str(client, &licenses, "\\", 0);
280*592efe25SPierre Pronchery TEST_ASSERT_EQ(license_count(&licenses), 0);
281*592efe25SPierre Pronchery
282*592efe25SPierre Pronchery pkgconf_license_free(&licenses);
283*592efe25SPierre Pronchery pkgconf_client_free(client);
284*592efe25SPierre Pronchery }
285*592efe25SPierre Pronchery
286*592efe25SPierre Pronchery int
main(int argc,char * argv[])287*592efe25SPierre Pronchery main(int argc, char *argv[])
288*592efe25SPierre Pronchery {
289*592efe25SPierre Pronchery (void) argc;
290*592efe25SPierre Pronchery const char *basename = pkgconf_path_find_basename(argv[0]);
291*592efe25SPierre Pronchery
292*592efe25SPierre Pronchery TEST_RUN(basename, test_license_insert_and_free);
293*592efe25SPierre Pronchery TEST_RUN(basename, test_license_free_empty);
294*592efe25SPierre Pronchery
295*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_single);
296*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_or);
297*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_and);
298*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_multiple_keys_implicit_and);
299*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_brackets);
300*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_empty);
301*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_sanitizes);
302*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_long_sanitized_token);
303*592efe25SPierre Pronchery TEST_RUN(basename, test_license_evaluate_unterminated_quote);
304*592efe25SPierre Pronchery
305*592efe25SPierre Pronchery TEST_RUN(basename, test_license_render_empty);
306*592efe25SPierre Pronchery TEST_RUN(basename, test_license_render_single);
307*592efe25SPierre Pronchery
308*592efe25SPierre Pronchery TEST_RUN(basename, test_license_copy_list);
309*592efe25SPierre Pronchery
310*592efe25SPierre Pronchery return EXIT_SUCCESS;
311*592efe25SPierre Pronchery }
312