1 /*
2 * test-buffer.c
3 * Tests for libpkgconf buffer API.
4 *
5 * SPDX-License-Identifier: pkgconf
6 *
7 * Copyright (c) 2025 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 "test-api.h"
21
22 static void
test_buffer_empty(void)23 test_buffer_empty(void)
24 {
25 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
26
27 TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 0);
28 TEST_ASSERT_NULL(pkgconf_buffer_str(&buf));
29 TEST_ASSERT_EMPTY_STRING(pkgconf_buffer_str_or_empty(&buf));
30 TEST_ASSERT_EQ(pkgconf_buffer_lastc(&buf), '\0');
31
32 pkgconf_buffer_finalize(&buf);
33 }
34
35 static void
test_buffer_append(void)36 test_buffer_append(void)
37 {
38 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
39
40 TEST_ASSERT_TRUE(pkgconf_buffer_append(&buf, "hello"));
41 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello");
42 TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 5);
43
44 TEST_ASSERT_TRUE(pkgconf_buffer_append(&buf, " world"));
45 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello world");
46 TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 11);
47
48 TEST_ASSERT_EQ(pkgconf_buffer_lastc(&buf), 'd');
49
50 pkgconf_buffer_finalize(&buf);
51 }
52
53 static void
test_buffer_append_slice(void)54 test_buffer_append_slice(void)
55 {
56 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
57
58 TEST_ASSERT_TRUE(pkgconf_buffer_append_slice(&buf, "abcdefgh", 3));
59 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "abc");
60
61 TEST_ASSERT_TRUE(pkgconf_buffer_append_slice(&buf, "xyz", 0));
62 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "abc");
63
64 pkgconf_buffer_finalize(&buf);
65 }
66
67 static void
test_buffer_append_fmt(void)68 test_buffer_append_fmt(void)
69 {
70 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
71
72 TEST_ASSERT_TRUE(pkgconf_buffer_append_fmt(&buf, "%s=%d", "x", 42));
73 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "x=42");
74
75 TEST_ASSERT_TRUE(pkgconf_buffer_append_fmt(&buf, " %s", "ok"));
76 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "x=42 ok");
77
78 pkgconf_buffer_finalize(&buf);
79 }
80
81 static void
test_buffer_prepend(void)82 test_buffer_prepend(void)
83 {
84 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
85
86 pkgconf_buffer_append(&buf, "world");
87 TEST_ASSERT_TRUE(pkgconf_buffer_prepend(&buf, "hello "));
88 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello world");
89
90 pkgconf_buffer_finalize(&buf);
91 }
92
93 static void
test_buffer_push_byte(void)94 test_buffer_push_byte(void)
95 {
96 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
97
98 TEST_ASSERT_TRUE(pkgconf_buffer_push_byte(&buf, 'a'));
99 TEST_ASSERT_TRUE(pkgconf_buffer_push_byte(&buf, 'b'));
100 TEST_ASSERT_TRUE(pkgconf_buffer_push_byte(&buf, 'c'));
101 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "abc");
102 TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 3);
103
104 pkgconf_buffer_finalize(&buf);
105 }
106
107 static void
test_buffer_trim_byte(void)108 test_buffer_trim_byte(void)
109 {
110 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
111
112 pkgconf_buffer_append(&buf, "hello\n");
113 TEST_ASSERT_TRUE(pkgconf_buffer_trim_byte(&buf));
114 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello");
115
116 pkgconf_buffer_reset(&buf);
117 pkgconf_buffer_push_byte(&buf, 'x');
118 TEST_ASSERT_TRUE(pkgconf_buffer_trim_byte(&buf));
119 TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 0);
120 TEST_ASSERT_FALSE(pkgconf_buffer_trim_byte(&buf));
121
122 pkgconf_buffer_finalize(&buf);
123 }
124
125 static void
test_buffer_reset(void)126 test_buffer_reset(void)
127 {
128 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
129
130 pkgconf_buffer_append(&buf, "some content");
131 TEST_ASSERT_NE(pkgconf_buffer_len(&buf), 0);
132
133 pkgconf_buffer_reset(&buf);
134 TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 0);
135 TEST_ASSERT_NULL(pkgconf_buffer_str(&buf));
136
137 TEST_ASSERT_TRUE(pkgconf_buffer_append(&buf, "fresh"));
138 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "fresh");
139
140 pkgconf_buffer_finalize(&buf);
141 }
142
143 static void
test_buffer_freeze(void)144 test_buffer_freeze(void)
145 {
146 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
147
148 pkgconf_buffer_append(&buf, "frozen");
149 char *out = pkgconf_buffer_freeze(&buf);
150 TEST_ASSERT_NONNULL(out);
151 TEST_ASSERT_STRCMP_EQ(out, "frozen");
152 TEST_ASSERT_EQ(pkgconf_buffer_len(&buf), 0);
153
154 TEST_ASSERT_NULL(pkgconf_buffer_freeze(&buf));
155
156 free(out);
157 pkgconf_buffer_finalize(&buf);
158 }
159
160 static void
test_buffer_copy(void)161 test_buffer_copy(void)
162 {
163 pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER;
164 pkgconf_buffer_t dst = PKGCONF_BUFFER_INITIALIZER;
165
166 pkgconf_buffer_append(&src, "original");
167 pkgconf_buffer_append(&dst, "to be replaced");
168 TEST_ASSERT_TRUE(pkgconf_buffer_copy(&src, &dst));
169 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst), "original");
170 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&src), "original"); // src is unchanged
171
172 pkgconf_buffer_finalize(&src);
173 pkgconf_buffer_finalize(&dst);
174 }
175
176 static void
test_buffer_join(void)177 test_buffer_join(void)
178 {
179 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
180
181 TEST_ASSERT_TRUE(pkgconf_buffer_join(&buf, '/', "usr", "local", "lib", NULL));
182 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "usr/local/lib");
183
184 pkgconf_buffer_finalize(&buf);
185 }
186
187 static void
test_buffer_contains(void)188 test_buffer_contains(void)
189 {
190 pkgconf_buffer_t hay = PKGCONF_BUFFER_INITIALIZER;
191 pkgconf_buffer_t needle = PKGCONF_BUFFER_INITIALIZER;
192
193 pkgconf_buffer_append(&hay, "the quick brown fox");
194
195 pkgconf_buffer_append(&needle, "quick");
196 TEST_ASSERT_TRUE(pkgconf_buffer_contains(&hay, &needle));
197
198 pkgconf_buffer_reset(&needle);
199 pkgconf_buffer_append(&needle, "slow");
200 TEST_ASSERT_FALSE(pkgconf_buffer_contains(&hay, &needle));
201
202 TEST_ASSERT_TRUE(pkgconf_buffer_contains_byte(&hay, 'q'));
203 TEST_ASSERT_FALSE(pkgconf_buffer_contains_byte(&hay, 'z'));
204
205 pkgconf_buffer_finalize(&hay);
206 pkgconf_buffer_finalize(&needle);
207 }
208
209 static void
test_buffer_match(void)210 test_buffer_match(void)
211 {
212 pkgconf_buffer_t a = PKGCONF_BUFFER_INITIALIZER;
213 pkgconf_buffer_t b = PKGCONF_BUFFER_INITIALIZER;
214
215 pkgconf_buffer_append(&a, "identical");
216 pkgconf_buffer_append(&b, "identical");
217 TEST_ASSERT_TRUE(pkgconf_buffer_match(&a, &b));
218
219 // Identical length, but different contents
220 pkgconf_buffer_reset(&b);
221 pkgconf_buffer_append(&b, "different");
222 TEST_ASSERT_FALSE(pkgconf_buffer_match(&a, &b));
223
224 // Different length and contents
225 pkgconf_buffer_reset(&b);
226 pkgconf_buffer_append(&b, "different!");
227 TEST_ASSERT_FALSE(pkgconf_buffer_match(&a, &b));
228
229 pkgconf_buffer_finalize(&a);
230 pkgconf_buffer_finalize(&b);
231 }
232
233 static void
test_buffer_has_prefix(void)234 test_buffer_has_prefix(void)
235 {
236 pkgconf_buffer_t hay = PKGCONF_BUFFER_INITIALIZER;
237 pkgconf_buffer_t pre = PKGCONF_BUFFER_INITIALIZER;
238
239 pkgconf_buffer_append(&hay, "/usr/local/lib");
240
241 pkgconf_buffer_append(&pre, "/usr");
242 TEST_ASSERT_TRUE(pkgconf_buffer_has_prefix(&hay, &pre));
243
244 pkgconf_buffer_reset(&pre);
245 pkgconf_buffer_append(&pre, "/opt");
246 TEST_ASSERT_FALSE(pkgconf_buffer_has_prefix(&hay, &pre));
247
248 pkgconf_buffer_finalize(&hay);
249 pkgconf_buffer_finalize(&pre);
250 }
251
252 static void
test_buffer_subst(void)253 test_buffer_subst(void)
254 {
255 pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER;
256 pkgconf_buffer_t dst = PKGCONF_BUFFER_INITIALIZER;
257
258 pkgconf_buffer_append(&src, "prefix=${PREFIX}/share");
259 TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst, &src, "${PREFIX}", "/opt/foo"));
260 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst), "prefix=/opt/foo/share");
261
262 pkgconf_buffer_finalize(&src);
263 pkgconf_buffer_finalize(&dst);
264 }
265
266 static void
test_buffer_subst_empty_pattern(void)267 test_buffer_subst_empty_pattern(void)
268 {
269 pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER;
270 pkgconf_buffer_t dst0 = PKGCONF_BUFFER_INITIALIZER;
271 pkgconf_buffer_t dst1 = PKGCONF_BUFFER_INITIALIZER;
272 pkgconf_buffer_t dst2 = PKGCONF_BUFFER_INITIALIZER;
273 pkgconf_buffer_t dst3 = PKGCONF_BUFFER_INITIALIZER;
274 pkgconf_buffer_t dst4 = PKGCONF_BUFFER_INITIALIZER;
275 pkgconf_buffer_t dst5 = PKGCONF_BUFFER_INITIALIZER;
276
277 pkgconf_buffer_append(&src, "prefix=${PREFIX}/share");
278
279 TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst0, &src, "", "foo"));
280 TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst1, &src, "", ""));
281 TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst2, &src, "", NULL));
282 TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst3, &src, NULL, "foo"));
283 TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst4, &src, NULL, ""));
284 TEST_ASSERT_TRUE(pkgconf_buffer_subst(&dst5, &src, NULL, NULL));
285
286 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst0), "prefix=${PREFIX}/share");
287 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst1), "prefix=${PREFIX}/share");
288 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst2), "prefix=${PREFIX}/share");
289 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst3), "prefix=${PREFIX}/share");
290 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst4), "prefix=${PREFIX}/share");
291 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst5), "prefix=${PREFIX}/share");
292
293 pkgconf_buffer_finalize(&src);
294 pkgconf_buffer_finalize(&dst0);
295 pkgconf_buffer_finalize(&dst1);
296 pkgconf_buffer_finalize(&dst2);
297 pkgconf_buffer_finalize(&dst3);
298 pkgconf_buffer_finalize(&dst4);
299 pkgconf_buffer_finalize(&dst5);
300 }
301
302 static void
test_buffer_escape(void)303 test_buffer_escape(void)
304 {
305 pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER;
306 pkgconf_buffer_t dst = PKGCONF_BUFFER_INITIALIZER;
307
308 pkgconf_span_t spans[] = {
309 { ' ', ' ' },
310 { '\t', '\t' },
311 };
312
313 pkgconf_buffer_append(&src, "a b\tc");
314 TEST_ASSERT_TRUE(pkgconf_buffer_escape(&dst, &src, spans, PKGCONF_ARRAY_SIZE(spans)));
315 TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst), "a\\ b\\\tc");
316
317 pkgconf_buffer_finalize(&src);
318 pkgconf_buffer_finalize(&dst);
319 }
320
321 static void
test_str_eq_slice(void)322 test_str_eq_slice(void)
323 {
324 TEST_ASSERT_TRUE(pkgconf_str_eq_slice("hello", "hello", 5));
325 TEST_ASSERT_FALSE(pkgconf_str_eq_slice("hello!", "hello", 5));
326 TEST_ASSERT_FALSE(pkgconf_str_eq_slice("hello", "world", 5));
327 TEST_ASSERT_FALSE(pkgconf_str_eq_slice(NULL, "hello", 5));
328 }
329
330 static void
test_span_contains(void)331 test_span_contains(void)
332 {
333 pkgconf_span_t spans[] = {
334 { '0', '9' },
335 { 'a', 'z' },
336 };
337
338 TEST_ASSERT_TRUE(pkgconf_span_contains('5', spans, PKGCONF_ARRAY_SIZE(spans)));
339 TEST_ASSERT_TRUE(pkgconf_span_contains('m', spans, PKGCONF_ARRAY_SIZE(spans)));
340 TEST_ASSERT_FALSE(pkgconf_span_contains('A', spans, PKGCONF_ARRAY_SIZE(spans)));
341 TEST_ASSERT_FALSE(pkgconf_span_contains('!', spans, PKGCONF_ARRAY_SIZE(spans)));
342 }
343
344 static void
test_buffer_fputs_nonempty(void)345 test_buffer_fputs_nonempty(void)
346 {
347 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
348 FILE *f = tmpfile();
349 TEST_ASSERT_NONNULL(f);
350
351 pkgconf_buffer_append(&buf, "hello world");
352 TEST_ASSERT_TRUE(pkgconf_buffer_fputs(&buf, f));
353
354 char out[64];
355 rewind(f);
356 size_t n = fread(out, 1, sizeof(out) - 1, f);
357 out[n] = '\0';
358
359 // Buffer contents followed by a newline.
360 TEST_ASSERT_STRCMP_EQ(out, "hello world\n");
361
362 fclose(f);
363 pkgconf_buffer_finalize(&buf);
364 }
365
366 static void
test_buffer_fputs_empty(void)367 test_buffer_fputs_empty(void)
368 {
369 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
370 FILE *f = tmpfile();
371 TEST_ASSERT_NONNULL(f);
372
373 // An empty buffer writes only a newline.
374 TEST_ASSERT_TRUE(pkgconf_buffer_fputs(&buf, f));
375
376 char out[64];
377 rewind(f);
378 size_t n = fread(out, 1, sizeof(out) - 1, f);
379 out[n] = '\0';
380
381 TEST_ASSERT_STRCMP_EQ(out, "\n");
382
383 fclose(f);
384 pkgconf_buffer_finalize(&buf);
385 }
386
387 int
main(int argc,const char ** argv)388 main(int argc, const char **argv)
389 {
390 (void) argc;
391
392 const char *basename = pkgconf_path_find_basename(argv[0]);
393
394 TEST_RUN(basename, test_buffer_empty);
395 TEST_RUN(basename, test_buffer_append);
396 TEST_RUN(basename, test_buffer_append_slice);
397 TEST_RUN(basename, test_buffer_append_fmt);
398 TEST_RUN(basename, test_buffer_prepend);
399 TEST_RUN(basename, test_buffer_push_byte);
400 TEST_RUN(basename, test_buffer_trim_byte);
401 TEST_RUN(basename, test_buffer_reset);
402 TEST_RUN(basename, test_buffer_freeze);
403 TEST_RUN(basename, test_buffer_copy);
404 TEST_RUN(basename, test_buffer_join);
405 TEST_RUN(basename, test_buffer_contains);
406 TEST_RUN(basename, test_buffer_match);
407 TEST_RUN(basename, test_buffer_has_prefix);
408 TEST_RUN(basename, test_buffer_subst);
409 TEST_RUN(basename, test_buffer_subst_empty_pattern);
410 TEST_RUN(basename, test_buffer_escape);
411 TEST_RUN(basename, test_str_eq_slice);
412 TEST_RUN(basename, test_span_contains);
413 TEST_RUN(basename, test_buffer_fputs_nonempty);
414 TEST_RUN(basename, test_buffer_fputs_empty);
415
416 return EXIT_SUCCESS;
417 }
418