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