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
1037{
1038 fr_sbuff_t sbuff;
1040
1041 TEST_CASE("Intermix shift and extend");
1042 TEST_CHECK(fr_sbuff_init_talloc(NULL, &sbuff, &tctx, 4, 8) == &sbuff);
1043 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "0123") == 4);
1044 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "5678") == 4);
1045 TEST_CHECK(fr_sbuff_shift(&sbuff, 4, false) == 4);
1046 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "AAAA") == 4);
1047 TEST_CHECK(fr_sbuff_shift(&sbuff, 8, false) == 8);
1048 TEST_CHECK(fr_sbuff_in_strcpy(&sbuff, "BBBBBBBB") == 8);
1049
1050 talloc_free(sbuff.buff);
1051}
1052
1053static void test_file_extend(void)
1054{
1055 fr_sbuff_t sbuff;
1056 fr_sbuff_t our_sbuff, child_sbuff;
1058 FILE *fp;
1059 char buff[5];
1060 char out[24];
1061 char fbuff[24];
1062 const char PATTERN[] = "xyzzy";
1063#define PATTERN_LEN (sizeof(PATTERN) - 1)
1064 char *post_ws;
1065 ssize_t slen;
1066
1067 static_assert(sizeof(buff) >= PATTERN_LEN, "Buffer must be sufficiently large to hold the pattern");
1068 static_assert((sizeof(fbuff) % sizeof(buff)) > 0, "sizeof buff must not be a multiple of fbuff");
1069 static_assert((sizeof(fbuff) % sizeof(buff)) < PATTERN_LEN, "remainder of sizeof(fbuff)/sizeof(buff) must be less than sizeof pattern");
1070
1071 TEST_CASE("Initialization");
1072 memset(fbuff, ' ', sizeof(fbuff));
1073 memcpy(fbuff + sizeof(fbuff) - PATTERN_LEN, PATTERN, PATTERN_LEN);
1074
1075 fp = fmemopen(fbuff, sizeof(fbuff), "r");
1076#ifdef __clang_analyzer__
1077 if (fp == NULL) return;
1078#endif
1079
1080 TEST_CHECK(fp != NULL);
1081 TEST_CHECK(fr_sbuff_init_file(&sbuff, &fctx, buff, sizeof(buff), fp, 128) == &sbuff);
1082 our_sbuff = FR_SBUFF_BIND_CURRENT(&sbuff);
1083
1084 TEST_CASE("Advance past whitespace, which will require shift/extend");
1085 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&our_sbuff, SIZE_MAX, NULL), sizeof(fbuff) - PATTERN_LEN);
1086 TEST_CASE("Verify extend on unused child buffer");
1087 child_sbuff = FR_SBUFF(&our_sbuff);
1088 slen = fr_sbuff_extend_file(NULL, &child_sbuff, 0);
1089 TEST_CHECK_SLEN(slen, sizeof(fbuff) % PATTERN_LEN);
1090 TEST_CASE("Verify that we passed all and only whitespace");
1091 (void) fr_sbuff_out_abstrncpy(NULL, &post_ws, &our_sbuff, 24);
1092 TEST_CHECK_STRCMP(post_ws, PATTERN);
1093 talloc_free(post_ws);
1094 TEST_CASE("Verify parent buffer end");
1095 TEST_CHECK(sbuff.end == our_sbuff.end);
1096
1097 TEST_CASE("Verify that we do not read shifted buffer past eof");
1098 slen = fr_sbuff_out_bstrncpy(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX);
1099 TEST_CHECK_SLEN(slen, 0);
1100 slen = fr_sbuff_out_bstrncpy_exact(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX);
1101 TEST_CHECK_SLEN(slen, 0);
1102 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX, NULL, NULL);
1103 TEST_CHECK_SLEN(slen, 0);
1104 slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX, allow_lowercase_and_space);
1105 TEST_CHECK_SLEN(slen, 0);
1106
1107 fclose(fp);
1108
1109 TEST_CASE("Verify fr_sbuff_out_bstrncpy_until() extends from file properly");
1110 fp = fmemopen(fbuff, sizeof(fbuff), "r");
1111#ifdef __clang_analyzer__
1112 if (fp == NULL) return;
1113#endif
1114
1115 TEST_CHECK(fp != NULL);
1116 TEST_CHECK(fr_sbuff_init_file(&sbuff, &fctx, buff, sizeof(buff), fp, 128) == &sbuff);
1117 our_sbuff = FR_SBUFF_BIND_CURRENT(&sbuff);
1118 slen = fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, sizeof(out)), &our_sbuff, SIZE_MAX, &FR_SBUFF_TERM("x"), NULL);
1119 TEST_CHECK_SLEN(slen, sizeof(fbuff) - PATTERN_LEN);
1120
1121 fclose(fp);
1122}
1123
1124static void test_file_extend_max(void)
1125{
1126 fr_sbuff_t sbuff;
1128 FILE *fp;
1129 char buff[16];
1130 char fbuff[] = " xyzzy";
1131 char *post_ws;
1132
1133 TEST_CASE("Initialization");
1134 fp = fmemopen(fbuff, sizeof(fbuff) - 1, "r");
1135#ifdef __clang_analyzer__
1136 if (fp == NULL) return;
1137#endif
1138 TEST_CHECK(fp != NULL);
1139 TEST_CHECK(fr_sbuff_init_file(&sbuff, &fctx, buff, sizeof(buff), fp, sizeof(fbuff) - 8) == &sbuff);
1140
1141 TEST_CASE("Confirm that max stops us from seeing xyzzy");
1142 TEST_CHECK_SLEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), sizeof(fbuff) - 8);
1143 TEST_CHECK_SLEN(fr_sbuff_out_abstrncpy(NULL, &post_ws, &sbuff, 24), 0);
1144 TEST_CHECK_STRCMP(post_ws, "");
1145 talloc_free(post_ws);
1146 fclose(fp);
1147}
1148
1149static void test_adv_past_str(void)
1150{
1151 fr_sbuff_t sbuff;
1152 char const in[] = "i am a test string";
1153
1154 TEST_CASE("Check for token at beginning of string");
1155 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1156 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, "i am a", SIZE_MAX), 6);
1157 TEST_CHECK_STRCMP(sbuff.p, " test string");
1158
1159 TEST_CASE("Check for token not at beginning of string");
1160 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1161 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, " am a", SIZE_MAX), 0);
1162 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1163
1164 TEST_CASE("Check for token larger than the string");
1165 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1166 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, "i am a test string ", SIZE_MAX), 0);
1167 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1168
1169 TEST_CASE("Check for token with zero length string");
1170 fr_sbuff_init_in(&sbuff, in, 0);
1171 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, "i am a", SIZE_MAX), 0);
1172
1173 TEST_CASE("Check for token that is the string");
1174 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1175 TEST_CHECK_LEN(fr_sbuff_adv_past_str(&sbuff, "i am a test string", SIZE_MAX), 18);
1176 TEST_CHECK_STRCMP(sbuff.p, "");
1177 TEST_CHECK(sbuff.p == sbuff.end);
1178}
1179
1180static void test_adv_past_strcase(void)
1181{
1182 fr_sbuff_t sbuff;
1183 char const in[] = "i am a test string";
1184
1185 TEST_CASE("Check for token at beginning of string");
1186 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1187 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, "i AM a", SIZE_MAX), 6);
1188 TEST_CHECK_STRCMP(sbuff.p, " test string");
1189
1190 TEST_CASE("Check for token not at beginning of string");
1191 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1192 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, " AM a", SIZE_MAX), 0);
1193 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1194
1195 TEST_CASE("Check for token larger than the string");
1196 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1197 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, "i AM a TEST string ", SIZE_MAX), 0);
1198 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1199
1200 TEST_CASE("Check for token with zero length string");
1201 fr_sbuff_init_in(&sbuff, in, 0);
1202 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, "i AM a", SIZE_MAX), 0);
1203
1204 TEST_CASE("Check for token that is the string");
1205 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1206 TEST_CHECK_LEN(fr_sbuff_adv_past_strcase(&sbuff, "i AM a TEST string", SIZE_MAX), 18);
1207 TEST_CHECK_STRCMP(sbuff.p, "");
1208 TEST_CHECK(sbuff.p == sbuff.end);
1209}
1210
1212{
1213 fr_sbuff_t sbuff;
1214 char const in[] = " i am a test string";
1215 char const in_ns[] = "i am a test string";
1216 char const in_ws[] = " ";
1217
1218 TEST_CASE("Check for token at beginning of string");
1219 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1220 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), 5);
1221 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1222
1223 TEST_CASE("Check for token not at beginning of string");
1224 fr_sbuff_init_in(&sbuff, in_ns, sizeof(in_ns) - 1);
1225 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), 0);
1226 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1227
1228 TEST_CASE("Check for token with zero length string");
1229 fr_sbuff_init_in(&sbuff, in, 0);
1230 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), 0);
1231
1232 TEST_CASE("Check for token that is the string");
1233 fr_sbuff_init_in(&sbuff, in_ws, sizeof(in_ws) - 1);
1234 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL), 5);
1235
1236 TEST_CASE("Length constraint with token match");
1237 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1238 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, 2, NULL), 2);
1239 TEST_CHECK_STRCMP(sbuff.p, " i am a test string");
1240
1241 TEST_CASE("Length constraint without token match");
1242 fr_sbuff_init_in(&sbuff, in_ns, sizeof(in_ns) - 1);
1243 TEST_CHECK_LEN(fr_sbuff_adv_past_whitespace(&sbuff, 2, NULL), 0);
1244 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1245}
1246
1247static void test_adv_past_allowed(void)
1248{
1249 fr_sbuff_t sbuff;
1250 char const in[] = " i am a test string";
1251 char const in_ns[] = "i am a test string";
1252 char const in_ws[] = " ";
1253
1254 TEST_CASE("Check for token at beginning of string");
1255 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1256 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, SIZE_MAX, (bool[UINT8_MAX + 1]){ [' '] = true }, NULL), 5);
1257 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1258
1259 TEST_CASE("Check for token not at beginning of string");
1260 fr_sbuff_init_in(&sbuff, in_ns, sizeof(in_ns) - 1);
1261 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, SIZE_MAX, (bool[UINT8_MAX + 1]){ [' '] = true }, NULL), 0);
1262 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1263
1264 TEST_CASE("Check for token with zero length string");
1265 fr_sbuff_init_in(&sbuff, in, 0);
1266 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, SIZE_MAX, (bool[UINT8_MAX + 1]){ [' '] = true }, NULL), 0);
1267 TEST_CHECK(sbuff.p == sbuff.start);
1268
1269 TEST_CASE("Check for token at the end of the string");
1270 fr_sbuff_init_in(&sbuff, in_ws, sizeof(in_ws) - 1);
1271 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, SIZE_MAX, (bool[UINT8_MAX + 1]){ [' '] = true }, NULL), 5);
1272 TEST_CHECK(sbuff.p == sbuff.end);
1273
1274 TEST_CASE("Length constraint with token match");
1275 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1276 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, 2, (bool[UINT8_MAX + 1]){ [' '] = true }, NULL), 2);
1277 TEST_CHECK_STRCMP(sbuff.p, " i am a test string");
1278
1279 TEST_CASE("Length constraint with token match");
1280 fr_sbuff_init_in(&sbuff, in_ns, sizeof(in_ns) - 1);
1281 TEST_CHECK_LEN(fr_sbuff_adv_past_allowed(&sbuff, 2, (bool[UINT8_MAX + 1]){ [' '] = true }, NULL), 0);
1282 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1283}
1284
1285static void test_adv_until(void)
1286{
1287 fr_sbuff_t sbuff;
1288 char const in[] = " abcdefgh ijklmnopp";
1289
1290 TEST_CASE("Check for token at beginning of string");
1291 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1292 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM(" "), '\0'), 0);
1293 TEST_CHECK_STRCMP(sbuff.p, " abcdefgh ijklmnopp");
1294
1295 TEST_CASE("Check for token not at beginning of string");
1296 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1297 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM("a"), '\0'), 1);
1298 TEST_CHECK_STRCMP(sbuff.p, "abcdefgh ijklmnopp");
1299
1300 TEST_CASE("Check for token with zero length string");
1301 fr_sbuff_init_in(&sbuff, in, 0);
1302 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM("a"), '\0'), 0);
1303 TEST_CHECK(sbuff.p == sbuff.start);
1304
1305 TEST_CASE("Check for token that is not in the string");
1306 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1307 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM("|"), '\0'), 19);
1308 TEST_CHECK(sbuff.p == sbuff.end);
1309
1310 TEST_CASE("Check escapes");
1311 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1312 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, SIZE_MAX, &FR_SBUFF_TERM("p"), 'o'), 18);
1313 TEST_CHECK_STRCMP(sbuff.p, "p");
1314
1315 TEST_CASE("Check for token that is not in the string with length constraint");
1316 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1317 TEST_CHECK_LEN(fr_sbuff_adv_until(&sbuff, 5, &FR_SBUFF_TERM("|"), '\0'), 5);
1318 TEST_CHECK(sbuff.p == (sbuff.start + 5));
1319}
1320
1321static void test_adv_to_utf8(void)
1322{
1323 fr_sbuff_t sbuff;
1324 char const in[] = "🥺🥺🥺🥺🍪😀";
1325 char *p;
1326
1327 TEST_CASE("Check for token at beginning of string");
1328 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1329 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "🥺");
1330 TEST_CHECK(p == sbuff.p);
1331 TEST_CHECK_STRCMP(sbuff.p, "🥺🥺🥺🥺🍪😀");
1332
1333 TEST_CASE("Check for token not at beginning of 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 == (sbuff.start + (sizeof("🥺🥺🥺🥺") - 1)));
1337 TEST_CHECK_STRCMP(p, "🍪😀");
1338
1339 TEST_CASE("Check for token with zero length string");
1340 fr_sbuff_init_in(&sbuff, in, 0);
1341 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "🍪");
1342 TEST_CHECK(p == NULL);
1343 TEST_CHECK(sbuff.start == sbuff.p);
1344
1345 TEST_CASE("Check for token at the end of the string");
1346 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1347 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "😀");
1348 TEST_CHECK(p == sbuff.start + (sizeof("🥺🥺🥺🥺🍪") - 1));
1349
1350 TEST_CASE("Check for token not in the string");
1351 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1352 p = fr_sbuff_adv_to_chr_utf8(&sbuff, SIZE_MAX, "🍆 ");
1353 TEST_CHECK(p == NULL);
1354
1355 TEST_CASE("Check for token at the end of the string within len constraints");
1356 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1357 p = fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 1), "😀");
1358 TEST_CHECK(p == sbuff.start + (sizeof("🥺🥺🥺🥺🍪") - 1));
1359
1360 TEST_CASE("Check for token at the end of the string outside len constraints #1");
1361 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1362 TEST_CHECK(!fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 2), "😀"));
1363 TEST_CHECK(sbuff.p == sbuff.start);
1364
1365 TEST_CASE("Check for token at the end of the string outside len constraints #2");
1366 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1367 TEST_CHECK(!fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 3), "😀"));
1368 TEST_CHECK(sbuff.p == sbuff.start);
1369
1370 TEST_CASE("Check for token at the end of the string outside len constraints #3");
1371 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1372 TEST_CHECK(!fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 4), "😀"));
1373 TEST_CHECK(sbuff.p == sbuff.start);
1374
1375 TEST_CASE("Check for token at the end of the string outside len constraints #4");
1376 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1377 TEST_CHECK(!fr_sbuff_adv_to_chr_utf8(&sbuff, (sizeof("🥺🥺🥺🥺🍪😀") - 5), "😀"));
1378 TEST_CHECK(sbuff.p == sbuff.start);
1379}
1380
1381static void test_adv_to_chr(void)
1382{
1383 fr_sbuff_t sbuff;
1384 char const in[] = "AAAAbC";
1385 char *p;
1386
1387 TEST_CASE("Check for token at beginning of string");
1388 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1389 p = fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'A');
1390 TEST_CHECK(p == sbuff.p);
1391 TEST_CHECK_STRCMP(sbuff.p, "AAAAbC");
1392
1393 TEST_CASE("Check for token not at beginning of string");
1394 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1395 p = fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'b');
1396 TEST_CHECK(p == (sbuff.start + (sizeof("AAAA") - 1)));
1397 TEST_CHECK_STRCMP(p, "bC");
1398
1399 TEST_CASE("Check for token with zero length string");
1400 fr_sbuff_init_in(&sbuff, in, 0);
1401 TEST_CHECK(!fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'b'));
1402 TEST_CHECK(sbuff.start == sbuff.p);
1403
1404 TEST_CASE("Check for token at the end of the string");
1405 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1406 p = fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'C');
1407 TEST_CHECK(p == sbuff.start + (sizeof("AAAAb") - 1));
1408
1409 TEST_CASE("Check for token not in the string");
1410 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1411 p = fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, 'D');
1412 TEST_CHECK(p == NULL);
1413
1414 TEST_CASE("Check for token not at beginning of string within length constraints");
1415 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1416 p = fr_sbuff_adv_to_chr(&sbuff, 5, 'b');
1417 TEST_CHECK(p == (sbuff.start + (sizeof("AAAA") - 1)));
1418 TEST_CHECK_STRCMP(p, "bC");
1419
1420 TEST_CASE("Check for token not at beginning of string outside length constraints");
1421 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1422 TEST_CHECK(!fr_sbuff_adv_to_chr(&sbuff, 4, 'b'));
1423 TEST_CHECK(sbuff.p == sbuff.start);
1424}
1425
1426static void test_adv_to_str(void)
1427{
1428 fr_sbuff_t sbuff;
1429 char const in[] = "i am a test string";
1430 char *p;
1431
1432 TEST_CASE("Check for token at beginning of string");
1433 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1434 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "i am a test", SIZE_MAX);
1435 TEST_CHECK(sbuff.p == p);
1436 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1437
1438 TEST_CASE("Check for token not at beginning of string");
1439 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1440 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "test", SIZE_MAX);
1441 TEST_CHECK(sbuff.p == p);
1442 TEST_CHECK_STRCMP(sbuff.p, "test string");
1443
1444 TEST_CASE("Check for token at the end of string");
1445 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1446 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "ing", SIZE_MAX);
1447 TEST_CHECK(sbuff.p == p);
1448 TEST_CHECK_STRCMP(sbuff.p, "ing");
1449
1450 TEST_CASE("Check for token larger than the string");
1451 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1452 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "i am a test string ", SIZE_MAX);
1453 TEST_CHECK(sbuff.p == sbuff.start);
1454 TEST_CHECK(p == NULL);
1455
1456 TEST_CASE("Check for token shorter than string, not in the string");
1457 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1458 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "ng ", SIZE_MAX);
1459 TEST_CHECK(sbuff.p == sbuff.start);
1460 TEST_CHECK(p == NULL);
1461
1462 TEST_CASE("Check for token with zero length string");
1463 fr_sbuff_init_in(&sbuff, in, 0);
1464 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "i am a", SIZE_MAX);
1465 TEST_CHECK(sbuff.p == sbuff.start);
1466 TEST_CHECK(p == NULL);
1467
1468 TEST_CASE("Check for token that is the string");
1469 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1470 p = fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, "i am a test string", SIZE_MAX);
1471 TEST_CHECK(sbuff.p == sbuff.start);
1472 TEST_CHECK(sbuff.p == p);
1473 TEST_CHECK_STRCMP(p, "i am a test string");
1474
1475 TEST_CASE("Check for token not at beginning of string within length constraints");
1476 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1477 p = fr_sbuff_adv_to_str(&sbuff, 11, "test", SIZE_MAX);
1478 TEST_CHECK(sbuff.p == p);
1479 TEST_CHECK_STRCMP(sbuff.p, "test string");
1480
1481 TEST_CASE("Check for token not at beginning of string outside length constraints");
1482 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1483 TEST_CHECK(!fr_sbuff_adv_to_str(&sbuff, 10, "test", SIZE_MAX));
1484 TEST_CHECK(sbuff.p == sbuff.start);
1485}
1486
1487static void test_adv_to_strcase(void)
1488{
1489 fr_sbuff_t sbuff;
1490 char const in[] = "i am a test string";
1491 char *p;
1492
1493 TEST_CASE("Check for token at beginning of string");
1494 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1495 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "i AM a TEST", SIZE_MAX);
1496 TEST_CHECK(sbuff.p == p);
1497 TEST_CHECK_STRCMP(sbuff.p, "i am a test string");
1498
1499 TEST_CASE("Check for token not at beginning of string");
1500 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1501 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "tEst", SIZE_MAX);
1502 TEST_CHECK(sbuff.p == p);
1503 TEST_CHECK_STRCMP(sbuff.p, "test string");
1504
1505 TEST_CASE("Check for token at the end of string");
1506 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1507 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "Ing", SIZE_MAX);
1508 TEST_CHECK(sbuff.p == p);
1509 TEST_CHECK_STRCMP(sbuff.p, "ing");
1510
1511 TEST_CASE("Check for token larger than the string");
1512 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1513 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "i aM a tEst stRIng ", SIZE_MAX);
1514 TEST_CHECK(sbuff.p == sbuff.start);
1515 TEST_CHECK(p == NULL);
1516
1517 TEST_CASE("Check for token shorter than string, not in the string");
1518 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1519 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "nG ", SIZE_MAX);
1520 TEST_CHECK(sbuff.p == sbuff.start);
1521 TEST_CHECK(p == NULL);
1522
1523 TEST_CASE("Check for token with zero length string");
1524 fr_sbuff_init_in(&sbuff, in, 0);
1525 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "i AM a", SIZE_MAX);
1526 TEST_CHECK(sbuff.p == sbuff.start);
1527 TEST_CHECK(p == NULL);
1528
1529 TEST_CASE("Check for token that is the string");
1530 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1531 p = fr_sbuff_adv_to_strcase(&sbuff, SIZE_MAX, "i AM a teST stRIng", SIZE_MAX);
1532 TEST_CHECK(sbuff.p == sbuff.start);
1533 TEST_CHECK(sbuff.p == p);
1534 TEST_CHECK_STRCMP(p, "i am a test string");
1535
1536 TEST_CASE("Check for token not at beginning of string within length constraints");
1537 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1538 p = fr_sbuff_adv_to_strcase(&sbuff, 11, "tEst", SIZE_MAX);
1539 TEST_CHECK(sbuff.p == p);
1540 TEST_CHECK_STRCMP(sbuff.p, "test string");
1541
1542 TEST_CASE("Check for token not at beginning of string outside length constraints");
1543 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1544 TEST_CHECK(!fr_sbuff_adv_to_strcase(&sbuff, 10, "tEst", SIZE_MAX));
1545 TEST_CHECK(sbuff.p == sbuff.start);
1546}
1547
1548static void test_next_if_char(void)
1549{
1550 fr_sbuff_t sbuff;
1551 char const in[] = "i ";
1552
1553 TEST_CASE("Check for advancement on match");
1554 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1555 TEST_CHECK(fr_sbuff_next_if_char(&sbuff, 'i') == true);
1556 TEST_CHECK_STRCMP(sbuff.p, " ");
1557
1558 TEST_CASE("Check for non-advancement on non-match");
1559 TEST_CHECK(fr_sbuff_next_if_char(&sbuff, 'i') == false);
1560 TEST_CHECK_STRCMP(sbuff.p, " ");
1561
1562 TEST_CASE("Check for advancement at end");
1563 TEST_CHECK(fr_sbuff_next_if_char(&sbuff, ' ') == true);
1564 TEST_CHECK_STRCMP(sbuff.p, "");
1565
1566 TEST_CASE("Check we can't advance off the end of the buffer");
1567 TEST_CHECK(fr_sbuff_next_if_char(&sbuff, ' ') == false);
1568 TEST_CHECK_STRCMP(sbuff.p, "");
1569}
1570
1571static void test_next_unless_char(void)
1572{
1573 fr_sbuff_t sbuff;
1574 char const in[] = "i ";
1575
1576 TEST_CASE("Check for advancement on non-match");
1577 fr_sbuff_init_in(&sbuff, in, sizeof(in) - 1);
1578 TEST_CHECK(fr_sbuff_next_unless_char(&sbuff, ' ') == true);
1579 TEST_CHECK_STRCMP(sbuff.p, " ");
1580
1581 TEST_CASE("Check for non-advancement on match");
1582 TEST_CHECK(fr_sbuff_next_unless_char(&sbuff, ' ') == false);
1583 TEST_CHECK_STRCMP(sbuff.p, " ");
1584
1585 TEST_CASE("Check for advancement at end");
1586 TEST_CHECK(fr_sbuff_next_unless_char(&sbuff, '_') == true);
1587 TEST_CHECK_STRCMP(sbuff.p, "");
1588
1589 TEST_CASE("Check we can't advance off the end of the buffer");
1590 TEST_CHECK(fr_sbuff_next_unless_char(&sbuff, '_') == false);
1591 TEST_CHECK_STRCMP(sbuff.p, "");
1592}
1593
1595 /*
1596 * Basic tests
1597 */
1598 { "fr_sbuff_init", test_parse_init },
1599 { "fr_sbuff_is_char", test_is_char },
1600 { "fr_sbuff_out_bstrncpy_exact", test_bstrncpy_exact },
1601 { "fr_sbuff_out_bstrncpy", test_bstrncpy },
1602 { "fr_sbuff_out_bstrncpy_allowed", test_bstrncpy_allowed },
1603 { "fr_sbuff_out_bstrncpy_until", test_bstrncpy_until },
1604 { "multi-char terminals", test_unescape_multi_char_terminals },
1605 { "fr_sbuff_out_unescape_until", test_unescape_until },
1606 { "fr_sbuff_terminal_eof", test_eof_terminal },
1607 { "terminal merge", test_terminal_merge },
1608
1609 /*
1610 * Extending buffer
1611 */
1612 { "fr_sbuff_talloc_extend", test_talloc_extend },
1613 { "fr_sbuff_talloc_extend_init_zero", test_talloc_extend_init_zero },
1614 { "fr_sbuff_talloc_extend_multi_level", test_talloc_extend_multi_level },
1615 { "fr_sbuff_talloc_extend_with_marker", test_talloc_extend_with_marker },
1616 { "fr_sbuff_talloc_extend_with_shift", test_talloc_extend_with_shift},
1617 { "fr_sbuff_file_extend", test_file_extend },
1618 { "fr_sbuff_file_extend_max", test_file_extend_max },
1619
1620 { "fr_sbuff_no_advance", test_no_advance },
1621
1622 /*
1623 * Token skipping
1624 */
1625 { "fr_sbuff_adv_past_str", test_adv_past_str },
1626 { "fr_sbuff_adv_past_strcase", test_adv_past_strcase },
1627 { "fr_sbuff_adv_past_whitespace", test_adv_past_whitespace },
1628 { "fr_sbuff_adv_past_allowed", test_adv_past_allowed },
1629 { "fr_sbuff_adv_until", test_adv_until },
1630
1631 /*
1632 * Token searching
1633 */
1634 { "fr_sbuff_adv_to_utf8", test_adv_to_utf8 },
1635 { "fr_sbuff_adv_to_chr", test_adv_to_chr },
1636 { "fr_sbuff_adv_to_str", test_adv_to_str },
1637 { "fr_sbuff_adv_to_strcase", test_adv_to_strcase },
1638
1639 /*
1640 * Advancement
1641 */
1642 { "fr_sbuff_next_if_char", test_next_if_char },
1643 { "fr_sbuff_next_unless_char", test_next_unless_char },
1644
1645 { NULL }
1646};
#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:840
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:421
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:1456
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:1779
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:1913
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:1994
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:2047
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:267
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:1714
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:197
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:1958
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition sbuff.c:2154
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:1745
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:2111
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:1854
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:725
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:647
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:2090
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 void test_talloc_extend_with_shift(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:1020