The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
sbuff_tests.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Tests for a generic string buffer structure for string printing and parsing
18 *
19 * @file src/lib/util/test//sbuff_tests.c
20 *
21 * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22 */
23#include "acutest.h"
24#include"acutest_helpers.h"
25
26#include <freeradius-devel/util/sbuff.h>
27
28#define TEST_SBUFF_LEN(_sbuff, _num) \
29do { \
30 size_t _len; \
31 _len = talloc_array_length((_sbuff)->buff); \
32 TEST_CHECK(_len == (size_t)_num); \
33 TEST_MSG("Expected length : %zu", (size_t)_num); \
34 TEST_MSG("Got length : %zu", _len); \
35} while(0)
36
37#define TEST_SBUFF_USED(_sbuff, _num) \
38do { \
39 size_t _len; \
40 _len = fr_sbuff_used(_sbuff); \
41 TEST_CHECK(_len == (size_t)_num); \
42 TEST_MSG("Expected length : %zu", (size_t)_num); \
43 TEST_MSG("Got length : %zu", _len); \
44} while(0)
45
46static void test_parse_init(void)
47{
48 char const in[] = "i am a test string";
49 fr_sbuff_t sbuff;
50
51 TEST_CASE("Parse init with size");
52 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
53
54 TEST_CHECK(sbuff.start == in);
55 TEST_CHECK(sbuff.p == in);
56 TEST_CHECK(sbuff.end == in + (sizeof(in) - 1));
57
58 TEST_CASE("Parse init with end");
59 fr_sbuff_init_in(&sbuff, in, in + strlen(in));
60
61 TEST_CHECK(sbuff.start == in);
62 TEST_CHECK(sbuff.p == in);
63 TEST_CHECK(sbuff.end == in + strlen(in));
64
65 TEST_CASE("Parse init with const end");
66 fr_sbuff_init_in(&sbuff, in, (char const *)(in + strlen(in)));
67
68 TEST_CHECK(sbuff.start == in);
69 TEST_CHECK(sbuff.p == in);
70 TEST_CHECK(sbuff.end == in + strlen(in));
71}
72
73static void test_is_char(void)
74{
75 char const in[] = "i am a test string";
76 fr_sbuff_t sbuff;
77 fr_sbuff_marker_t marker;
78
79 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
80 TEST_CHECK(fr_sbuff_is_char(&sbuff, 'i'));
81 TEST_CHECK(!fr_sbuff_is_char(&sbuff, 'z'));
82
83 fr_sbuff_advance(&sbuff, 2);
84 TEST_CHECK(!fr_sbuff_is_char(&sbuff, 'i'));
85 TEST_CHECK(fr_sbuff_is_char(&sbuff, 'a'));
86
87 fr_sbuff_advance(&sbuff, 15);
88 TEST_CHECK(fr_sbuff_is_char(&sbuff, 'g'));
89 fr_sbuff_marker(&marker, &sbuff);
90 TEST_CHECK(fr_sbuff_is_char(&marker, 'g'));
91
92 /*
93 * Ensure that after advancing the buffer past
94 * the end, the marker can still be correctly
95 * tested
96 */
97 fr_sbuff_advance(&sbuff, 1);
98 TEST_CHECK(!fr_sbuff_is_char(&sbuff, 'g'));
99 TEST_CHECK(fr_sbuff_is_char(&marker, 'g'));
100}
101
102static void test_bstrncpy_exact(void)
103{
104 char const in[] = "i am a test string";
105 char const in_long[] = "i am a longer test string";
106 char out[18 + 1] = "";
107 fr_sbuff_t sbuff;
108 ssize_t slen;
109
110 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
111
112 TEST_CASE("Copy 5 bytes to out");
113 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 5);
114 TEST_CHECK_SLEN_RETURN(slen, 5);
115 TEST_CHECK_STRCMP(out, "i am ");
116 TEST_CHECK_STRCMP(sbuff.p, "a test string");
117
118 TEST_CASE("Copy 13 bytes to out");
119 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 13);
120 TEST_CHECK_SLEN(slen, 13);
121 TEST_CHECK_STRCMP(out, "a test string");
122 TEST_CHECK_STRCMP(sbuff.p, "");
123 TEST_CHECK(sbuff.p == sbuff.end);
124
125 TEST_CASE("Copy would overrun input");
126 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 1);
127 TEST_CHECK_SLEN(slen, 0);
128 TEST_CHECK(sbuff.p == sbuff.end);
129
130 TEST_CASE("Copy would overrun output (and SIZE_MAX special value)");
131 fr_sbuff_init_in(&sbuff, in_long, sizeof(in_long) - 1);
132
133 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX);
134 TEST_CHECK_SLEN(slen, -7);
135 TEST_CHECK(sbuff.p == sbuff.start);
136
137 TEST_CASE("Zero length output buffer");
138 fr_sbuff_set_to_start(&sbuff);
139 out[0] = 'a';
140 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, (size_t)1), &sbuff, SIZE_MAX);
141 TEST_CHECK_SLEN(slen, -25);
142 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
143 TEST_CHECK(sbuff.p == sbuff.start);
144
145 TEST_CASE("Zero length size");
146 fr_sbuff_set_to_start(&sbuff);
147 out[0] = 'a';
148 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, (size_t)1), &sbuff, 0);
149 TEST_CHECK_SLEN(slen, 0);
150 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
151 TEST_CHECK(sbuff.p == sbuff.start);
152}
153
154static void test_bstrncpy(void)
155{
156 char const in[] = "i am a test string";
157 char const in_long[] = "i am a longer test string";
158 char out[18 + 1] = "";
159 fr_sbuff_t sbuff;
160 ssize_t slen;
161
162 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
163
164 TEST_CASE("Copy 5 bytes to out");
165 slen = fr_sbuff_out_bstrncpy(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 5);
166 TEST_CHECK_SLEN_RETURN(slen, 5);
167 TEST_CHECK_STRCMP(out, "i am ");
168 TEST_CHECK_STRCMP(sbuff.p, "a test string");
169
170 TEST_CASE("Copy 13 bytes to out");
171 slen = fr_sbuff_out_bstrncpy(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 13);
172 TEST_CHECK_SLEN(slen, 13);
173 TEST_CHECK_STRCMP(out, "a test string");
174 TEST_CHECK_STRCMP(sbuff.p, "");
175 TEST_CHECK(sbuff.p == sbuff.end);
176
177 TEST_CASE("Copy would overrun input");
178 slen = fr_sbuff_out_bstrncpy(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 1);
179 TEST_CHECK_SLEN(slen, 0);
180 TEST_CHECK(sbuff.p == sbuff.end);
181
182 TEST_CASE("Copy would overrun output (and SIZE_MAX special value)");
183 fr_sbuff_init_in(&sbuff, in_long, sizeof(in_long) - 1);
184
185 slen = fr_sbuff_out_bstrncpy(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX);
186 TEST_CHECK_SLEN(slen, 18);
187 TEST_CHECK_STRCMP(out, "i am a longer test");
188
189 TEST_CASE("Zero length output buffer");
190 fr_sbuff_set_to_start(&sbuff);
191 out[0] = 'a';
192 slen = fr_sbuff_out_bstrncpy(&FR_SBUFF_OUT(out, (size_t)1), &sbuff, SIZE_MAX);
193 TEST_CHECK_SLEN(slen, 0);
194 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
195 TEST_CHECK(sbuff.p == sbuff.start);
196
197 TEST_CASE("Zero length size");
198 fr_sbuff_set_to_start(&sbuff);
199 out[0] = 'a';
200 slen = fr_sbuff_out_bstrncpy(&FR_SBUFF_OUT(out, (size_t)1), &sbuff, 0);
201 TEST_CHECK_SLEN(slen, 0);
202 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
203 TEST_CHECK(sbuff.p == sbuff.start);
204}
205
207 ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
208 ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true,
209 ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true,
210 ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true,
211 ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true,
212 ['z'] = true, [' '] = true
213};
214
216 ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
217 ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true,
218 ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true,
219 ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = false,
220 ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true,
221 ['z'] = true, [' '] = true
222};
223
224static void test_bstrncpy_allowed(void)
225{
226 char const in[] = "i am a test string";
227 char const in_long[] = "i am a longer test string";
228 char out[18 + 1] = "";
229 fr_sbuff_t sbuff;
230 ssize_t slen;
231
232 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
233
234 /*
235 * Should behave identically to bstrncpy
236 * where there's no restrictions on char
237 * set.
238 */
239 TEST_CASE("Copy 5 bytes to out");
241 TEST_CHECK_SLEN_RETURN(slen, 5);
242 TEST_CHECK_STRCMP(out, "i am ");
243 TEST_CHECK_STRCMP(sbuff.p, "a test string");
244
245 TEST_CASE("Copy 13 bytes to out");
247 TEST_CHECK_SLEN(slen, 13);
248 TEST_CHECK_STRCMP(out, "a test string");
249 TEST_CHECK_STRCMP(sbuff.p, "");
250 TEST_CHECK(sbuff.p == sbuff.end);
251
252 TEST_CASE("Copy would overrun input");
254 TEST_CHECK_SLEN(slen, 0);
255 TEST_CHECK(sbuff.p == sbuff.end);
256
257 TEST_CASE("Copy would overrun output (and SIZE_MAX special value)");
258 fr_sbuff_init_in(&sbuff, in_long, sizeof(in_long));
259
260 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, allow_lowercase_and_space);
261 TEST_CHECK_SLEN(slen, 18);
262 TEST_CHECK_STRCMP(out, "i am a longer test");
263
264 TEST_CASE("Zero length output buffer");
265 fr_sbuff_set_to_start(&sbuff);
266 out[0] = 'a';
267 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, (size_t)1), &sbuff, SIZE_MAX, allow_lowercase_and_space);
268 TEST_CHECK_SLEN(slen, 0);
269 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
270 TEST_CHECK(sbuff.p == sbuff.start);
271
272 TEST_CASE("Zero length size");
273 fr_sbuff_set_to_start(&sbuff);
274 out[0] = 'a';
275 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, (size_t)1), &sbuff, SIZE_MAX, allow_lowercase_and_space);
276 TEST_CHECK_SLEN(slen, 0);
277 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
278 TEST_CHECK(sbuff.p == sbuff.start);
279
280 /*
281 * Check copy stops early
282 */
283 TEST_CASE("Copy until first t");
284 fr_sbuff_set_to_start(&sbuff);
285 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX,
287 TEST_CHECK_SLEN(slen, 14);
288 TEST_CHECK_STRCMP(out, "i am a longer ");
289
290 TEST_CASE("Copy until first t with length constraint (same len as token)");
291 fr_sbuff_set_to_start(&sbuff);
292 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, 15), &sbuff, SIZE_MAX,
294 TEST_CHECK_SLEN(slen, 14);
295 TEST_CHECK_STRCMP(out, "i am a longer ");
296
297 TEST_CASE("Copy until first t with length constraint (one shorter than token)");
298 fr_sbuff_set_to_start(&sbuff);
299 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, 14), &sbuff, SIZE_MAX,
301 TEST_CHECK_SLEN(slen, 13);
302 TEST_CHECK_STRCMP(out, "i am a longer");
303
304 TEST_CASE("Zero length token (should still be terminated)");
305 fr_sbuff_set_to_start(&sbuff);
306 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, 14), &sbuff, SIZE_MAX,
307 (bool[SBUFF_CHAR_CLASS]){});
308 TEST_CHECK_SLEN(slen, 0);
310}
311
312static void test_bstrncpy_until(void)
313{
314 char const in[] = "i am a test string";
315 char const in_long[] = "i am a longer test string";
316 char out[18 + 1];
317 fr_sbuff_t sbuff;
318 ssize_t slen = 0;
319
320 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
321
322 /*
323 * Should behave identically to bstrncpy
324 * where there's no restrictions on char
325 * set.
326 */
327 TEST_CASE("Copy 5 bytes to out");
328 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 5, NULL, NULL);
329 TEST_CHECK_SLEN_RETURN(slen, 5);
330 TEST_CHECK_STRCMP(out, "i am ");
331 TEST_CHECK_STRCMP(sbuff.p, "a test string");
332
333 TEST_CASE("Copy 13 bytes to out");
334 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 13, NULL, NULL);
335 TEST_CHECK_SLEN(slen, 13);
336 TEST_CHECK_STRCMP(out, "a test string");
337 TEST_CHECK_STRCMP(sbuff.p, "");
338 TEST_CHECK(sbuff.p == sbuff.end);
339
340 TEST_CASE("Copy would overrun input");
341 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 1, NULL, NULL);
342 TEST_CHECK_SLEN(slen, 0);
343 TEST_CHECK(sbuff.p == sbuff.end);
344
345 TEST_CASE("Check escapes");
346 fr_sbuff_set_to_start(&sbuff);
347 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX,
348 &FR_SBUFF_TERM("g"), &(fr_sbuff_unescape_rules_t){ .chr = 'n' });
349 TEST_CHECK_SLEN(slen, 18);
350 TEST_CHECK_STRCMP(out, "i am a test string");
351 TEST_CHECK_STRCMP(sbuff.p, "");
352
353 TEST_CASE("Copy would overrun output (and SIZE_MAX special value)");
354 fr_sbuff_init_in(&sbuff, in_long, sizeof(in_long) - 1);
355
356 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, NULL, NULL);
357 TEST_CHECK_SLEN(slen, 18);
358 TEST_CHECK_STRCMP(out, "i am a longer test");
359
360 TEST_CASE("Zero length output buffer");
361 fr_sbuff_set_to_start(&sbuff);
362 out[0] = 'a';
363 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, (size_t)1), &sbuff, SIZE_MAX, NULL, NULL);
364 TEST_CHECK_SLEN(slen, 0);
365 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
366 TEST_CHECK(sbuff.p == sbuff.start);
367
368 TEST_CASE("Zero length size");
369 fr_sbuff_set_to_start(&sbuff);
370 out[0] = 'a';
371 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 0, NULL, NULL);
372 TEST_CHECK_SLEN(slen, 0);
373 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
374 TEST_CHECK(sbuff.p == sbuff.start);
375
376 /*
377 * Check copy stops early
378 */
379 TEST_CASE("Copy until first t");
380 fr_sbuff_set_to_start(&sbuff);
381 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, &FR_SBUFF_TERM("t"), NULL);
382 TEST_CHECK_SLEN(slen, 14);
383 TEST_CHECK_STRCMP(out, "i am a longer ");
384
385 TEST_CASE("Copy until first t with length constraint (same len as token)");
386 fr_sbuff_set_to_start(&sbuff);
387 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, 15), &sbuff, SIZE_MAX, &FR_SBUFF_TERM("t"), NULL);
388 TEST_CHECK_SLEN(slen, 14);
389 TEST_CHECK_STRCMP(out, "i am a longer ");
390
391 TEST_CASE("Copy until first t with length constraint (one shorter than token)");
392 fr_sbuff_set_to_start(&sbuff);
393 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, 14), &sbuff, SIZE_MAX, &FR_SBUFF_TERM("t"), NULL);
394 TEST_CHECK_SLEN(slen, 13);
395 TEST_CHECK_STRCMP(out, "i am a longer");
396
397 TEST_CASE("Zero length token (should still be terminated)");
398 fr_sbuff_set_to_start(&sbuff);
399 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, 14), &sbuff, SIZE_MAX, &FR_SBUFF_TERM("i"), NULL);
400 TEST_CHECK_SLEN(slen, 0);
402}
403
404static void test_unescape_until(void)
405{
406 char const in[] = "i am a test string";
407 char const in_long[] = "i am a longer test string";
408 char const in_escapes[] = "i am a |t|est strin|g";
409 char const in_escapes_seq[] = "i |x|0am a |t|est strin|g|x20|040";
410 char out[18 + 1] = "";
411 char escape_out[20 + 1];
412
413 fr_sbuff_t sbuff;
414 ssize_t slen;
415
417 .chr = '\\'
418 };
419
420 fr_sbuff_unescape_rules_t pipe_rules = {
421 .chr = '|',
422 .subs = { ['g'] = 'g', ['|'] = '|' }
423 };
424
425 fr_sbuff_unescape_rules_t pipe_rules_sub = {
426 .chr = '|', .subs = { ['g'] = 'h', ['|'] = '|' }
427 };
428
429 fr_sbuff_unescape_rules_t pipe_rules_sub_hex = {
430 .chr = '|',
431 .subs = { ['g'] = 'h', ['|'] = '|' },
432 .do_hex = true
433 };
434
435 fr_sbuff_unescape_rules_t pipe_rules_sub_oct = {
436 .chr = '|',
437 .subs = { ['g'] = 'h', ['|'] = '|' },
438 .do_oct = true
439 };
440
441 fr_sbuff_unescape_rules_t pipe_rules_both = {
442 .chr = '|',
443 .subs = { ['g'] = 'h', ['|'] = '|' },
444 .do_hex = true,
445 .do_oct = true
446 };
447
448 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
449 /*
450 * Should behave identically to bstrncpy
451 * where there's no restrictions on char
452 * set.
453 */
454 TEST_CASE("Copy 5 bytes to out");
455 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 5, NULL, &rules);
456 TEST_CHECK_SLEN_RETURN(slen, 5);
457 TEST_CHECK_STRCMP(out, "i am ");
458 TEST_CHECK_STRCMP(sbuff.p, "a test string");
459
460 TEST_CASE("Copy 13 bytes to out");
461 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 13, NULL, &rules);
462 TEST_CHECK_SLEN(slen, 13);
463 TEST_CHECK_STRCMP(out, "a test string");
464 TEST_CHECK_STRCMP(sbuff.p, "");
465 TEST_CHECK(sbuff.p == sbuff.end);
466
467 TEST_CASE("Copy would overrun input");
468 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 1, NULL, &rules);
469 TEST_CHECK_SLEN(slen, 0);
470 TEST_CHECK(sbuff.p == sbuff.end);
471
472 TEST_CASE("Copy would overrun output (and SIZE_MAX special value)");
473 fr_sbuff_init_in(&sbuff, in_long, sizeof(in_long) - 1);
474
475 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, NULL, &rules);
476 TEST_CHECK_SLEN(slen, 18);
477 TEST_CHECK_STRCMP(out, "i am a longer test");
478
479 TEST_CASE("Zero length output buffer");
480 fr_sbuff_set_to_start(&sbuff);
481 out[0] = 'a';
482 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, (size_t)1), &sbuff, SIZE_MAX, NULL, &rules);
483 TEST_CHECK_SLEN(slen, 0);
484 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
485 TEST_CHECK(sbuff.p == sbuff.start);
486
487 TEST_CASE("Zero length size");
488 fr_sbuff_set_to_start(&sbuff);
489 out[0] = 'a';
490 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, 0, NULL, &rules);
491 TEST_CHECK_SLEN(slen, 0);
492 TEST_CHECK(out[0] == '\0'); /* should be set to \0 */
493 TEST_CHECK(sbuff.p == sbuff.start);
494
495 /*
496 * Check copy stops early
497 */
498 TEST_CASE("Copy until first t");
499 fr_sbuff_set_to_start(&sbuff);
500 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX,
501 &FR_SBUFF_TERM("t"), &rules);
502 TEST_CHECK_SLEN(slen, 14);
503 TEST_CHECK_STRCMP(out, "i am a longer ");
504
505 TEST_CASE("Copy until first t with length constraint (same len as token)");
506 fr_sbuff_set_to_start(&sbuff);
507 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, 15), &sbuff, SIZE_MAX,
508 &FR_SBUFF_TERM("t"), &rules);
509 TEST_CHECK_SLEN(slen, 14);
510 TEST_CHECK_STRCMP(out, "i am a longer ");
511
512 TEST_CASE("Copy until first t with length constraint (one shorter than token)");
513 fr_sbuff_set_to_start(&sbuff);
514 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, 14), &sbuff, SIZE_MAX,
515 &FR_SBUFF_TERM("t"), &rules);
516 TEST_CHECK_SLEN(slen, 13);
517 TEST_CHECK_STRCMP(out, "i am a longer");
518
519 TEST_CASE("Zero length token (should still be terminated)");
520 fr_sbuff_set_to_start(&sbuff);
521 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(out, 14), &sbuff, SIZE_MAX,
522 &FR_SBUFF_TERM("i"), &rules);
523 TEST_CHECK_SLEN(slen, 0);
525
526 /*
527 * Escapes and substitution
528 */
529 TEST_CASE("Escape with substitution to same char");
530 fr_sbuff_init_in(&sbuff, in_escapes, sizeof(in_escapes) - 1);
531 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(escape_out, sizeof(escape_out)), &sbuff, SIZE_MAX,
532 &FR_SBUFF_TERM("g"), &pipe_rules);
533 TEST_CHECK_SLEN_RETURN(slen, 20);
534 TEST_CHECK_STRCMP(escape_out, "i am a |t|est string");
535 TEST_CHECK_STRCMP(sbuff.p, "");
536
537 TEST_CASE("Escape with substitution to different char");
538 fr_sbuff_init_in(&sbuff, in_escapes, sizeof(in_escapes) - 1);
539 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(escape_out, sizeof(escape_out)), &sbuff, SIZE_MAX,
540 &FR_SBUFF_TERM("g"), &pipe_rules_sub);
541 TEST_CHECK_SLEN(slen, 20);
542 TEST_CHECK_STRCMP(escape_out, "i am a |t|est strinh");
543 TEST_CHECK_STRCMP(sbuff.p, "");
544
545 {
546 char tmp_out[24 + 1];
547
548 TEST_CASE("Escape with hex substitutions (insufficient output space)");
549 fr_sbuff_init_in(&sbuff, in_escapes_seq, sizeof(in_escapes_seq) - 1);
550 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(tmp_out, sizeof(tmp_out)), &sbuff, SIZE_MAX,
551 &FR_SBUFF_TERM("g"), &pipe_rules_sub_hex);
552 TEST_CHECK_SLEN_RETURN(slen, 24);
553 TEST_CHECK_STRCMP(tmp_out, "i |x|0am a |t|est strinh");
554 TEST_CHECK_STRCMP(sbuff.p, "|x20|040");
555 }
556
557 {
558 char tmp_out[25 + 1];
559
560 TEST_CASE("Escape with hex substitutions (sufficient output space)");
561 fr_sbuff_init_in(&sbuff, in_escapes_seq, sizeof(in_escapes_seq) - 1);
562 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(tmp_out, sizeof(tmp_out)), &sbuff, SIZE_MAX,
563 &FR_SBUFF_TERM("g"), &pipe_rules_sub_hex);
564 TEST_CHECK_SLEN(slen, 25);
565 TEST_CHECK_STRCMP(tmp_out, "i |x|0am a |t|est strinh ");
566 TEST_CHECK_STRCMP(sbuff.p, "|040");
567 }
568
569 {
570 char tmp_out[28 + 1];
571
572 TEST_CASE("Escape with oct substitutions (insufficient output space)");
573 fr_sbuff_init_in(&sbuff, in_escapes_seq, sizeof(in_escapes_seq) - 1);
574 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(tmp_out, sizeof(tmp_out)), &sbuff, SIZE_MAX,
575 &FR_SBUFF_TERM("g"), &pipe_rules_sub_oct);
576 TEST_CHECK_SLEN(slen, 28);
577 TEST_CHECK_STRCMP(tmp_out, "i |x|0am a |t|est strinh|x20");
578 TEST_CHECK_STRCMP(sbuff.p, "|040");
579 }
580
581 {
582 char tmp_out[29 + 1];
583
584 TEST_CASE("Escape with oct substitutions (sufficient output space)");
585 fr_sbuff_init_in(&sbuff, in_escapes_seq, sizeof(in_escapes_seq) - 1);
586 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(tmp_out, sizeof(tmp_out)), &sbuff, SIZE_MAX,
587 &FR_SBUFF_TERM("g"), &pipe_rules_sub_oct);
588 TEST_CHECK_SLEN(slen, 29);
589 TEST_CHECK_STRCMP(tmp_out, "i |x|0am a |t|est strinh|x20 ");
590 TEST_CHECK_STRCMP(sbuff.p, "");
591 }
592
593 {
594 char tmp_out[26 + 1];
595
596 TEST_CASE("Escape with hex and oct substitutions (sufficient output space)");
597 fr_sbuff_init_in(&sbuff, in_escapes_seq, sizeof(in_escapes_seq) - 1);
598 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(tmp_out, sizeof(tmp_out)), &sbuff, SIZE_MAX,
599 &FR_SBUFF_TERM("g"), &pipe_rules_both);
600 TEST_CHECK_SLEN(slen, 26);
601 TEST_CHECK_STRCMP(tmp_out, "i |x|0am a |t|est strinh ");
602 TEST_CHECK_STRCMP(sbuff.p, "");
603 }
604
605 {
606 char tmp_out[2 + 1];
607 char const in_escapes_collapse[] = "||";
608
609 TEST_CASE("Collapse double escapes");
610 fr_sbuff_init_in(&sbuff, in_escapes_collapse, sizeof(in_escapes_collapse) - 1);
611 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(tmp_out, sizeof(tmp_out)),
612 &sbuff, SIZE_MAX, NULL, &pipe_rules);
613 TEST_CHECK_SLEN(slen, 1);
614 TEST_CHECK_STRCMP(tmp_out, "|");
615 TEST_CHECK_STRCMP(sbuff.p, "");
616 }
617
618 {
619 char in_escapes_collapse[] = "||foo||";
620
621 TEST_CASE("Collapse double escapes overlapping");
622 fr_sbuff_init_in(&sbuff, in_escapes_collapse, sizeof(in_escapes_collapse) - 1);
623 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(in_escapes_collapse, sizeof(in_escapes_collapse)),
624 &sbuff, SIZE_MAX, NULL, &pipe_rules);
625 TEST_CHECK_SLEN(slen, 5);
626 TEST_CHECK_STRCMP(in_escapes_collapse, "|foo|");
627 TEST_CHECK_STRCMP(sbuff.p, "");
628 }
629
630 {
631 char tmp_out[30 + 1];
632
633 fr_sbuff_unescape_rules_t double_quote_rules = {
634 .chr = '\\',
635 .subs = {
636 ['a'] = '\a',
637 ['b'] = '\b',
638 ['e'] = '\\',
639 ['n'] = '\n',
640 ['r'] = '\r',
641 ['t'] = '\t',
642 ['v'] = '\v',
643 ['\\'] = '\\',
644 ['"'] = '"' /* Quoting char */
645 },
646 .do_hex = true,
647 .do_oct = true
648 };
649
650 char const in_escapes_unit[] =
651 "0x01\\001"
652 "0x07\\007"
653 "0x0A\\n"
654 "0x0D\\r"
655 "\\\"\\\""
656 "0xb0"
657 "\\260\\xb0";
658
659 char const expected[] = {
660 '0', 'x', '0', '1', '\001',
661 '0', 'x', '0', '7', '\007',
662 '0', 'x', '0', 'A', '\n',
663 '0', 'x', '0', 'D', '\r',
664 '"', '"',
665 '0', 'x', 'b', '0',
666 '\260', '\xb0', '\0'
667 };
668
669 TEST_CASE("Check unit test test strings");
670 fr_sbuff_init_in(&sbuff, in_escapes_unit, sizeof(in_escapes_unit) - 1);
671 slen = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(tmp_out, sizeof(tmp_out)), &sbuff, SIZE_MAX,
672 NULL, &double_quote_rules);
673 TEST_CHECK_SLEN(slen, 28);
674 TEST_CHECK_STRCMP(tmp_out, expected);
675 TEST_CHECK_STRCMP(sbuff.p, "");
676 }
677
678 /*
679 * Verify dynamic allocation
680 */
681 {
682 char *buff;
683 size_t len;
684 char const in_zero[] = "";
685
686 len = fr_sbuff_out_aunescape_until(NULL, &buff, &FR_SBUFF_IN(in_zero, sizeof(in_zero) - 1), SIZE_MAX,
687 NULL, &pipe_rules);
688 TEST_CHECK_SLEN(len, 0);
689 talloc_get_type_abort(buff, char);
690 TEST_CHECK_SLEN(talloc_array_length(buff), 1);
692 }
693}
694
696{
697 char const in[] = "foo, bar, baz```";
698 fr_sbuff_t sbuff;
699 ssize_t slen = 0;
701 L(","),
702 L("```"),
703 L("bad"),
704 L("bar"),
705 L("boink"),
706 L("food"),
707 L("nyi")
708 );
709 char out[100];
710
711 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
712
713 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, &tt, NULL);
714 TEST_CHECK_SLEN_RETURN(slen, 3);
715 TEST_CHECK_STRCMP(out, "foo");
716
717 fr_sbuff_advance(&sbuff, 1);
718
719 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, &tt, NULL);
720 TEST_CHECK(slen == 1);
722
723 fr_sbuff_advance(&sbuff, 4);
724
725 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, &tt, NULL);
726 TEST_CHECK(slen == 4);
727 TEST_CHECK_STRCMP(out, " baz");
728}
729
730static void test_eof_terminal(void)
731{
732 char const in[] = "foo, bar";
733 fr_sbuff_t sbuff;
734 ssize_t slen = 0;
736 L(""),
737 L(","),
738 );
740 L(",")
741 );
742 char out[100];
743
744 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
745
746 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, &tt_eof, NULL);
747 TEST_CHECK_SLEN_RETURN(slen, 3);
748 TEST_CHECK_STRCMP(out, "foo");
749
750 fr_sbuff_advance(&sbuff, 1); /* Advance past comma */
751
752 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, &tt_eof, NULL);
753 TEST_CHECK_SLEN_RETURN(slen, 4);
754 TEST_CHECK_STRCMP(out, " bar");
755
756 TEST_CHECK(fr_sbuff_is_terminal(&sbuff, &tt_eof) == true);
757 TEST_CHECK(fr_sbuff_is_terminal(&sbuff, &tt) == false);
758}
759
760/*
761 * fr_sbuff_terminal_search() is called with a `p` that walks
762 * forward independently of in->p (see fr_sbuff_out_bstrncpy_until).
763 * `remaining` must be measured from `p`, not from `in->p` — otherwise
764 * memcmp() can read past in->end when matching a multi-byte terminal
765 * near the visible end of the buffer.
766 *
767 * The underlying C string is "abc}xyz" but the sbuff is initialised
768 * to only see the first 4 bytes ("abc}"). With a "}xyz" terminal,
769 * the (buggy) code would happily compare 4 bytes from p='}' against
770 * "}xyz" — reading the "xyz" tail past in->end and reporting a false
771 * match. The fix clamps the compare to (in->end - p) = 1 byte, so
772 * the partial-prefix match correctly falls through.
773 */
775{
776 char const in[] = "abc}xyz";
777 fr_sbuff_t sbuff;
779 L("}xyz")
780 );
781 char out[16];
782 ssize_t slen;
783
784 fr_sbuff_init_in(&sbuff, in, (size_t)4); /* Only "abc}" is visible */
785
786 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &sbuff, SIZE_MAX, &tt, NULL);
787
788 TEST_CHECK_SLEN(slen, 4);
789 TEST_CHECK_STRCMP(out, "abc}");
790}
791
792/*
793 * Regression: fr_sbuff_terminal_search() did the fast-path "idx[*p]"
794 * dereference before checking whether the buffer was fully consumed.
795 * When "p == in->end" (nothing left) "*p" is one byte past the usable
796 * buffer. For a non-NUL-terminated sbuff whose end sits on an
797 * allocation boundary that is a 1-byte over-read, which ASAN reports as
798 * a heap-buffer-overflow.
799 *
800 * A heap buffer sized exactly to its contents (no trailing '\0') is used
801 * so the byte past "end" lands in an ASAN redzone.
802 */
804{
805 size_t const len = 4;
806 char *buff = malloc(len); /* exactly len bytes, no NUL */
807 fr_sbuff_t sbuff;
809 L(","),
810 L("}"),
811 );
812
813 TEST_CHECK(buff != NULL);
814 if (!buff) return;
815 memcpy(buff, "abcd", len);
816
817 fr_sbuff_init_in(&sbuff, buff, len);
818 fr_sbuff_advance(&sbuff, len); /* Consume everything: in->p == in->end */
819
820 /*
821 * Must not read *p (one byte past the buffer). The sbuff is not
822 * extendable and '\0' is not a terminal, so this is simply "not a
823 * terminal".
824 */
825 TEST_CHECK(fr_sbuff_is_terminal(&sbuff, &tt) == false);
826
827 free(buff);
828}
829
830static void test_terminal_merge(void)
831{
832 size_t i;
834 L(""),
835 L("\t"),
836 L("\n"),
837 L("\r"),
838 L(" "),
839 L("!"),
840 L("%"),
841 L("&"),
842 L("*"),
843 L("+"),
844 L("-"),
845 L("/"),
846 L("<"),
847 L("="),
848 L(">"),
849 L("^"),
850 L("{"),
851 L("|"),
852 L("~")
853 );
855 L(""),
856 L(")"),
857 );
858
859 fr_sbuff_term_t expect =
861 L(""),
862 L("\t"),
863 L("\n"),
864 L("\r"),
865 L(" "),
866 L("!"),
867 L("%"),
868 L("&"),
869 L(")"),
870 L("*"),
871 L("+"),
872 L("-"),
873 L("/"),
874 L("<"),
875 L("="),
876 L(">"),
877 L("^"),
878 L("{"),
879 L("|"),
880 L("~")
881 );
882 fr_sbuff_term_t *result;
883
884 result = fr_sbuff_terminals_amerge(NULL, &a, &b);
885 TEST_CHECK_LEN(result->len, expect.len);
886
887 for (i = 0; i < result->len; i++) {
888 TEST_CHECK_STRCMP(result->elem[i].str, expect.elem[i].str);
889 }
890
891 talloc_free(result);
892}
893
894static void test_no_advance(void)
895{
896 char const *in = "i am a test string";
897 char out[18 + 1] = "";
898 fr_sbuff_t sbuff;
899 ssize_t slen;
900
901 fr_sbuff_init_in(&sbuff, in, strlen(in));
902
903 TEST_CASE("Copy 5 bytes to out - no advance");
904 TEST_CHECK(sbuff.p == sbuff.start);
905 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, sizeof(out)), &FR_SBUFF(&sbuff), 5);
906 TEST_CHECK_SLEN_RETURN(slen, 5);
907 TEST_CHECK(strcmp(out, "i am ") == 0);
908 TEST_CHECK(sbuff.p == sbuff.start);
909}
910
911static void test_talloc_extend(void)
912{
913 fr_sbuff_t sbuff;
915
916 TEST_CASE("Initial allocation");
917 TEST_CHECK(fr_sbuff_init_talloc(NULL, &sbuff, &tctx, 32, 50) == &sbuff);
918 TEST_SBUFF_USED(&sbuff, 0);
919 TEST_SBUFF_LEN(&sbuff, 33);
920
921 TEST_CASE("Trim to zero");
922 TEST_CHECK(fr_sbuff_trim_talloc(&sbuff, SIZE_MAX) == 0);
923 TEST_SBUFF_USED(&sbuff, 0);
924 TEST_SBUFF_LEN(&sbuff, 1);
925
926 TEST_CASE("Print string - Should realloc to init");
927 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "0123456789") == 10);
928 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "0123456789") == 0);
929 TEST_SBUFF_USED(&sbuff, 10);
930 TEST_SBUFF_LEN(&sbuff, 33);
931
932 TEST_CASE("Trim to strlen");
933 TEST_CHECK(fr_sbuff_trim_talloc(&sbuff, SIZE_MAX) == 0);
934 TEST_SBUFF_LEN(&sbuff, 11);
935
936 TEST_CASE("Print string - Should realloc to init");
937 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "0123456789") == 10);
938 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "01234567890123456789") == 0);
939 TEST_SBUFF_USED(&sbuff, 20);
940 TEST_SBUFF_LEN(&sbuff, 33);
941
942 TEST_CASE("Trim to strlen");
943 TEST_CHECK(fr_sbuff_trim_talloc(&sbuff, SIZE_MAX) == 0);
944 TEST_SBUFF_LEN(&sbuff, 21);
945
946 TEST_CASE("Print string - Should realloc to double buffer len");
947 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "012345678901234") == 15);
948 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "01234567890123456789012345678901234") == 0);
949 TEST_SBUFF_USED(&sbuff, 35);
950 TEST_SBUFF_LEN(&sbuff, 41);
951
952 TEST_CASE("Print string - Should only add a single char, should not extend the buffer");
953 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "A") == 1);
954 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "01234567890123456789012345678901234A") == 0);
955 TEST_SBUFF_USED(&sbuff, 36);
956 TEST_SBUFF_LEN(&sbuff, 41);
957
958 TEST_CASE("Print string - Use all available buffer data");
959 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "BCDE") == 4);
960 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "01234567890123456789012345678901234ABCDE") == 0);
961 TEST_SBUFF_USED(&sbuff, 40);
962 TEST_SBUFF_LEN(&sbuff, 41);
963
964 TEST_CASE("Print string - Add single char, should trigger doubling constrained by max");
965 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "F") == 1);
966 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "01234567890123456789012345678901234ABCDEF") == 0);
967 TEST_SBUFF_USED(&sbuff, 41);
968 TEST_SBUFF_LEN(&sbuff, 51);
969
970 TEST_CASE("Print string - Add data to take us up to max");
971 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "GHIJKLMNO") == 9);
972 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "01234567890123456789012345678901234ABCDEFGHIJKLMNO") == 0);
973 TEST_SBUFF_USED(&sbuff, 50);
974 TEST_SBUFF_LEN(&sbuff, 51);
975
976 TEST_CASE("Print string - Add single char, should fail");
977 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "P") == -1);
978 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "01234567890123456789012345678901234ABCDEFGHIJKLMNO") == 0);
979 TEST_SBUFF_USED(&sbuff, 50);
980 TEST_SBUFF_LEN(&sbuff, 51);
981
982 TEST_CASE("Trim to strlen (should be noop)");
983 TEST_CHECK(fr_sbuff_trim_talloc(&sbuff, SIZE_MAX) == 0);
984 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "01234567890123456789012345678901234ABCDEFGHIJKLMNO") == 0);
985 TEST_SBUFF_USED(&sbuff, 50);
986 TEST_SBUFF_LEN(&sbuff, 51);
987
988 talloc_free(sbuff.buff);
989}
990
992{
993 fr_sbuff_t sbuff;
995
996 TEST_CASE("Initial allocation");
997 TEST_CHECK(fr_sbuff_init_talloc(NULL, &sbuff, &tctx, 0, 50) == &sbuff);
998 TEST_SBUFF_USED(&sbuff, 0);
999 TEST_SBUFF_LEN(&sbuff, 1);
1000
1001 TEST_CASE("Print string - Should alloc one byte");
1002 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "A") == 1);
1003 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "A") == 0);
1004 TEST_SBUFF_USED(&sbuff, 1);
1005 TEST_SBUFF_LEN(&sbuff, 2);
1006
1007 TEST_CASE("Print string - Should alloc two bytes");
1008 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "BC") == 2);
1009 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "ABC") == 0);
1010 TEST_SBUFF_USED(&sbuff, 3);
1011 TEST_SBUFF_LEN(&sbuff, 4);
1012
1013 TEST_CASE("Print string - Should alloc three bytes");
1014 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "D") == 1);
1015 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff), "ABCD") == 0);
1016 TEST_SBUFF_USED(&sbuff, 4);
1017 TEST_SBUFF_LEN(&sbuff, 7);
1018
1019 talloc_free(sbuff.buff);
1020}
1021
1023{
1024 fr_sbuff_t sbuff_0, sbuff_1;
1026
1027 TEST_CASE("Initial allocation");
1028 TEST_CHECK(fr_sbuff_init_talloc(NULL, &sbuff_0, &tctx, 0, 50) == &sbuff_0);
1029 TEST_SBUFF_USED(&sbuff_0, 0);
1030 TEST_SBUFF_LEN(&sbuff_0, 1);
1031
1032 sbuff_1 = FR_SBUFF_BIND_CURRENT(&sbuff_0);
1033 TEST_CASE("Check sbuff_1 has extend fields set");
1034 TEST_CHECK(sbuff_0.extend == sbuff_1.extend);
1035 TEST_CHECK(sbuff_0.uctx == sbuff_1.uctx);
1036 TEST_CHECK(sbuff_1.parent == &sbuff_0);
1037 TEST_SBUFF_USED(&sbuff_1, 0);
1038 TEST_SBUFF_LEN(&sbuff_1, 1);
1039
1040 TEST_CASE("Print string - Should alloc one byte");
1041 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff_1, "A") == 1);
1042 TEST_CHECK(strcmp(fr_sbuff_start(&sbuff_1), "A") == 0);
1043 TEST_SBUFF_USED(&sbuff_0, 1);
1044 TEST_SBUFF_LEN(&sbuff_0, 2);
1045 TEST_SBUFF_USED(&sbuff_1, 1);
1046 TEST_SBUFF_LEN(&sbuff_1, 2);
1047
1048 TEST_CHECK(sbuff_0.start == sbuff_1.start);
1049 TEST_CHECK(sbuff_0.end == sbuff_1.end);
1050 TEST_CHECK(sbuff_0.p == sbuff_1.p);
1051
1052 talloc_free(sbuff_0.buff);
1053}
1054
1056{
1057 fr_sbuff_t sbuff_0, sbuff_1;
1058 fr_sbuff_marker_t marker_0, marker_1;
1060
1061 TEST_CASE("Initial allocation");
1062 TEST_CHECK(fr_sbuff_init_talloc(NULL, &sbuff_0, &tctx, 0, 50) == &sbuff_0);
1063 TEST_SBUFF_USED(&sbuff_0, 0);
1064 TEST_SBUFF_LEN(&sbuff_0, 1);
1065
1066 TEST_CASE("Print string - Should alloc one byte");
1067 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff_0, "A") == 1);
1068 TEST_CHECK_STRCMP(fr_sbuff_start(&sbuff_0), "A");
1069 TEST_SBUFF_USED(&sbuff_0, 1);
1070 TEST_SBUFF_LEN(&sbuff_0, 2);
1071
1072 fr_sbuff_marker(&marker_0, &sbuff_0);
1073 TEST_CHECK((marker_0.p - sbuff_0.start) == 1);
1074
1075 TEST_CASE("Print string - Ensure marker is updated");
1076 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff_0, "B") == 1);
1077 TEST_CHECK_STRCMP(fr_sbuff_start(&sbuff_0), "AB");
1078 TEST_SBUFF_USED(&sbuff_0, 2);
1079 TEST_SBUFF_LEN(&sbuff_0, 3);
1080 TEST_CHECK((marker_0.p - sbuff_0.start) == 1);
1081
1082 TEST_CASE("Print string - Copy sbuff");
1083 sbuff_1 = FR_SBUFF_BIND_CURRENT(&sbuff_0); /* Dup sbuff_0 */
1084 TEST_CHECK(sbuff_0.p == sbuff_1.start);
1085 fr_sbuff_marker(&marker_1, &sbuff_1);
1086
1087 TEST_CHECK((marker_1.p - sbuff_1.start) == 0);
1088 TEST_CHECK((marker_1.p - sbuff_0.start) == 2);
1089 TEST_CHECK(sbuff_0.p == sbuff_1.start);
1090
1091 TEST_CASE("Print string - Trigger re-alloc, ensure all pointers are updated");
1092 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff_1, "C") == 1);
1093 TEST_CHECK_STRCMP(fr_sbuff_start(&sbuff_1), "C");
1094 TEST_CHECK(sbuff_0.buff == sbuff_1.buff);
1095 TEST_CHECK(sbuff_0.p == sbuff_1.start + 1);
1096 TEST_CHECK((marker_1.p - sbuff_1.start) == 0);
1097 TEST_CHECK((marker_1.p - sbuff_0.start) == 2);
1098 TEST_SBUFF_USED(&sbuff_0, 3);
1099 TEST_SBUFF_LEN(&sbuff_0, 5);
1100
1101 talloc_free(sbuff_0.buff);
1102}
1103
1105{
1106 fr_sbuff_t sbuff;
1108
1109 TEST_CASE("Intermix shift and extend");
1110 TEST_CHECK(fr_sbuff_init_talloc(NULL, &sbuff, &tctx, 4, 8) == &sbuff);
1111 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "0123") == 4);
1112 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "5678") == 4);
1113 TEST_CHECK(fr_sbuff_shift(&sbuff, 4, false) == 4);
1114 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "AAAA") == 4);
1115 TEST_CHECK(fr_sbuff_shift(&sbuff, 8, false) == 8);
1116 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "BBBBBBBB") == 8);
1117
1118 talloc_free(sbuff.buff);
1119}
1120
1121static void test_file_extend(void)
1122{
1123 fr_sbuff_t sbuff;
1124 fr_sbuff_t our_sbuff, child_sbuff;
1126 FILE *fp;
1127 char buff[5];
1128 char out[24];
1129 char fbuff[24];
1130 const char PATTERN[] = "xyzzy";
1131#define PATTERN_LEN (sizeof(PATTERN) - 1)
1132 char *post_ws;
1133 ssize_t slen;
1134
1135 static_assert(sizeof(buff) >= PATTERN_LEN, "Buffer must be sufficiently large to hold the pattern");
1136 static_assert((sizeof(fbuff) % sizeof(buff)) > 0, "sizeof buff must not be a multiple of fbuff");
1137 static_assert((sizeof(fbuff) % sizeof(buff)) < PATTERN_LEN, "remainder of sizeof(fbuff)/sizeof(buff) must be less than sizeof pattern");
1138
1139 TEST_CASE("Initialization");
1140 memset(fbuff, ' ', sizeof(fbuff));
1141 memcpy(fbuff + sizeof(fbuff) - PATTERN_LEN, PATTERN, PATTERN_LEN);
1142
1143 fp = fmemopen(fbuff, sizeof(fbuff), "r");
1144#ifdef __clang_analyzer__
1145 if (fp == NULL) return;
1146#endif
1147
1148 TEST_CHECK(fp != NULL);
1149 TEST_CHECK(fr_sbuff_init_file(&sbuff, &fctx, buff, sizeof(buff), fp, 128) == &sbuff);
1150 our_sbuff = FR_SBUFF_BIND_CURRENT(&sbuff);
1151
1152 TEST_CASE("Advance past whitespace, which will require shift/extend");
1153 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&our_sbuff, SIZE_MAX, NULL), sizeof(fbuff) - PATTERN_LEN);
1154 TEST_CASE("Verify extend on unused child buffer");
1155 child_sbuff = FR_SBUFF(&our_sbuff);
1156 slen = fr_sbuff_extend_file(NULL, &child_sbuff, 0);
1157 TEST_CHECK_SLEN(slen, sizeof(fbuff) % PATTERN_LEN);
1158 TEST_CASE("Verify that we passed all and only whitespace");
1159 (void) fr_sbuff_out_abstrncpy(NULL, &post_ws, &our_sbuff, 24);
1160 TEST_CHECK_STRCMP(post_ws, PATTERN);
1161 talloc_free(post_ws);
1162 TEST_CASE("Verify parent buffer end");
1163 TEST_CHECK(sbuff.end == our_sbuff.end);
1164
1165 TEST_CASE("Verify that we do not read shifted buffer past eof");
1166 slen = fr_sbuff_out_bstrncpy(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX);
1167 TEST_CHECK_SLEN(slen, 0);
1168 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX);
1169 TEST_CHECK_SLEN(slen, 0);
1170 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX, NULL, NULL);
1171 TEST_CHECK_SLEN(slen, 0);
1172 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX, allow_lowercase_and_space);
1173 TEST_CHECK_SLEN(slen, 0);
1174
1175 fclose(fp);
1176
1177 TEST_CASE("Verify fr_sbuff_out_bstrncpy_until() extends from file properly");
1178 fp = fmemopen(fbuff, sizeof(fbuff), "r");
1179#ifdef __clang_analyzer__
1180 if (fp == NULL) return;
1181#endif
1182
1183 TEST_CHECK(fp != NULL);
1184 TEST_CHECK(fr_sbuff_init_file(&sbuff, &fctx, buff, sizeof(buff), fp, 128) == &sbuff);
1185 our_sbuff = FR_SBUFF_BIND_CURRENT(&sbuff);
1186 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX, &FR_SBUFF_TERM("x"), NULL);
1187 TEST_CHECK_SLEN(slen, sizeof(fbuff) - PATTERN_LEN);
1188
1189 fclose(fp);
1190}
1191
1192static void test_file_extend_max(void)
1193{
1194 fr_sbuff_t sbuff;
1196 FILE *fp;
1197 char buff[16];
1198 char fbuff[] = " xyzzy";
1199 char *post_ws;
1200
1201 TEST_CASE("Initialization");
1202 fp = fmemopen(fbuff, sizeof(fbuff) - 1, "r");
1203#ifdef __clang_analyzer__
1204 if (fp == NULL) return;
1205#endif
1206 TEST_CHECK(fp != NULL);
1207 TEST_CHECK(fr_sbuff_init_file(&sbuff, &fctx, buff, sizeof(buff), fp, sizeof(fbuff) - 8) == &sbuff);
1208
1209 TEST_CASE("Confirm that max stops us from seeing xyzzy");
1210 TEST_CHECK_SLEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), sizeof(fbuff) - 8);
1211 TEST_CHECK_SLEN(fr_sbuff_out_abstrncpy(NULL, &post_ws, &sbuff, 24), 0);
1212 TEST_CHECK_STRCMP(post_ws, "");
1213 talloc_free(post_ws);
1214 fclose(fp);
1215}
1216
1217static void test_adv_past_str(void)
1218{
1219 fr_sbuff_t sbuff;
1220 char const in[] = "i am a test string";
1221
1222 TEST_CASE("Check for token at beginning of string");
1223 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1224 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, "i am a", SIZE_MAX), 6);
1225 TEST_CHECK_STRCMP(sbuff.p, " test string");
1226
1227 TEST_CASE("Check for token not at beginning of string");
1228 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1229 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, " am a", SIZE_MAX), 0);
1230 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1231
1232 TEST_CASE("Check for token larger than the string");
1233 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1234 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, "i am a test string ", SIZE_MAX), 0);
1235 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1236
1237 TEST_CASE("Check for token with zero length string");
1238 fr_sbuff_init_in(&sbuff, in, 0);
1239 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, "i am a", SIZE_MAX), 0);
1240
1241 TEST_CASE("Check for token that is the string");
1242 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1243 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, "i am a test string", SIZE_MAX), 18);
1244 TEST_CHECK_STRCMP(sbuff.p, "");
1245 TEST_CHECK(sbuff.p == sbuff.end);
1246}
1247
1248static void test_adv_past_strcase(void)
1249{
1250 fr_sbuff_t sbuff;
1251 char const in[] = "i am a test string";
1252
1253 TEST_CASE("Check for token at beginning of string");
1254 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1255 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, "i AM a", SIZE_MAX), 6);
1256 TEST_CHECK_STRCMP(sbuff.p, " test string");
1257
1258 TEST_CASE("Check for token not at beginning of string");
1259 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1260 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, " AM a", SIZE_MAX), 0);
1261 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1262
1263 TEST_CASE("Check for token larger than the string");
1264 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1265 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, "i AM a TEST string ", SIZE_MAX), 0);
1266 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1267
1268 TEST_CASE("Check for token with zero length string");
1269 fr_sbuff_init_in(&sbuff, in, 0);
1270 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, "i AM a", SIZE_MAX), 0);
1271
1272 TEST_CASE("Check for token that is the string");
1273 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1274 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, "i AM a TEST string", SIZE_MAX), 18);
1275 TEST_CHECK_STRCMP(sbuff.p, "");
1276 TEST_CHECK(sbuff.p == sbuff.end);
1277}
1278
1280{
1281 fr_sbuff_t sbuff;
1282 char const in[] = " i am a test string";
1283 char const in_ns[] = "i am a test string";
1284 char const in_ws[] = " ";
1285
1286 TEST_CASE("Check for token at beginning of string");
1287 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1288 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), 5);
1289 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1290
1291 TEST_CASE("Check for token not at beginning of string");
1292 fr_sbuff_init_in(&sbuff, in_ns, sizeof(in_ns) - 1);
1293 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), 0);
1294 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1295
1296 TEST_CASE("Check for token with zero length string");
1297 fr_sbuff_init_in(&sbuff, in, 0);
1298 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), 0);
1299
1300 TEST_CASE("Check for token that is the string");
1301 fr_sbuff_init_in(&sbuff, in_ws, sizeof(in_ws) - 1);
1302 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), 5);
1303
1304 TEST_CASE("Length constraint with token match");
1305 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1306 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, 2, NULL), 2);
1307 TEST_CHECK_STRCMP(sbuff.p, " i am a test string");
1308
1309 TEST_CASE("Length constraint without token match");
1310 fr_sbuff_init_in(&sbuff, in_ns, sizeof(in_ns) - 1);
1311 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, 2, NULL), 0);
1312 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1313}
1314
1315static void test_adv_past_allowed(void)
1316{
1317 fr_sbuff_t sbuff;
1318 char const in[] = " i am a test string";
1319 char const in_ns[] = "i am a test string";
1320 char const in_ws[] = " ";
1321
1322 TEST_CASE("Check for token at beginning of string");
1323 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1324 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, SIZE_MAX, (bool[SBUFF_CHAR_CLASS]){ [' '] = true }, NULL), 5);
1325 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1326
1327 TEST_CASE("Check for token not at beginning of string");
1328 fr_sbuff_init_in(&sbuff, in_ns, sizeof(in_ns) - 1);
1329 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, SIZE_MAX, (bool[SBUFF_CHAR_CLASS]){ [' '] = true }, NULL), 0);
1330 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1331
1332 TEST_CASE("Check for token with zero length string");
1333 fr_sbuff_init_in(&sbuff, in, 0);
1334 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, SIZE_MAX, (bool[SBUFF_CHAR_CLASS]){ [' '] = true }, NULL), 0);
1335 TEST_CHECK(sbuff.p == sbuff.start);
1336
1337 TEST_CASE("Check for token at the end of the string");
1338 fr_sbuff_init_in(&sbuff, in_ws, sizeof(in_ws) - 1);
1339 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, SIZE_MAX, (bool[SBUFF_CHAR_CLASS]){ [' '] = true }, NULL), 5);
1340 TEST_CHECK(sbuff.p == sbuff.end);
1341
1342 TEST_CASE("Length constraint with token match");
1343 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1344 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, 2, (bool[SBUFF_CHAR_CLASS]){ [' '] = true }, NULL), 2);
1345 TEST_CHECK_STRCMP(sbuff.p, " i am a test string");
1346
1347 TEST_CASE("Length constraint with token match");
1348 fr_sbuff_init_in(&sbuff, in_ns, sizeof(in_ns) - 1);
1349 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, 2, (bool[SBUFF_CHAR_CLASS]){ [' '] = true }, NULL), 0);
1350 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1351}
1352
1353static void test_adv_until(void)
1354{
1355 fr_sbuff_t sbuff;
1356 char const in[] = " abcdefgh ijklmnopp";
1357
1358 TEST_CASE("Check for token at beginning of string");
1359 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1360 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM(" "), '\0'), 0);
1361 TEST_CHECK_STRCMP(sbuff.p, " abcdefgh ijklmnopp");
1362
1363 TEST_CASE("Check for token not at beginning of string");
1364 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1365 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM("a"), '\0'), 1);
1366 TEST_CHECK_STRCMP(sbuff.p, "abcdefgh ijklmnopp");
1367
1368 TEST_CASE("Check for token with zero length string");
1369 fr_sbuff_init_in(&sbuff, in, 0);
1370 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM("a"), '\0'), 0);
1371 TEST_CHECK(sbuff.p == sbuff.start);
1372
1373 TEST_CASE("Check for token that is not in the string");
1374 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1375 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM("|"), '\0'), 19);
1376 TEST_CHECK(sbuff.p == sbuff.end);
1377
1378 TEST_CASE("Check escapes");
1379 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1380 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM("p"), 'o'), 18);
1381 TEST_CHECK_STRCMP(sbuff.p, "p");
1382
1383 TEST_CASE("Check for token that is not in the string with length constraint");
1384 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1385 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, 5, &FR_SBUFF_TERM("|"), '\0'), 5);
1386 TEST_CHECK(sbuff.p == (sbuff.start + 5));
1387}
1388
1389static void test_adv_to_utf8(void)
1390{
1391 fr_sbuff_t sbuff;
1392 char const in[] = "🥺🥺🥺🥺🍪😀";
1393 char *p;
1394
1395 TEST_CASE("Check for token at beginning of string");
1396 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1397 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "🥺");
1398 TEST_CHECK(p == sbuff.p);
1399 TEST_CHECK_STRCMP(sbuff.p, "🥺🥺🥺🥺🍪😀");
1400
1401 TEST_CASE("Check for token not at beginning of string");
1402 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1403 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "🍪");
1404 TEST_CHECK(p == (sbuff.start + (sizeof("🥺🥺🥺🥺") - 1)));
1405 TEST_CHECK_STRCMP(p, "🍪😀");
1406
1407 TEST_CASE("Check for token with zero length string");
1408 fr_sbuff_init_in(&sbuff, in, 0);
1409 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "🍪");
1410 TEST_CHECK(p == NULL);
1411 TEST_CHECK(sbuff.start == sbuff.p);
1412
1413 TEST_CASE("Check for token at the end of the string");
1414 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1415 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "😀");
1416 TEST_CHECK(p == sbuff.start + (sizeof("🥺🥺🥺🥺🍪") - 1));
1417
1418 TEST_CASE("Check for token not in the string");
1419 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1420 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "🍆 ");
1421 TEST_CHECK(p == NULL);
1422
1423 TEST_CASE("Check for token at the end of the string within len constraints");
1424 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1425 p = fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 1), "😀");
1426 TEST_CHECK(p == sbuff.start + (sizeof("🥺🥺🥺🥺🍪") - 1));
1427
1428 TEST_CASE("Check for token at the end of the string outside len constraints #1");
1429 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1430 TEST_CHECK(!fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 2), "😀"));
1431 TEST_CHECK(sbuff.p == sbuff.start);
1432
1433 TEST_CASE("Check for token at the end of the string outside len constraints #2");
1434 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1435 TEST_CHECK(!fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 3), "😀"));
1436 TEST_CHECK(sbuff.p == sbuff.start);
1437
1438 TEST_CASE("Check for token at the end of the string outside len constraints #3");
1439 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1440 TEST_CHECK(!fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 4), "😀"));
1441 TEST_CHECK(sbuff.p == sbuff.start);
1442
1443 TEST_CASE("Check for token at the end of the string outside len constraints #4");
1444 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1445 TEST_CHECK(!fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 5), "😀"));
1446 TEST_CHECK(sbuff.p == sbuff.start);
1447}
1448
1449static void test_adv_to_chr(void)
1450{
1451 fr_sbuff_t sbuff;
1452 char const in[] = "AAAAbC";
1453 char *p;
1454
1455 TEST_CASE("Check for token at beginning of string");
1456 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1457 p = fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'A');
1458 TEST_CHECK(p == sbuff.p);
1459 TEST_CHECK_STRCMP(sbuff.p, "AAAAbC");
1460
1461 TEST_CASE("Check for token not at beginning of string");
1462 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1463 p = fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'b');
1464 TEST_CHECK(p == (sbuff.start + (sizeof("AAAA") - 1)));
1465 TEST_CHECK_STRCMP(p, "bC");
1466
1467 TEST_CASE("Check for token with zero length string");
1468 fr_sbuff_init_in(&sbuff, in, 0);
1469 TEST_CHECK(!fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'b'));
1470 TEST_CHECK(sbuff.start == sbuff.p);
1471
1472 TEST_CASE("Check for token at the end of the string");
1473 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1474 p = fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'C');
1475 TEST_CHECK(p == sbuff.start + (sizeof("AAAAb") - 1));
1476
1477 TEST_CASE("Check for token not in the string");
1478 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1479 p = fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'D');
1480 TEST_CHECK(p == NULL);
1481
1482 TEST_CASE("Check for token not at beginning of string within length constraints");
1483 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1484 p = fr_sbuff_adv_to_chr(&sbuff, 5, 'b');
1485 TEST_CHECK(p == (sbuff.start + (sizeof("AAAA") - 1)));
1486 TEST_CHECK_STRCMP(p, "bC");
1487
1488 TEST_CASE("Check for token not at beginning of string outside length constraints");
1489 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1490 TEST_CHECK(!fr_sbuff_adv_to_chr(&sbuff, 4, 'b'));
1491 TEST_CHECK(sbuff.p == sbuff.start);
1492}
1493
1494static void test_adv_to_str(void)
1495{
1496 fr_sbuff_t sbuff;
1497 char const in[] = "i am a test string";
1498 char *p;
1499
1500 TEST_CASE("Check for token at beginning of string");
1501 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1502 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "i am a test", SIZE_MAX);
1503 TEST_CHECK(sbuff.p == p);
1504 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1505
1506 TEST_CASE("Check for token not at beginning of string");
1507 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1508 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "test", SIZE_MAX);
1509 TEST_CHECK(sbuff.p == p);
1510 TEST_CHECK_STRCMP(sbuff.p, "test string");
1511
1512 TEST_CASE("Check for token at the end of string");
1513 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1514 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "ing", SIZE_MAX);
1515 TEST_CHECK(sbuff.p == p);
1516 TEST_CHECK_STRCMP(sbuff.p, "ing");
1517
1518 TEST_CASE("Check for token larger than the string");
1519 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1520 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "i am a test string ", SIZE_MAX);
1521 TEST_CHECK(sbuff.p == sbuff.start);
1522 TEST_CHECK(p == NULL);
1523
1524 TEST_CASE("Check for token shorter than string, not in the string");
1525 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1526 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "ng ", SIZE_MAX);
1527 TEST_CHECK(sbuff.p == sbuff.start);
1528 TEST_CHECK(p == NULL);
1529
1530 TEST_CASE("Check for token with zero length string");
1531 fr_sbuff_init_in(&sbuff, in, 0);
1532 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "i am a", SIZE_MAX);
1533 TEST_CHECK(sbuff.p == sbuff.start);
1534 TEST_CHECK(p == NULL);
1535
1536 TEST_CASE("Check for token that is the string");
1537 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1538 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "i am a test string", SIZE_MAX);
1539 TEST_CHECK(sbuff.p == sbuff.start);
1540 TEST_CHECK(sbuff.p == p);
1541 TEST_CHECK_STRCMP(p, "i am a test string");
1542
1543 TEST_CASE("Check for token not at beginning of string within length constraints");
1544 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1545 p = fr_sbuff_adv_to_str(&sbuff, 11, "test", SIZE_MAX);
1546 TEST_CHECK(sbuff.p == p);
1547 TEST_CHECK_STRCMP(sbuff.p, "test string");
1548
1549 TEST_CASE("Check for token not at beginning of string outside length constraints");
1550 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1551 TEST_CHECK(!fr_sbuff_adv_to_str(&sbuff, 10, "test", SIZE_MAX));
1552 TEST_CHECK(sbuff.p == sbuff.start);
1553}
1554
1555static void test_adv_to_strcase(void)
1556{
1557 fr_sbuff_t sbuff;
1558 char const in[] = "i am a test string";
1559 char *p;
1560
1561 TEST_CASE("Check for token at beginning of string");
1562 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1563 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "i AM a TEST", SIZE_MAX);
1564 TEST_CHECK(sbuff.p == p);
1565 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1566
1567 TEST_CASE("Check for token not at beginning of string");
1568 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1569 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "tEst", SIZE_MAX);
1570 TEST_CHECK(sbuff.p == p);
1571 TEST_CHECK_STRCMP(sbuff.p, "test string");
1572
1573 TEST_CASE("Check for token at the end of string");
1574 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1575 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "Ing", SIZE_MAX);
1576 TEST_CHECK(sbuff.p == p);
1577 TEST_CHECK_STRCMP(sbuff.p, "ing");
1578
1579 TEST_CASE("Check for token larger than the string");
1580 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1581 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "i aM a tEst stRIng ", SIZE_MAX);
1582 TEST_CHECK(sbuff.p == sbuff.start);
1583 TEST_CHECK(p == NULL);
1584
1585 TEST_CASE("Check for token shorter than string, not in the string");
1586 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1587 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "nG ", SIZE_MAX);
1588 TEST_CHECK(sbuff.p == sbuff.start);
1589 TEST_CHECK(p == NULL);
1590
1591 TEST_CASE("Check for token with zero length string");
1592 fr_sbuff_init_in(&sbuff, in, 0);
1593 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "i AM a", SIZE_MAX);
1594 TEST_CHECK(sbuff.p == sbuff.start);
1595 TEST_CHECK(p == NULL);
1596
1597 TEST_CASE("Check for token that is the string");
1598 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1599 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "i AM a teST stRIng", SIZE_MAX);
1600 TEST_CHECK(sbuff.p == sbuff.start);
1601 TEST_CHECK(sbuff.p == p);
1602 TEST_CHECK_STRCMP(p, "i am a test string");
1603
1604 TEST_CASE("Check for token not at beginning of string within length constraints");
1605 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1606 p = fr_sbuff_adv_to_strcase(&sbuff, 11, "tEst", SIZE_MAX);
1607 TEST_CHECK(sbuff.p == p);
1608 TEST_CHECK_STRCMP(sbuff.p, "test string");
1609
1610 TEST_CASE("Check for token not at beginning of string outside length constraints");
1611 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1612 TEST_CHECK(!fr_sbuff_adv_to_strcase(&sbuff, 10, "tEst", SIZE_MAX));
1613 TEST_CHECK(sbuff.p == sbuff.start);
1614}
1615
1616static void test_next_if_char(void)
1617{
1618 fr_sbuff_t sbuff;
1619 char const in[] = "i ";
1620
1621 TEST_CASE("Check for advancement on match");
1622 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1623 TEST_CHECK(fr_sbuff_next_if_char(&sbuff, 'i') == true);
1624 TEST_CHECK_STRCMP(sbuff.p, " ");
1625
1626 TEST_CASE("Check for non-advancement on non-match");
1627 TEST_CHECK(fr_sbuff_next_if_char(&sbuff, 'i') == false);
1628 TEST_CHECK_STRCMP(sbuff.p, " ");
1629
1630 TEST_CASE("Check for advancement at end");
1631 TEST_CHECK(fr_sbuff_next_if_char(&sbuff, ' ') == true);
1632 TEST_CHECK_STRCMP(sbuff.p, "");
1633
1634 TEST_CASE("Check we can't advance off the end of the buffer");
1635 TEST_CHECK(fr_sbuff_next_if_char(&sbuff, ' ') == false);
1636 TEST_CHECK_STRCMP(sbuff.p, "");
1637}
1638
1639static void test_next_unless_char(void)
1640{
1641 fr_sbuff_t sbuff;
1642 char const in[] = "i ";
1643
1644 TEST_CASE("Check for advancement on non-match");
1645 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1646 TEST_CHECK(fr_sbuff_next_unless_char(&sbuff, ' ') == true);
1647 TEST_CHECK_STRCMP(sbuff.p, " ");
1648
1649 TEST_CASE("Check for non-advancement on match");
1650 TEST_CHECK(fr_sbuff_next_unless_char(&sbuff, ' ') == false);
1651 TEST_CHECK_STRCMP(sbuff.p, " ");
1652
1653 TEST_CASE("Check for advancement at end");
1654 TEST_CHECK(fr_sbuff_next_unless_char(&sbuff, '_') == true);
1655 TEST_CHECK_STRCMP(sbuff.p, "");
1656
1657 TEST_CASE("Check we can't advance off the end of the buffer");
1658 TEST_CHECK(fr_sbuff_next_unless_char(&sbuff, '_') == false);
1659 TEST_CHECK_STRCMP(sbuff.p, "");
1660}
1661
1663 /*
1664 * Basic tests
1665 */
1666 { "fr_sbuff_init", test_parse_init },
1667 { "fr_sbuff_is_char", test_is_char },
1668 { "fr_sbuff_out_bstrncpy_exact", test_bstrncpy_exact },
1669 { "fr_sbuff_out_bstrncpy", test_bstrncpy },
1670 { "fr_sbuff_out_bstrncpy_allowed", test_bstrncpy_allowed },
1671 { "fr_sbuff_out_bstrncpy_until", test_bstrncpy_until },
1672 { "multi-char terminals", test_unescape_multi_char_terminals },
1673 { "fr_sbuff_out_unescape_until", test_unescape_until },
1674 { "fr_sbuff_terminal_eof", test_eof_terminal },
1675 { "terminal search past visible end", test_terminal_search_past_visible_end },
1676 { "terminal search at end no overrun", test_terminal_search_at_end_no_overrun },
1677 { "terminal merge", test_terminal_merge },
1678
1679 /*
1680 * Extending buffer
1681 */
1682 { "fr_sbuff_talloc_extend", test_talloc_extend },
1683 { "fr_sbuff_talloc_extend_init_zero", test_talloc_extend_init_zero },
1684 { "fr_sbuff_talloc_extend_multi_level", test_talloc_extend_multi_level },
1685 { "fr_sbuff_talloc_extend_with_marker", test_talloc_extend_with_marker },
1686 { "fr_sbuff_talloc_extend_with_shift", test_talloc_extend_with_shift},
1687 { "fr_sbuff_file_extend", test_file_extend },
1688 { "fr_sbuff_file_extend_max", test_file_extend_max },
1689
1690 { "fr_sbuff_no_advance", test_no_advance },
1691
1692 /*
1693 * Token skipping
1694 */
1695 { "fr_sbuff_adv_past_str", test_adv_past_str },
1696 { "fr_sbuff_adv_past_strcase", test_adv_past_strcase },
1697 { "fr_sbuff_adv_past_whitespace", test_adv_past_whitespace },
1698 { "fr_sbuff_adv_past_allowed", test_adv_past_allowed },
1699 { "fr_sbuff_adv_until", test_adv_until },
1700
1701 /*
1702 * Token searching
1703 */
1704 { "fr_sbuff_adv_to_utf8", test_adv_to_utf8 },
1705 { "fr_sbuff_adv_to_chr", test_adv_to_chr },
1706 { "fr_sbuff_adv_to_str", test_adv_to_str },
1707 { "fr_sbuff_adv_to_strcase", test_adv_to_strcase },
1708
1709 /*
1710 * Advancement
1711 */
1712 { "fr_sbuff_next_if_char", test_next_if_char },
1713 { "fr_sbuff_next_unless_char", test_next_unless_char },
1714
1716};
#define TEST_CHECK(cond)
Definition acutest.h:87
#define TEST_CASE(name)
Definition acutest.h:186
#define TEST_TERMINATOR
Definition acutest.h:64
#define TEST_CHECK_SLEN(_got, _exp)
#define TEST_CHECK_SLEN_RETURN(_got, _exp)
#define TEST_CHECK_LEN(_got, _exp)
#define TEST_CHECK_STRCMP(_got, _exp)
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
static fr_slen_t in
Definition dict.h:882
free(array)
talloc_free(hp)
size_t fr_sbuff_out_unescape_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
long int ssize_t
ssize_t fr_sbuff_out_bstrncpy_exact(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
size_t fr_sbuff_out_bstrncpy_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
size_t fr_sbuff_out_bstrncpy_allowed(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, bool const allowed[static SBUFF_CHAR_CLASS])
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static SBUFF_CHAR_CLASS], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
Definition sbuff.c:1867
int fr_sbuff_trim_talloc(fr_sbuff_t *sbuff, size_t len)
Trim a talloced sbuff to the minimum length required to represent the contained string.
Definition sbuff.c:433
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1471
char * fr_sbuff_adv_to_chr_utf8(fr_sbuff_t *sbuff, size_t len, char const *chr)
Wind position to first instance of specified multibyte utf8 char.
Definition sbuff.c:2001
char * fr_sbuff_adv_to_str(fr_sbuff_t *sbuff, size_t len, char const *needle, size_t needle_len)
Wind position to the first instance of the specified needle.
Definition sbuff.c:2082
char * fr_sbuff_adv_to_strcase(fr_sbuff_t *sbuff, size_t len, char const *needle, size_t needle_len)
Wind position to the first instance of the specified needle.
Definition sbuff.c:2135
size_t fr_sbuff_extend_file(fr_sbuff_extend_status_t *status, fr_sbuff_t *sbuff, size_t extension)
Refresh the buffer with more data from the file.
Definition sbuff.c:271
size_t fr_sbuff_adv_past_str(fr_sbuff_t *sbuff, char const *needle, size_t needle_len)
Return true and advance past the end of the needle if needle occurs next in the sbuff.
Definition sbuff.c:1802
size_t fr_sbuff_shift(fr_sbuff_t *sbuff, size_t shift, bool move_end)
Shift the contents of the sbuff, returning the number of bytes we managed to shift.
Definition sbuff.c:201
char * fr_sbuff_adv_to_chr(fr_sbuff_t *sbuff, size_t len, char c)
Wind position to first instance of specified char.
Definition sbuff.c:2046
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition sbuff.c:2242
size_t fr_sbuff_adv_past_strcase(fr_sbuff_t *sbuff, char const *needle, size_t needle_len)
Return true and advance past the end of the needle if needle occurs next in the sbuff.
Definition sbuff.c:1833
bool fr_sbuff_next_unless_char(fr_sbuff_t *sbuff, char c)
Return true and advance if the next char does not match.
Definition sbuff.c:2199
size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr)
Wind position until we hit a character in the terminal set.
Definition sbuff.c:1942
size_t fr_sbuff_out_bstrncpy(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
Copy as many bytes as possible from a sbuff to a sbuff.
Definition sbuff.c:735
fr_sbuff_term_t * fr_sbuff_terminals_amerge(TALLOC_CTX *ctx, fr_sbuff_term_t const *a, fr_sbuff_term_t const *b)
Merge two sets of terminal strings.
Definition sbuff.c:657
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition sbuff.c:2178
#define fr_sbuff_start(_sbuff_or_marker)
#define SBUFF_CHAR_CLASS
Definition sbuff.h:203
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_BIND_CURRENT(_sbuff_or_marker)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
char const * str
Terminal string.
Definition sbuff.h:160
char chr
Character at the start of an escape sequence.
Definition sbuff.h:211
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:190
size_t len
Length of the list.
Definition sbuff.h:170
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_init_in(_out, _start, _len_or_end)
#define FR_SBUFF_OUT(_start, _len_or_end)
fr_sbuff_term_elem_t * elem
A sorted list of terminal strings.
Definition sbuff.h:171
#define FR_SBUFF_TERM(_str)
Initialise a terminal structure with a single string.
Definition sbuff.h:178
Set of terminal elements.
File sbuff extension structure.
Definition sbuff.h:148
Talloc sbuff extension structure.
Definition sbuff.h:137
Set of parsing rules for *unescape_until functions.
static void test_adv_past_allowed(void)
static void test_terminal_search_past_visible_end(void)
TEST_LIST
static void test_no_advance(void)
static void test_file_extend_max(void)
static void test_talloc_extend_multi_level(void)
static void test_adv_past_strcase(void)
static void test_adv_to_strcase(void)
static void test_talloc_extend(void)
static void test_bstrncpy_until(void)
static void test_bstrncpy_allowed(void)
static bool allow_lowercase_and_space_no_t[SBUFF_CHAR_CLASS]
#define TEST_SBUFF_USED(_sbuff, _num)
Definition sbuff_tests.c:37
static void test_adv_until(void)
static void test_is_char(void)
Definition sbuff_tests.c:73
static void test_bstrncpy(void)
static void test_bstrncpy_exact(void)
static void test_adv_to_utf8(void)
static void test_adv_to_chr(void)
static void test_eof_terminal(void)
static void test_next_unless_char(void)
static void test_adv_past_whitespace(void)
static void test_next_if_char(void)
static void test_terminal_search_at_end_no_overrun(void)
static void test_unescape_until(void)
static void test_adv_past_str(void)
static void test_talloc_extend_with_shift(void)
static void test_unescape_multi_char_terminals(void)
#define TEST_SBUFF_LEN(_sbuff, _num)
Definition sbuff_tests.c:28
static void test_file_extend(void)
static void test_terminal_merge(void)
static void test_parse_init(void)
Definition sbuff_tests.c:46
static bool allow_lowercase_and_space[SBUFF_CHAR_CLASS]
static void test_adv_to_str(void)
static void test_talloc_extend_init_zero(void)
static void test_talloc_extend_with_marker(void)
#define PATTERN_LEN
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
static size_t char ** out
Definition value.h:1030