xref: /freebsd/contrib/pkgconf/tests/api/test-path-utils.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1 /*
2  * test-path-utils.c
3  * Tests for libpkgconf internal path utility functions.
4  *
5  * SPDX-License-Identifier: pkgconf
6  *
7  * Copyright (c) 2025-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 <libpkgconf/stdinc.h>
19 #include <libpkgconf/libpkgconf.h>
20 #include <libpkgconf/path.h>
21 #include "test-api.h"
22 
23 static void
test_path_find_basename(void)24 test_path_find_basename(void)
25 {
26 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("/usr/lib/pkgconfig/foo.pc"), "foo.pc");
27 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("/usr/lib/pkgconfig"), "pkgconfig");
28 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("foo.pc"), "foo.pc");
29 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("/foo.pc"), "foo.pc");
30 	TEST_ASSERT_EMPTY_STRING(pkgconf_path_find_basename("/"));
31 	TEST_ASSERT_EMPTY_STRING(pkgconf_path_find_basename(""));
32 	TEST_ASSERT_EMPTY_STRING(pkgconf_path_find_basename("/usr/"));
33 	TEST_ASSERT_EMPTY_STRING(pkgconf_path_find_basename("usr/"));
34 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("///usr/lib///pkgconfig///foo.pc"), "foo.pc");
35 #ifdef _WIN32
36 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("C:\\lib\\pkgconfig\\foo.pc"), "foo.pc");
37 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("C:/lib/pkgconfig/foo.pc"), "foo.pc");
38 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("C:/lib\\pkgconfig/foo.pc"), "foo.pc");
39 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename("C:\\lib/pkgconfig\\foo.pc"), "foo.pc");
40 #endif
41 }
42 
43 static void
test_path_trim_basename(void)44 test_path_trim_basename(void)
45 {
46 	pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
47 
48 	pkgconf_buffer_append(&buf, "/usr/lib/pkgconfig/foo.pc");
49 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
50 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr/lib/pkgconfig");
51 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
52 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr/lib");
53 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
54 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr");
55 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
56 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "");
57 	TEST_ASSERT_FALSE(pkgconf_path_trim_basename(&buf));
58 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "");
59 
60 	pkgconf_buffer_reset(&buf);
61 	pkgconf_buffer_append(&buf, "foo.pc");
62 	TEST_ASSERT_FALSE(pkgconf_path_trim_basename(&buf));
63 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "foo.pc");
64 
65 	pkgconf_buffer_finalize(&buf);
66 }
67 
68 static void
test_determine_prefix_logic(void)69 test_determine_prefix_logic(void)
70 {
71 	pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
72 
73 	// Normal case
74 	pkgconf_buffer_append(&buf, "/opt/foo/lib/pkgconfig/bar.pc");
75 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
76 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename(pkgconf_buffer_str(&buf)), "pkgconfig");
77 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
78 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
79 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/opt/foo");
80 
81 	// Short path: /pkgconfig/foo.pc
82 	pkgconf_buffer_reset(&buf);
83 	pkgconf_buffer_append(&buf, "/pkgconfig/foo.pc");
84 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
85 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename(pkgconf_buffer_str(&buf)), "pkgconfig");
86 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf)); // trims pkgconfig, returns true because of /
87 	TEST_ASSERT_FALSE(pkgconf_path_trim_basename(&buf)); // fails to trim further
88 
89 	// Another short path: lib/pkgconfig/foo.pc
90 	pkgconf_buffer_reset(&buf);
91 	pkgconf_buffer_append(&buf, "lib/pkgconfig/foo.pc");
92 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
93 	TEST_ASSERT_STRCMP_EQ(pkgconf_path_find_basename(pkgconf_buffer_str(&buf)), "pkgconfig");
94 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
95 	TEST_ASSERT_FALSE(pkgconf_path_trim_basename(&buf));
96 
97 	// Trailing slash
98 	pkgconf_buffer_reset(&buf);
99 	pkgconf_buffer_append(&buf, "/usr/lib/pkgconfig/");
100 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
101 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr/lib/pkgconfig");
102 	TEST_ASSERT_TRUE(pkgconf_path_trim_basename(&buf));
103 	TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "/usr/lib");
104 
105 	pkgconf_buffer_finalize(&buf);
106 }
107 
108 static const char *
nth_path(const pkgconf_list_t * list,size_t idx)109 nth_path(const pkgconf_list_t *list, size_t idx)
110 {
111 	pkgconf_node_t *n;
112 	size_t i = 0;
113 
114 	PKGCONF_FOREACH_LIST_ENTRY(list->head, n)
115 	{
116 		const pkgconf_path_t *p = n->data;
117 
118 		if (i++ == idx)
119 			return p->path;
120 	}
121 
122 	return NULL;
123 }
124 
125 static void
test_path_prepend(void)126 test_path_prepend(void)
127 {
128 	pkgconf_list_t list = PKGCONF_LIST_INITIALIZER;
129 
130 	pkgconf_path_prepend("/a", &list, false);
131 	pkgconf_path_prepend("/b", &list, false);
132 	pkgconf_path_prepend("/c", &list, false);
133 
134 	TEST_ASSERT_EQ(list.length, 3);
135 	TEST_ASSERT_STRCMP_EQ(nth_path(&list, 0), "/c");
136 	TEST_ASSERT_STRCMP_EQ(nth_path(&list, 1), "/b");
137 	TEST_ASSERT_STRCMP_EQ(nth_path(&list, 2), "/a");
138 
139 	pkgconf_path_add("/d", &list, false);
140 	TEST_ASSERT_EQ(list.length, 4);
141 	TEST_ASSERT_STRCMP_EQ(nth_path(&list, 0), "/c");
142 	TEST_ASSERT_STRCMP_EQ(nth_path(&list, 3), "/d");
143 
144 	pkgconf_path_prepend("/e//f", &list, false);
145 	TEST_ASSERT_STRCMP_EQ(nth_path(&list, 0), "/e/f");
146 
147 	pkgconf_path_free(&list);
148 	TEST_ASSERT_EQ(list.length, 0);
149 	TEST_ASSERT_NULL(list.head);
150 	TEST_ASSERT_NULL(list.tail);
151 }
152 
153 static void
test_path_prepend_filter(void)154 test_path_prepend_filter(void)
155 {
156 	pkgconf_list_t list = PKGCONF_LIST_INITIALIZER;
157 
158 	pkgconf_path_prepend(".", &list, true);
159 	TEST_ASSERT_EQ(list.length, 1);
160 
161 	pkgconf_path_prepend(".", &list, true);
162 	TEST_ASSERT_EQ(list.length, 1);
163 
164 	pkgconf_path_prepend("..", &list, true);
165 	TEST_ASSERT_EQ(list.length, 2);
166 
167 	pkgconf_path_prepend(".", &list, false);
168 	TEST_ASSERT_EQ(list.length, 3);
169 
170 	pkgconf_path_free(&list);
171 }
172 
173 static void
test_path_prepend_list(void)174 test_path_prepend_list(void)
175 {
176 	pkgconf_list_t src = PKGCONF_LIST_INITIALIZER;
177 	pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER;
178 
179 	pkgconf_path_add("/s1", &src, false);
180 	pkgconf_path_add("/s2", &src, false);
181 	pkgconf_path_add("/s3", &src, false);
182 
183 	pkgconf_path_add("/d1", &dst, false);
184 	pkgconf_path_add("/d2", &dst, false);
185 
186 	pkgconf_path_prepend_list(&dst, &src);
187 
188 	TEST_ASSERT_EQ(dst.length, 5);
189 	TEST_ASSERT_STRCMP_EQ(nth_path(&dst, 0), "/s3");
190 	TEST_ASSERT_STRCMP_EQ(nth_path(&dst, 1), "/s2");
191 	TEST_ASSERT_STRCMP_EQ(nth_path(&dst, 2), "/s1");
192 	TEST_ASSERT_STRCMP_EQ(nth_path(&dst, 3), "/d1");
193 	TEST_ASSERT_STRCMP_EQ(nth_path(&dst, 4), "/d2");
194 
195 	TEST_ASSERT_EQ(src.length, 3);
196 	TEST_ASSERT_STRCMP_EQ(nth_path(&src, 0), "/s1");
197 	TEST_ASSERT_TRUE(nth_path(&dst, 2) != nth_path(&src, 0));
198 
199 	pkgconf_path_free(&dst);
200 	TEST_ASSERT_EQ(dst.length, 0);
201 
202 	TEST_ASSERT_EQ(src.length, 3);
203 	TEST_ASSERT_STRCMP_EQ(nth_path(&src, 2), "/s3");
204 
205 	pkgconf_path_prepend_list(&dst, &src);
206 	TEST_ASSERT_EQ(dst.length, 3);
207 	TEST_ASSERT_STRCMP_EQ(nth_path(&dst, 0), "/s3");
208 	TEST_ASSERT_STRCMP_EQ(nth_path(&dst, 2), "/s1");
209 
210 	pkgconf_path_free(&src);
211 	pkgconf_path_free(&dst);
212 }
213 
214 static bool
plausible(const char * text)215 plausible(const char *text)
216 {
217 	pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
218 	bool result;
219 
220 	pkgconf_buffer_append(&buf, text);
221 	result = pkgconf_path_is_plausible(&buf);
222 	pkgconf_buffer_finalize(&buf);
223 
224 	return result;
225 }
226 
227 static void
test_path_is_plausible(void)228 test_path_is_plausible(void)
229 {
230 	pkgconf_buffer_t empty = PKGCONF_BUFFER_INITIALIZER;
231 
232 	TEST_ASSERT_FALSE(pkgconf_path_is_plausible(NULL));
233 	TEST_ASSERT_FALSE(pkgconf_path_is_plausible(&empty));
234 	pkgconf_buffer_finalize(&empty);
235 
236 	TEST_ASSERT_FALSE(plausible(""));
237 	TEST_ASSERT_FALSE(plausible("   "));
238 	TEST_ASSERT_FALSE(plausible("libfoo"));
239 	TEST_ASSERT_FALSE(plausible("foo bar"));
240 	TEST_ASSERT_FALSE(plausible("."));
241 	TEST_ASSERT_FALSE(plausible(".."));
242 
243 	TEST_ASSERT_TRUE(plausible("/usr/lib/pkgconfig"));
244 	TEST_ASSERT_TRUE(plausible("  /usr/lib"));
245 	TEST_ASSERT_TRUE(plausible("./foo"));
246 	TEST_ASSERT_TRUE(plausible("../foo"));
247 	TEST_ASSERT_TRUE(plausible(".\\foo"));
248 	TEST_ASSERT_TRUE(plausible("..\\foo"));
249 	TEST_ASSERT_TRUE(plausible("C:/foo"));
250 	TEST_ASSERT_TRUE(plausible("C:\\foo"));
251 	TEST_ASSERT_TRUE(plausible("relative/path"));
252 	TEST_ASSERT_TRUE(plausible("relative\\path"));
253 	TEST_ASSERT_TRUE(plausible("Program Files/MySDK"));
254 }
255 
256 int
main(int argc,char * argv[])257 main(int argc, char *argv[])
258 {
259 	(void) argc;
260 	const char *basename = pkgconf_path_find_basename(argv[0]);
261 
262 	TEST_RUN(basename, test_path_find_basename);
263 	TEST_RUN(basename, test_path_trim_basename);
264 	TEST_RUN(basename, test_determine_prefix_logic);
265 	TEST_RUN(basename, test_path_prepend);
266 	TEST_RUN(basename, test_path_prepend_filter);
267 	TEST_RUN(basename, test_path_prepend_list);
268 	TEST_RUN(basename, test_path_is_plausible);
269 
270 	return EXIT_SUCCESS;
271 }
272