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