The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
dbuff_tests.c
Go to the documentation of this file.
1#include "acutest.h"
2#include"acutest_helpers.h"
3#include <float.h>
4
5#include <freeradius-devel/util/dbuff.h>
6
7/*
8 * Type for a function with the internals of a test of fd flavored dbuffs.
9 */
10typedef void (*fr_dbuff_fd_test_body)(fr_dbuff_t *dbuff, uint8_t const data[]);
11
12static void test_dbuff_init(void)
13{
14 uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04 };
15 fr_dbuff_t dbuff;
16
17 TEST_CASE("Parse init with size");
18 fr_dbuff_init(&dbuff, in, sizeof(in));
19
20 TEST_CHECK(dbuff.start == in);
21 TEST_CHECK(dbuff.p == in);
22 TEST_CHECK(dbuff.end == in + sizeof(in));
23
24 TEST_CASE("Parse init with end");
25 fr_dbuff_init(&dbuff, in, in + sizeof(in));
26
27 TEST_CHECK(dbuff.start == in);
28 TEST_CHECK(dbuff.p == in);
29 TEST_CHECK(dbuff.end == in + sizeof(in));
30
31 TEST_CASE("Parse init with const end");
32 fr_dbuff_init(&dbuff, in, (uint8_t const *)(in + sizeof(in)));
33
34 TEST_CHECK(dbuff.start == in);
35 TEST_CHECK(dbuff.p == in);
36 TEST_CHECK(dbuff.end == in + sizeof(in));
37}
38
40{ uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04 };
41 fr_dbuff_t dbuff;
42
43 TEST_CASE("Confirm init returns parentless dbuff");
44 fr_dbuff_init(&dbuff, in, sizeof(in));
45
46 TEST_CHECK(dbuff.parent == NULL);
47}
48
49static void test_dbuff_max(void)
50{
51 uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
52 fr_dbuff_t dbuff;
53 fr_dbuff_t max_dbuff;
54
55 TEST_CASE("Confirm max constrains available space");
56 fr_dbuff_init(&dbuff, in, sizeof(in));
57
58 max_dbuff = FR_DBUFF_MAX_BIND_CURRENT(&dbuff, 4);
59 TEST_CHECK(fr_dbuff_remaining(&max_dbuff) == 4);
60
61 max_dbuff = FR_DBUFF_MAX_BIND_CURRENT(&dbuff, 2 * sizeof(in));
62 TEST_CHECK(fr_dbuff_remaining(&max_dbuff) == sizeof(in));
63}
64
65
66/** Test the various dbuff_net_encode() functions and macros
67 *
68 * @note Passing constants to fr_dbuff_in() as it is written results in
69 * warnings about narrowing casts on the constants--but those casts are in
70 * the underlying inlined fr_nbo_from*() functions. They have to be there;
71 * that's how those functions work. (The tests worked despite the warnings.)
72 * Using variables avoids the warnings, at least with the compile options
73 * the build system uses by default.
74 */
75static void test_dbuff_net_encode(void)
76{
77 uint8_t buff[sizeof(uint64_t)];
78 fr_dbuff_t dbuff;
79 fr_dbuff_marker_t marker;
80 uint16_t u16val = 0x1234;
81 uint16_t u16val2 = 0xcdef;
82 uint32_t u32val = 0x12345678;
83 uint64_t u64val = 0x123456789abcdef0;
84 int16_t i16val = 0x1234;
85 int32_t i32val = 0xd34d;
86 int64_t i64val = 0x123456789abcdef0;
87 float float_in = 1.0f + FLT_EPSILON;
88 float float_out = 0;
89 double double_in = 1.0 + DBL_EPSILON;
90 double double_out = 0;
91 uint64_t u64v_vals[] = {
92 0, 0x12, 0x3412, 0x563412, 0x78563412, 0x9a78563412,
93 0xbc9a78563412, 0xdebc9a78563412, 0xf0debc9a78563412
94 };
95
96 TEST_CASE("Generate wire format unsigned 16-bit value");
97 memset(buff, 0, sizeof(buff));
98 fr_dbuff_init(&dbuff, buff, sizeof(buff));
99 fr_dbuff_marker(&marker, &dbuff);
100
101 TEST_CHECK(fr_dbuff_in(&dbuff, u16val) == sizeof(uint16_t));
102 TEST_CHECK(*((uint16_t *)buff) == htons(u16val));
103
104 TEST_CASE("Generate wire format unsigned 16-bit value using marker");
105 fr_dbuff_set_to_start(&dbuff);
106 TEST_CHECK(fr_dbuff_in(&marker, u16val2) == sizeof(uint16_t));
107 TEST_CHECK(*((uint16_t *)buff) == htons(u16val2));
108 TEST_CHECK(fr_dbuff_used(&marker) == sizeof(uint16_t));
109 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
110
111 TEST_CASE("Generate wire format unsigned 32-bit value");
112 memset(buff, 0, sizeof(buff));
113 fr_dbuff_init(&dbuff, buff, sizeof(buff));
114
115 TEST_CHECK(fr_dbuff_in(&dbuff, u32val) == sizeof(uint32_t));
116 TEST_CHECK(*((uint32_t *)buff) == htonl(u32val));
117
118 TEST_CASE("Generate wire format unsigned 64-bit value");
119 memset(buff, 0, sizeof(buff));
120 fr_dbuff_init(&dbuff, buff, sizeof(buff));
121
122 TEST_CHECK(fr_dbuff_in(&dbuff, u64val) == sizeof(uint64_t));
123 TEST_CHECK(*((uint64_t *)buff) == htonll(u64val));
124
125 TEST_CASE("Generate wire format signed 16-bit value");
126 memset(buff, 0, sizeof(buff));
127 fr_dbuff_init(&dbuff, buff, sizeof(buff));
128
129 TEST_CHECK(fr_dbuff_in(&dbuff, i16val) == sizeof(int16_t));
130 TEST_CHECK(*((uint16_t *)buff) == htons((uint16_t) i16val));
131
132 TEST_CASE("Generate wire format signed 32-bit value");
133 memset(buff, 0, sizeof(buff));
134 fr_dbuff_init(&dbuff, buff, sizeof(buff));
135
136 TEST_CHECK(fr_dbuff_in(&dbuff, i32val) == sizeof(int32_t));
137 TEST_CHECK(*((uint32_t *)buff) == htonl((uint32_t) i32val));
138
139 TEST_CASE("Generate wire format signed 64-bit value");
140 memset(buff, 0, sizeof(buff));
141 fr_dbuff_init(&dbuff, buff, sizeof(buff));
142
143 TEST_CHECK(fr_dbuff_in(&dbuff, i64val) == sizeof(int64_t));
144 TEST_CHECK(*((uint64_t *)buff) == htonll((uint64_t) i64val));
145
146 TEST_CASE("Generate wire format variable-width");
147 for (size_t i = 0; i < (sizeof(u64v_vals) / sizeof(uint64_t)); i++) {
148 uint64_t val = u64v_vals[i];
149 int num_bytes;
150
151 fr_dbuff_set_to_start(&dbuff);
152 for (num_bytes = 1; (val & ~((uint64_t) 0xff)) != 0; num_bytes++) val >>= 8;
153 TEST_CHECK(fr_dbuff_in_uint64v(&dbuff, u64v_vals[i]) == num_bytes);
154 val = u64v_vals[i];
155 fr_dbuff_set_to_start(&dbuff);
156 for (int j = num_bytes; --j >= 0; ) {
157 uint8_t byte = 0;
158
159 TEST_CHECK(fr_dbuff_out(&byte, &dbuff) == 1);
160 TEST_CHECK(byte == (uint8_t) (val >> (8 * j)));
161 }
162 }
163
164 TEST_CASE("Generate wire-format float");
165 memset(buff, 0, sizeof(buff));
166 fr_dbuff_init(&dbuff, buff, sizeof(buff));
167 TEST_CHECK(fr_dbuff_in(&dbuff, float_in) == 4);
168 fr_dbuff_set_to_start(&dbuff);
169 TEST_CHECK(fr_dbuff_out(&float_out, &dbuff) == 4);
170 TEST_CHECK(memcmp(&float_out, &float_in, sizeof(float)) == 0);
171
172 TEST_CASE("Generate wire-format double");
173 memset(buff, 0, sizeof(buff));
174 fr_dbuff_init(&dbuff, buff, sizeof(buff));
175 TEST_CHECK(fr_dbuff_in(&dbuff, double_in) == 8);
176 fr_dbuff_set_to_start(&dbuff);
177 TEST_CHECK(fr_dbuff_out(&double_out, &dbuff) == 8);
178 TEST_CHECK(memcmp(&double_out, &double_in, sizeof(double)) == 0);
179
180 TEST_CASE("Refuse to write to too-small space");
181 fr_dbuff_init(&dbuff, buff, sizeof(uint32_t));
182
183 TEST_CHECK(fr_dbuff_in(&dbuff, u64val) == -(ssize_t)(sizeof(uint64_t) - sizeof(uint32_t)));
184
185 TEST_CASE("Input bytes using dbuff current position");
186 memset(buff, 0, sizeof(buff));
187 fr_dbuff_init(&dbuff, buff, sizeof(buff));
188 fr_dbuff_marker(&marker, &dbuff);
189 TEST_CHECK(fr_dbuff_in_bytes(&dbuff, 0xf0, 0xed, 0xcb) == 3);
190 TEST_CHECK(buff[0] == 0xf0);
191 TEST_CHECK(buff[1] == 0xed);
192 TEST_CHECK(buff[2] == 0xcb);
193 TEST_CHECK(fr_dbuff_used(&dbuff) == 3);
194 TEST_CASE("Input bytes using marker");
195 TEST_CHECK(fr_dbuff_in_bytes(&marker, 0x01, 0x23) == 2);
196 TEST_CHECK(buff[0] == 0x01);
197 TEST_CHECK(buff[1] == 0x23);
198 TEST_CHECK(fr_dbuff_used(&marker) == 2);
199}
200
201static void test_dbuff_no_advance(void)
202{
203 uint8_t in[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
204 fr_dbuff_t dbuff;
205 fr_dbuff_t no_advance_dbuff;
206 size_t init_remaining;
207
208 TEST_CASE("Confirm no-advance dbuff operations don't affect ancestors' position");
209 fr_dbuff_init(&dbuff, in, sizeof(in));
210
211 no_advance_dbuff = FR_DBUFF(&dbuff);
212 init_remaining = fr_dbuff_remaining(&dbuff);
213 TEST_CHECK(fr_dbuff_in_bytes(&no_advance_dbuff, 0x11, 0x12, 0x13) == 3);
214 TEST_CHECK(init_remaining == fr_dbuff_remaining(&dbuff));
215 fr_dbuff_advance(&no_advance_dbuff, 2);
216 TEST_CHECK(init_remaining == fr_dbuff_remaining(&dbuff));
217 fr_dbuff_set_to_end(&no_advance_dbuff);
218 TEST_CHECK(init_remaining == fr_dbuff_remaining(&dbuff));
219}
220
221static void test_dbuff_move(void)
222{
223 uint8_t buff1[26], buff2[26], buff3[10];
224 fr_dbuff_t dbuff1, dbuff2, dbuff3;
225 fr_dbuff_marker_t marker1, marker2;
226
227 memcpy(buff1, "abcdefghijklmnopqrstuvwxyz", sizeof(buff1));
228 memcpy(buff2, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sizeof(buff2));
229 memcpy(buff3, "0123456789", sizeof(buff3));
230 fr_dbuff_init(&dbuff1, buff1, sizeof(buff1));
231 fr_dbuff_init(&dbuff2, buff2, sizeof(buff2));
232 fr_dbuff_init(&dbuff3, buff3, sizeof(buff3));
233 fr_dbuff_marker(&marker1, &dbuff1);
234 fr_dbuff_marker(&marker2, &dbuff2);
235
236 TEST_CASE("move dbuff to dbuff");
237 TEST_CHECK_LEN(fr_dbuff_move(&dbuff1, &dbuff2, 13), 13);
238 TEST_CHECK_LEN(fr_dbuff_used(&dbuff1), 13);
239 TEST_CHECK_LEN(fr_dbuff_used(&dbuff2), 13);
240 TEST_CHECK(memcmp(dbuff1.start, "ABCDEFGHIJKLMnopqrstuvwxyz", 26) == 0);
241
242 TEST_CASE("move dbuff to marker");
243 TEST_CHECK_SLEN(fr_dbuff_advance(&marker2, 4), 4);
244 TEST_CHECK_LEN(fr_dbuff_move(&marker2, &dbuff3, 10), 10);
245 TEST_CHECK_LEN(fr_dbuff_used(&marker2), 14);
246 TEST_CHECK(memcmp(dbuff2.start, "ABCD0123456789OPQRSTUVWXYZ", 26) == 0);
247
248 TEST_CASE("move marker to dbuff");
249 TEST_CHECK_SLEN(fr_dbuff_advance(&marker1, 7), 7);
250 TEST_CHECK_LEN(fr_dbuff_move(&dbuff1, &marker1, 6), 6);
251 TEST_CHECK_LEN(fr_dbuff_used(&dbuff1), 19);
252 TEST_CHECK_LEN(fr_dbuff_used(&marker1), 13);
253 TEST_CHECK(memcmp(dbuff1.start, "ABCDEFGHIJKLMHIJKLMtuvwxyz", 26) == 0);
254
255 TEST_CASE("move marker to marker");
256 TEST_CHECK_LEN(fr_dbuff_move(&marker2, &marker1, 8), 8);
257 TEST_CHECK_LEN(fr_dbuff_used(&marker1), 21);
258 TEST_CHECK_LEN(fr_dbuff_used(&marker2), 22);
259 TEST_CHECK(memcmp(dbuff2.start, "ABCD0123456789HIJKLMtuWXYZ", 26) == 0);
260}
261
262/** Test extensible dbuffs
263 *
264 */
265
267{
268 fr_dbuff_t dbuff1, dbuff2;
269 fr_dbuff_uctx_talloc_t tctx1, tctx2;
270 fr_dbuff_marker_t marker1;
271 uint8_t const value[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
272
273 TEST_CASE("Initial allocation");
274 TEST_CHECK(fr_dbuff_init_talloc(NULL, &dbuff1, &tctx1, 4, 14) == &dbuff1);
275 TEST_CHECK(fr_dbuff_used(&dbuff1) == 0);
276 TEST_CHECK(fr_dbuff_remaining(&dbuff1) == 4);
277 fr_dbuff_marker(&marker1, &dbuff1);
278
279 TEST_CASE("Extension");
280 TEST_CHECK(fr_dbuff_in(&dbuff1, (uint64_t) 0x123456789abcdef0) == sizeof(uint64_t));
281 TEST_CASE("Markers track extended buffer");
282 TEST_CHECK(marker1.p == dbuff1.start);
283 TEST_CASE("Already-written content stays with the buffer");
284 TEST_CHECK(memcmp(fr_dbuff_current(&marker1), value, sizeof(value)) == 0);
285 TEST_CASE("Refuse to extend past specified maximum");
286 TEST_CHECK(fr_dbuff_in(&dbuff1, (uint64_t) 0x123456789abcdef0) == -2);
287 TEST_CASE("Extend move destination if possible and input length demands");
288 TEST_CHECK(fr_dbuff_init_talloc(NULL, &dbuff2, &tctx2, 4, 14) == &dbuff2);
289 fr_dbuff_set_to_start(&dbuff1);
290 TEST_CHECK(fr_dbuff_move(&dbuff2, &dbuff1, sizeof(value)) == sizeof(value));
291 TEST_CHECK(fr_dbuff_used(&dbuff2) == sizeof(value));
292 /*
293 * @todo: the analogous test for extensible source.
294 */
295
296 talloc_free(dbuff1.buff);
297 talloc_free(dbuff2.buff);
298}
299
301{
302 fr_dbuff_t dbuff1, dbuff2;
303 fr_dbuff_uctx_talloc_t tctx;
304
305 TEST_CASE("Initial allocation");
306 TEST_CHECK(fr_dbuff_init_talloc(NULL, &dbuff1, &tctx, 0, 32) == &dbuff1);
307 TEST_CHECK(fr_dbuff_used(&dbuff1) == 0);
308 TEST_CHECK(fr_dbuff_remaining(&dbuff1) == 0);
309
310 dbuff2 = FR_DBUFF(&dbuff1);
311 TEST_CASE("Check that dbuff2 inherits extend fields");
312 TEST_CHECK(dbuff2.extend == dbuff1.extend);
313 TEST_CHECK(dbuff2.uctx == dbuff1.uctx);
314 TEST_CHECK(fr_dbuff_used(&dbuff2) == 0);
315 TEST_CHECK(fr_dbuff_remaining(&dbuff2) == 0);
316
317 dbuff2 = FR_DBUFF_MAX_BIND_CURRENT(&dbuff1, 8);
318 TEST_CASE("Check that FR_DBUFF_MAX_BIND_CURRENT() is not extensible");
319 TEST_CHECK(dbuff2.extend == NULL);
320 TEST_CHECK(dbuff2.uctx == NULL);
321 TEST_CHECK(fr_dbuff_used(&dbuff2) == 0);
322 TEST_CHECK(fr_dbuff_remaining(&dbuff2) == 0);
323 TEST_CHECK(fr_dbuff_in(&dbuff2, (uint64_t) 0x123456789abcdef0) == -8);
324
325 talloc_free(dbuff1.buff);
326}
327
328/*
329 * test_dbuff_fd_shell() puts setup and teardown of a fd flavored dbuff in one place
330 * so jscpd won't complain about copy/paste.
331 */
332static void test_dbuff_fd_shell(fr_dbuff_fd_test_body body, uint8_t const data[], size_t datasize,
333 uint8_t buff[], size_t buffsize, size_t max)
334{
335 int fd[2];
336 fr_dbuff_t dbuff;
337 fr_dbuff_uctx_fd_t fctx;
338
339 TEST_CASE("Initial allocation");
340 TEST_CHECK(pipe(fd) == 0);
341 TEST_CHECK(write(fd[1], data, datasize) == (ssize_t) datasize);
342 close(fd[1]);
343 TEST_CHECK(fr_dbuff_init_fd(&dbuff, &fctx, buff, buffsize, fd[0], max) == &dbuff);
344
345 body(&dbuff, data);
346
347 close(fd[0]);
348}
349
350static void fd_body(fr_dbuff_t *dbuff, uint8_t const data[])
351{
352 uint8_t output[8] = { 0x00 };
353
354 TEST_CASE("Initial extend");
355 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 1) == 1);
356 TEST_CHECK(memcmp(output, data, 1) == 0);
357 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 2) == 2);
358 TEST_CHECK(memcmp(output, &data[1], 2) == 0);
359 TEST_CASE("Leftover byte plus data from next extend");
360 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 4) == 4);
361 TEST_CHECK(memcmp(output, &data[3], 4) == 0);
362 TEST_CASE("Multiple extends");
363 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 8) == 8);
364 TEST_CHECK(memcmp(output, &data[7], 8) == 0);
365 TEST_CASE("EOF");
366 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 4) == -3);
367}
368
369static void test_dbuff_fd(void)
370{
371 uint8_t const data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
372 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
373 uint8_t buff[4];
374
375 test_dbuff_fd_shell(fd_body, data, sizeof(data), buff, sizeof(buff), 24);
376}
377
378
379static void max_body(fr_dbuff_t *dbuff, uint8_t const data[])
380{
381 uint8_t output[8];
382
383 TEST_CASE("Initial extend");
384 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 2) == 2);
385 TEST_CHECK(memcmp(output, data, 2) == 0);
386 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 1) == 1);
387 TEST_CHECK(memcmp(output, &data[2], 1) == 0);
388 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 4) == 4);
389 TEST_CHECK(memcmp(output, &data[3], 4) == 0);
390 TEST_CASE("Confirm that max precludes another shift/extend");
391 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 8) == -7);
392}
393
394static void test_dbuff_fd_max(void)
395{
396 uint8_t const data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
397 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
398 uint8_t buff[4];
399
400
401 test_dbuff_fd_shell(max_body, data, sizeof(data), buff, sizeof(buff), 8);
402}
403
404/** Test functions that read from dbuffs.
405 *
406 */
407static void test_dbuff_out(void)
408{
409 uint8_t const buff1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
410 uint8_t buff2[8];
411 uint8_t buff3[8];
412 fr_dbuff_t dbuff1;
413 fr_dbuff_t dbuff2;
414 fr_dbuff_marker_t marker1;
415 uint8_t u8val = 0;
416 uint16_t u16val = 0;
417 uint32_t u32val = 0;
418 uint64_t u64val = 0;
419 uint64_t u64val2 = 0;
420 int8_t i8val = 0;
421 int16_t i16val = 0;
422 int32_t i32val = 0;
423 int64_t i64val = 0;
424 float fval1 = 1.5, fval2 = 0;
425 double dval1 = 2048.0625, dval2 = 0;
426
427 fr_dbuff_init(&dbuff1, buff1, sizeof(buff1));
428 fr_dbuff_init(&dbuff2, buff2, sizeof(buff2));
429
430 TEST_CASE("Check dbuff reads of unsigned integers");
431 TEST_CHECK(fr_dbuff_out(&u8val, &dbuff1) == 1);
432 TEST_CHECK(u8val == 0x01);
433 TEST_CHECK(fr_dbuff_out(&u16val, &dbuff1) == 2);
434 TEST_CHECK(u16val == 0x2345);
435 TEST_CHECK(fr_dbuff_out(&u32val, &dbuff1) == 4);
436 TEST_CHECK(u32val == 0x6789abcd);
437 fr_dbuff_set_to_start(&dbuff1);
438 TEST_CHECK(fr_dbuff_out(&u64val, &dbuff1) == 8);
439 TEST_CHECK(u64val == 0x0123456789abcdef);
440
441 TEST_CASE("Don't walk off the end of the buffer");
442 TEST_CHECK(fr_dbuff_out(&u32val, &dbuff1) == -4);
443
444 TEST_CASE("Check dbuff reads using markers");
445 fr_dbuff_set_to_start(&dbuff1);
446 fr_dbuff_marker(&marker1, &dbuff1);
447 TEST_CHECK(fr_dbuff_out(&u64val, &marker1) == 8);
448 TEST_CHECK(fr_dbuff_out(&u64val2, &dbuff1) == 8);
449 TEST_CHECK(u64val == u64val2);
450 TEST_CHECK(fr_dbuff_current(&dbuff1) == fr_dbuff_current(&marker1));
451
452 TEST_CASE("Check dbuff reads of signed integers");
453 fr_dbuff_set_to_start(&dbuff1);
454 TEST_CHECK(fr_dbuff_out(&i8val, &dbuff1) == 1);
455 TEST_CHECK(i8val == 0x01);
456 TEST_CHECK(fr_dbuff_out(&i16val, &dbuff1) == 2);
457 TEST_CHECK(i16val == 0x2345);
458 TEST_CHECK(fr_dbuff_out(&i32val, &dbuff1) == 4);
459 TEST_CHECK(i32val == 0x6789abcd);
460 fr_dbuff_set_to_start(&dbuff1);
461 TEST_CHECK(fr_dbuff_out(&i64val, &dbuff1) == 8);
462 TEST_CHECK(i64val == 0x0123456789abcdef);
463
464 TEST_CASE("Check dbuff reads of floating point values");
465 TEST_CHECK(fr_dbuff_in(&dbuff2, *(uint32_t *)&fval1) == 4);
466 fr_dbuff_set_to_start(&dbuff2);
467 TEST_CHECK(fr_dbuff_out(&fval2, &dbuff2) == 4);
468 TEST_CHECK(memcmp(&fval1, &fval2, sizeof(fval1)) == 0);
469 fr_dbuff_set_to_start(&dbuff2);
470 TEST_CHECK(fr_dbuff_in(&dbuff2, *(uint64_t *)&dval1) == 8);
471 fr_dbuff_set_to_start(&dbuff2);
472 TEST_CHECK(fr_dbuff_out(&dval2, &dbuff2) == 8);
473 TEST_CHECK(memcmp(&dval1, &dval2, sizeof(dval1)) == 0);
474
475 TEST_CASE("Check variable length uint64_t read");
476 fr_dbuff_set_to_start(&dbuff1);
477 TEST_CHECK(fr_dbuff_out_uint64v(&u64val, &dbuff1, 2) == 2);
478 TEST_CHECK(u64val == 0x0123);
479 TEST_CHECK(fr_dbuff_out_uint64v(&u64val, &dbuff1, 4) == 4);
480 TEST_CHECK(u64val == 0x456789ab);
481 fr_dbuff_set_to_start(&dbuff1);
482 TEST_CHECK(fr_dbuff_out_uint64v(&u64val, &dbuff1, 8) == 8);
483 TEST_CHECK(u64val == 0x0123456789abcdef);
484
485 TEST_CASE("fr_dbuff_out_memcpy");
486 fr_dbuff_set_to_start(&dbuff1);
487 fr_dbuff_set_to_start(&dbuff2);
488 fr_dbuff_marker(&marker1, &dbuff1);
489 memset(buff3, 0, sizeof(buff3));
490 TEST_CHECK(fr_dbuff_out_memcpy(buff3, &dbuff1, 7) == 7);
491 TEST_CHECK(memcmp(buff3, fr_dbuff_start(&dbuff1), 7) == 0 && buff3[7] == 0);
492 TEST_CHECK(fr_dbuff_current(&dbuff1) - fr_dbuff_current(&marker1) == 7);
493 fr_dbuff_set_to_start(&dbuff1);
494 TEST_CHECK(fr_dbuff_out_memcpy(&dbuff2, &dbuff1, 4) == 4);
495 fr_dbuff_set_to_start(&dbuff1);
496 fr_dbuff_advance(&dbuff1, 3);
497 fr_dbuff_advance(&dbuff2, 2);
498 TEST_CHECK(fr_dbuff_out_memcpy(&dbuff2, &dbuff1, 4) == 4);
499 TEST_CHECK(memcmp(fr_dbuff_start(&dbuff2), fr_dbuff_start(&dbuff1), 2) == 0 &&
500 memcmp(fr_dbuff_start(&dbuff2) + 2, fr_dbuff_start(&dbuff1) + 3, 4) == 0);
501 memset(buff3, 0, sizeof(buff3));
502 fr_dbuff_set_to_start(&marker1);
503 TEST_CHECK(fr_dbuff_out_memcpy(buff3, &marker1, 4) == 4);
504 TEST_CHECK(memcmp(buff3, buff1, 4) == 0);
505 TEST_CHECK(fr_dbuff_current(&marker1) - fr_dbuff_start(&dbuff1) == 4);
506}
507
508/** Test the child-dbuff macros: FR_DBUFF, FR_DBUFF_ABS, FR_DBUFF_BIND_CURRENT,
509 * FR_DBUFF_BIND_CURRENT_ABS, FR_DBUFF_BIND_END_ABS and FR_DBUFF_MAX.
510 *
511 * These differ only in where the child's 'start' pointer is set (parent
512 * 'current' vs parent 'start') and whether writing to the child advances the
513 * parent's 'current' pointer, 'end' pointer, or neither.
514 */
515static void test_dbuff_child(void)
516{
517 fr_dbuff_t dbuff;
518 fr_dbuff_t child;
519 uint8_t buff[16] = "";
520
521 TEST_CASE("FR_DBUFF: start bound to parent 'current', parent not advanced");
522 fr_dbuff_init(&dbuff, buff, sizeof(buff));
523 fr_dbuff_advance(&dbuff, 4);
524 child = FR_DBUFF(&dbuff);
525 TEST_CHECK(fr_dbuff_start(&child) == fr_dbuff_current(&dbuff));
526 TEST_CHECK(fr_dbuff_current(&child) == fr_dbuff_current(&dbuff));
527 TEST_CHECK(fr_dbuff_used(&child) == 0);
528 TEST_CHECK(fr_dbuff_remaining(&child) == sizeof(buff) - 4);
529 TEST_CHECK(fr_dbuff_in_bytes(&child, 0xaa, 0xbb) == 2);
530 TEST_CHECK(fr_dbuff_used(&dbuff) == 4); /* parent NOT advanced */
531
532 TEST_CASE("FR_DBUFF_ABS: start bound to parent 'start', parent not advanced");
533 fr_dbuff_init(&dbuff, buff, sizeof(buff));
534 fr_dbuff_advance(&dbuff, 4);
535 child = FR_DBUFF_ABS(&dbuff);
536 TEST_CHECK(fr_dbuff_start(&child) == fr_dbuff_start(&dbuff));
537 TEST_CHECK(fr_dbuff_current(&child) == fr_dbuff_current(&dbuff));
538 TEST_CHECK(fr_dbuff_used(&child) == 4); /* current - start */
539 TEST_CHECK(fr_dbuff_in_bytes(&child, 0xaa) == 1);
540 TEST_CHECK(fr_dbuff_used(&dbuff) == 4); /* parent NOT advanced */
541
542 TEST_CASE("FR_DBUFF_BIND_CURRENT: writes advance parent 'current'");
543 fr_dbuff_init(&dbuff, buff, sizeof(buff));
544 fr_dbuff_advance(&dbuff, 4);
545 child = FR_DBUFF_BIND_CURRENT(&dbuff);
546 TEST_CHECK(fr_dbuff_start(&child) == fr_dbuff_current(&dbuff));
547 TEST_CHECK(fr_dbuff_in_bytes(&child, 0xaa, 0xbb, 0xcc) == 3);
548 TEST_CHECK(fr_dbuff_used(&dbuff) == 7); /* 4 + 3 */
549
550 TEST_CASE("FR_DBUFF_BIND_CURRENT_ABS: start bound to parent 'start', writes advance parent 'current'");
551 fr_dbuff_init(&dbuff, buff, sizeof(buff));
552 fr_dbuff_advance(&dbuff, 4);
553 child = FR_DBUFF_BIND_CURRENT_ABS(&dbuff);
554 TEST_CHECK(fr_dbuff_start(&child) == fr_dbuff_start(&dbuff));
555 TEST_CHECK(fr_dbuff_used(&child) == 4);
556 TEST_CHECK(fr_dbuff_in_bytes(&child, 0xaa, 0xbb) == 2);
557 TEST_CHECK(fr_dbuff_used(&dbuff) == 6); /* 4 + 2 */
558 TEST_CHECK(fr_dbuff_used(&child) == 6); /* child start == parent start */
559
560 TEST_CASE("FR_DBUFF_BIND_END_ABS: writes advance parent 'end' (producer side)");
561 fr_dbuff_init(&dbuff, buff, sizeof(buff));
562 child = FR_DBUFF_BIND_END_ABS(&dbuff);
563 TEST_CHECK(fr_dbuff_end(&dbuff) == buff + sizeof(buff));
564 TEST_CHECK(fr_dbuff_in_bytes(&child, 0x01, 0x02, 0x03, 0x04, 0x05) == 5);
565 TEST_CHECK(fr_dbuff_end(&dbuff) == buff + 5); /* parent 'end' pulled back to producer position */
566 TEST_CHECK(fr_dbuff_remaining(&dbuff) == 5); /* consumer can now read what was produced */
567
568 TEST_CASE("FR_DBUFF_MAX: caps available space, non-bind variant leaves parent alone");
569 fr_dbuff_init(&dbuff, buff, sizeof(buff));
570 child = FR_DBUFF_MAX(&dbuff, 4);
571 TEST_CHECK(fr_dbuff_remaining(&child) == 4);
572 TEST_CHECK(fr_dbuff_in_bytes(&child, 0x01, 0x02, 0x03, 0x04) == 4);
573 TEST_CHECK(fr_dbuff_in_bytes(&child, 0x05) == -1); /* capped: 1 byte short */
574 TEST_CHECK(fr_dbuff_used(&dbuff) == 0); /* parent NOT advanced */
575
576 TEST_CASE("FR_DBUFF_MAX: _max larger than remaining is clamped to remaining");
577 child = FR_DBUFF_MAX(&dbuff, 2 * sizeof(buff));
578 TEST_CHECK(fr_dbuff_remaining(&child) == sizeof(buff));
579}
580
581/** Test the measurement / accessor macros against both a dbuff and a marker.
582 *
583 * Covers fr_dbuff_len, fr_dbuff_buff, fr_dbuff_end, fr_dbuff_ptr,
584 * fr_dbuff_behind and fr_dbuff_ahead, which the existing tests never touch.
585 */
586static void test_dbuff_measure(void)
587{
588 fr_dbuff_t dbuff;
590 uint8_t buff[10] = "";
591
592 fr_dbuff_init(&dbuff, buff, sizeof(buff));
593
594 TEST_CASE("dbuff accessors");
595 TEST_CHECK(fr_dbuff_len(&dbuff) == sizeof(buff));
596 TEST_CHECK(fr_dbuff_buff(&dbuff) == buff);
597 TEST_CHECK(fr_dbuff_start(&dbuff) == buff);
598 TEST_CHECK(fr_dbuff_current(&dbuff) == buff);
599 TEST_CHECK(fr_dbuff_end(&dbuff) == buff + sizeof(buff));
600 TEST_CHECK(fr_dbuff_ptr(&dbuff) == &dbuff);
601
602 TEST_CASE("marker behind then ahead of parent");
603 fr_dbuff_marker(&m, &dbuff);
604 fr_dbuff_advance(&dbuff, 6);
605 TEST_CHECK(fr_dbuff_behind(&m) == 6); /* marker 6 bytes behind parent */
606 TEST_CHECK(fr_dbuff_ahead(&m) == 0);
607 fr_dbuff_advance(&m, 8);
608 TEST_CHECK(fr_dbuff_ahead(&m) == 2); /* marker now 2 bytes ahead */
609 TEST_CHECK(fr_dbuff_behind(&m) == 0);
610
611 TEST_CASE("marker accessors resolve through parent");
614 TEST_CHECK(fr_dbuff_end(&m) == buff + sizeof(buff));
615 TEST_CHECK(fr_dbuff_len(&m) == sizeof(buff));
616 TEST_CHECK(fr_dbuff_ptr(&m) == &dbuff);
617 TEST_CHECK(fr_dbuff_current(&m) == buff + 8);
618 TEST_CHECK(fr_dbuff_used(&m) == 8);
620}
621
622/** Test fr_dbuff_set (by size_t, pointer, marker) and fr_dbuff_set_end.
623 *
624 * The backing array is deliberately larger than the dbuff window so that we
625 * can form a pointer past the dbuff 'end' without forming a pointer outside
626 * the real allocation (which would be undefined behaviour).
627 */
628static void test_dbuff_set(void)
629{
630 uint8_t backing[32];
631 fr_dbuff_t dbuff;
633
634 TEST_CASE("fr_dbuff_set by size_t offset, pointer, and out-of-range");
635 fr_dbuff_init(&dbuff, backing, 10);
636 TEST_CHECK(fr_dbuff_set(&dbuff, (size_t)5) == 5);
637 TEST_CHECK(fr_dbuff_current(&dbuff) == backing + 5);
638 TEST_CHECK(fr_dbuff_set(&dbuff, backing + 2) == -3); /* moving backwards returns the signed diff */
639 TEST_CHECK(fr_dbuff_current(&dbuff) == backing + 2);
640 TEST_CHECK(fr_dbuff_set(&dbuff, backing + 20) == -10); /* past 'end': bytes over, no move */
641 TEST_CHECK(fr_dbuff_current(&dbuff) == backing + 2);
642
643 TEST_CASE("fr_dbuff_set from a marker");
644 fr_dbuff_set_to_start(&dbuff);
645 fr_dbuff_marker(&m, &dbuff);
646 fr_dbuff_advance(&m, 7);
647 TEST_CHECK(fr_dbuff_set(&dbuff, &m) == 7);
649
650 TEST_CASE("fr_dbuff_set_end trims the 'end' pointer");
651 fr_dbuff_init(&dbuff, backing, 10);
652 fr_dbuff_advance(&dbuff, 3);
653 fr_dbuff_set_end(&dbuff, backing + 6);
654 TEST_CHECK(fr_dbuff_end(&dbuff) == backing + 6);
655 TEST_CHECK(fr_dbuff_remaining(&dbuff) == 3);
656#ifdef NDEBUG
657 fr_dbuff_set_end(&dbuff, backing + 8); /* beyond current 'end': asserts in debug builds */
658#endif
659 TEST_CHECK(fr_dbuff_end(&dbuff) == backing + 6);
660}
661
662/** Test fr_dbuff_advance_extend against a talloc-backed (extensible) dbuff. */
664{
665 fr_dbuff_t dbuff;
666 fr_dbuff_uctx_talloc_t tctx;
667
668 TEST_CHECK(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 4, 16) == &dbuff);
669
670 TEST_CASE("advance within the initial allocation");
671 TEST_CHECK(fr_dbuff_advance_extend(&dbuff, 2) == 2);
672 TEST_CHECK(fr_dbuff_used(&dbuff) == 2);
673
674 TEST_CASE("advance past the current size triggers an extend");
675 TEST_CHECK(fr_dbuff_advance_extend(&dbuff, 10) == 10);
676 TEST_CHECK(fr_dbuff_used(&dbuff) == 12);
677
678 TEST_CASE("advance past max fails and does not advance");
679 TEST_CHECK(fr_dbuff_advance_extend(&dbuff, 10) < 0);
680 TEST_CHECK(fr_dbuff_used(&dbuff) == 12);
681
682 fr_dbuff_free_talloc(&dbuff);
683}
684
685/** Test fr_dbuff_memset. */
686static void test_dbuff_memset(void)
687{
688 fr_dbuff_t dbuff;
689 uint8_t buff[8] = "";
690
691 fr_dbuff_init(&dbuff, buff, sizeof(buff));
692
693 TEST_CASE("memset writes and advances");
694 TEST_CHECK(fr_dbuff_memset(&dbuff, 0xa5, 5) == 5);
695 TEST_CHECK(fr_dbuff_used(&dbuff) == 5);
696 for (size_t i = 0; i < 5; i++) TEST_CHECK(buff[i] == 0xa5);
697
698 TEST_CASE("memset that does not fit returns bytes needed and does not advance");
699 TEST_CHECK(fr_dbuff_memset(&dbuff, 0x00, 5) == -2); /* only 3 left, need 5 */
700 TEST_CHECK(fr_dbuff_used(&dbuff) == 5);
701}
702
703/** Test fr_dbuff_in_memcpy, fr_dbuff_in_memcpy_partial and fr_dbuff_in_bytes_partial. */
704static void test_dbuff_in_memcpy(void)
705{
706 uint8_t buff[8] = "";
707 uint8_t const src[] = { 0x11, 0x22, 0x33, 0x44 };
708 uint8_t sbuf[4] = { 0x0a, 0x0b, 0x0c, 0x0d };
709 char const *str = "abc";
710 fr_dbuff_t dbuff;
711 fr_dbuff_t src_dbuff;
712
713 TEST_CASE("exact copy from a byte buffer");
714 fr_dbuff_init(&dbuff, buff, sizeof(buff));
715
716 /*
717 * Note _fr_dbuff_in_memcpy(), to avoid false positive complaints with -Werror=stringop-overread
718 *
719 * We could suppress the warn
720 */
721 TEST_CHECK(_fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(&dbuff), &dbuff, src, sizeof(src)) == 4);
722 TEST_CHECK(fr_dbuff_used(&dbuff) == 4);
723 TEST_CHECK(memcmp(buff, src, 4) == 0);
724
725 TEST_CASE("copy from a C string with SIZE_MAX uses strlen");
726 fr_dbuff_init(&dbuff, buff, sizeof(buff));
727 TEST_CHECK(fr_dbuff_in_memcpy(&dbuff, str, SIZE_MAX) == 3);
728 TEST_CHECK(memcmp(buff, str, 3) == 0);
729
730 TEST_CASE("copy that does not fit fails entirely and does not advance");
731 fr_dbuff_init(&dbuff, buff, 2);
732 TEST_CHECK(_fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(&dbuff), &dbuff, src, sizeof(src)) == -2);
733 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
734
735 TEST_CASE("copy from another dbuff, source is not advanced");
736 fr_dbuff_init(&dbuff, buff, sizeof(buff));
737 fr_dbuff_init(&src_dbuff, sbuf, sizeof(sbuf));
738 TEST_CHECK(fr_dbuff_in_memcpy(&dbuff, &src_dbuff, 3) == 3);
739 TEST_CHECK(fr_dbuff_used(&dbuff) == 3);
740 TEST_CHECK(fr_dbuff_used(&src_dbuff) == 0);
741 TEST_CHECK(memcmp(buff, sbuf, 3) == 0);
742
743 TEST_CASE("SIZE_MAX with a dbuff source copies the source's remaining bytes");
744 fr_dbuff_init(&dbuff, buff, sizeof(buff));
745 fr_dbuff_init(&src_dbuff, sbuf, sizeof(sbuf));
746 TEST_CHECK(_fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(&dbuff), &dbuff, &src_dbuff.p, &src_dbuff, SIZE_MAX) == 4);
747 TEST_CHECK(fr_dbuff_used(&dbuff) == 4);
748
749 TEST_CASE("partial copy writes as much as fits and reports it");
750 fr_dbuff_init(&dbuff, buff, 2);
751 TEST_CHECK(_fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(&dbuff), &dbuff, src, sizeof(src)) == 2);
752 TEST_CHECK(fr_dbuff_used(&dbuff) == 2);
753 TEST_CHECK(memcmp(buff, src, 2) == 0);
754
755 TEST_CASE("in_bytes_partial truncates to the available space");
756 fr_dbuff_init(&dbuff, buff, 3);
757 TEST_CHECK(fr_dbuff_in_bytes_partial(&dbuff, 0xde, 0xad, 0xbe, 0xef) == 3);
758 TEST_CHECK(fr_dbuff_used(&dbuff) == 3);
759}
760
761/** Test fr_dbuff_marker_release, fr_dbuff_marker_release_behind and _ahead. */
763{
764 uint8_t buff[16];
765 fr_dbuff_t dbuff;
766 fr_dbuff_marker_t m1, m2;
767
768 TEST_CASE("plain release trims the marker list back to the previous marker");
769 fr_dbuff_init(&dbuff, buff, sizeof(buff));
770 fr_dbuff_marker(&m1, &dbuff);
771 fr_dbuff_marker(&m2, &dbuff);
772 TEST_CHECK(dbuff.m == &m2); /* newest marker at the head */
774 TEST_CHECK(dbuff.m == &m1);
776 TEST_CHECK(dbuff.m == NULL);
777
778 TEST_CASE("release_behind returns how far the marker trailed the parent");
779 fr_dbuff_init(&dbuff, buff, sizeof(buff));
780 fr_dbuff_marker(&m1, &dbuff);
781 fr_dbuff_advance(&dbuff, 4);
782 fr_dbuff_marker(&m2, &dbuff);
783 fr_dbuff_advance(&dbuff, 3); /* parent at 7, m2 at 4 */
785 TEST_CHECK(dbuff.m == &m1);
786
787 TEST_CASE("release_ahead returns how far the marker led the parent");
788 fr_dbuff_set(&m1, (size_t)10); /* m1 at 10, parent at 7 */
790 TEST_CHECK(dbuff.m == NULL);
791}
792
793/** Test fr_dbuff_out_int64v, which sign-extends based on the most significant bit. */
794static void test_dbuff_out_int64v(void)
795{
796 uint8_t const pos[] = { 0x7f, 0xff }; /* MSB clear -> positive */
797 uint8_t const neg[] = { 0xff, 0x00 }; /* MSB set -> negative */
798 fr_dbuff_t dbuff;
799 int64_t val;
800
801 TEST_CASE("positive two-byte value");
802 fr_dbuff_init(&dbuff, pos, sizeof(pos));
803 TEST_CHECK(fr_dbuff_out_int64v(&val, &dbuff, 2) == 2);
804 TEST_CHECK(val == 0x7fff);
805
806 TEST_CASE("negative two-byte value is sign extended");
807 fr_dbuff_init(&dbuff, neg, sizeof(neg));
808 TEST_CHECK(fr_dbuff_out_int64v(&val, &dbuff, 2) == 2);
809 TEST_CHECK(val == -256);
810
811 TEST_CASE("single positive byte");
812 fr_dbuff_init(&dbuff, pos, sizeof(pos));
813 TEST_CHECK(fr_dbuff_out_int64v(&val, &dbuff, 1) == 1);
814 TEST_CHECK(val == 0x7f);
815
816 TEST_CASE("not enough data returns bytes needed");
817 fr_dbuff_init(&dbuff, pos, 1);
818 TEST_CHECK(fr_dbuff_out_int64v(&val, &dbuff, 2) == -1);
819}
820
821/** Test fr_dbuff_shift moves unconsumed content to the front of the buffer. */
822static void test_dbuff_shift(void)
823{
824 uint8_t buff[8] = "";
825 fr_dbuff_t dbuff;
826
827 memcpy(buff, "ABCDEFGH", sizeof(buff));
828 fr_dbuff_init(&dbuff, buff, sizeof(buff));
829 fr_dbuff_advance(&dbuff, 3); /* consume "ABC" */
830
831 TEST_CASE("shift discards consumed bytes and moves the rest down");
832 TEST_CHECK(fr_dbuff_shift(&dbuff, 3) == 3);
833 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
834 TEST_CHECK(memcmp(buff, "DEFGH", 5) == 0);
835 TEST_CHECK(fr_dbuff_remaining(&dbuff) == 5); /* 'end' pulled down by the shift */
836}
837
838/** Test fr_dbuff_update repoints the dbuff and its markers after a buffer move. */
839static void test_dbuff_update(void)
840{
841 uint8_t buff[8] = "";
842 uint8_t newbuff[8] = "";
843 fr_dbuff_t dbuff;
845
846 fr_dbuff_init(&dbuff, buff, sizeof(buff));
847 fr_dbuff_advance(&dbuff, 4);
848 fr_dbuff_marker(&m, &dbuff); /* marker at offset 4 */
849 fr_dbuff_set_to_start(&dbuff);
850 fr_dbuff_advance(&dbuff, 2); /* dbuff 'current' at offset 2 */
851
852 TEST_CASE("relative offsets are preserved against the new buffer");
853 fr_dbuff_update(&dbuff, newbuff, sizeof(newbuff));
854 TEST_CHECK(fr_dbuff_buff(&dbuff) == newbuff);
855 TEST_CHECK(fr_dbuff_start(&dbuff) == newbuff);
856 TEST_CHECK(fr_dbuff_current(&dbuff) == newbuff + 2);
857 TEST_CHECK(fr_dbuff_end(&dbuff) == newbuff + sizeof(newbuff));
858 TEST_CHECK(fr_dbuff_current(&m) == newbuff + 4); /* marker offset preserved */
859}
860
861/** Test fr_dbuff_trim_talloc, fr_dbuff_reset_talloc and fr_dbuff_free_talloc. */
863{
864 fr_dbuff_t dbuff;
865 fr_dbuff_uctx_talloc_t tctx;
866
867 TEST_CHECK(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 32, 128) == &dbuff);
868 TEST_CHECK(talloc_array_length(dbuff.buff) == 32);
869 TEST_CHECK(fr_dbuff_in_bytes(&dbuff, 0x01, 0x02, 0x03, 0x04) == 4);
870
871 TEST_CASE("trim to content length (SIZE_MAX)");
872 TEST_CHECK(fr_dbuff_trim_talloc(&dbuff, SIZE_MAX) == 0);
873 TEST_CHECK(talloc_array_length(dbuff.buff) == 4);
874 TEST_CHECK(fr_dbuff_len(&dbuff) == 4);
875
876 TEST_CASE("trim to an explicit length");
877 TEST_CHECK(fr_dbuff_trim_talloc(&dbuff, 2) == 0);
878 TEST_CHECK(talloc_array_length(dbuff.buff) == 2);
879
880 TEST_CASE("reset restores the initial length and clears the position");
881 TEST_CHECK(fr_dbuff_reset_talloc(&dbuff) == 0);
882 TEST_CHECK(talloc_array_length(dbuff.buff) == 32);
883 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
884
885 TEST_CASE("free_talloc releases the buffer");
886 fr_dbuff_free_talloc(&dbuff);
887 TEST_CHECK(dbuff.buff == NULL);
888}
889
890/** Test FR_DBUFF_TMP, the compound-literal dbuff. */
891static void test_dbuff_tmp(void)
892{
893 uint8_t buff[8] = "";
894 fr_dbuff_t tmp = FR_DBUFF_TMP(buff, sizeof(buff));
895
896 TEST_CASE("compound literal points at the supplied buffer and is writable");
899 TEST_CHECK(fr_dbuff_end(&tmp) == buff + sizeof(buff));
900 TEST_CHECK(fr_dbuff_in_bytes(&tmp, 0x01, 0x02) == 2);
901 TEST_CHECK(buff[0] == 0x01);
902 TEST_CHECK(buff[1] == 0x02);
903}
904
905/** Test the extension-request API: fr_dbuff_extend, fr_dbuff_extend_lowat,
906 * fr_dbuff_is_extendable and fr_dbuff_was_extended.
907 */
908static void test_dbuff_extend(void)
909{
910 uint8_t buff[8];
911 fr_dbuff_t dbuff;
912 fr_dbuff_uctx_talloc_t tctx;
914
915 TEST_CASE("fixed buffer: extend returns remaining and never grows");
916 fr_dbuff_init(&dbuff, buff, sizeof(buff));
917 TEST_CHECK(fr_dbuff_extend(&dbuff) == sizeof(buff));
918
919 TEST_CASE("fixed buffer at end: cannot satisfy lowat");
920 status = FR_DBUFF_EXTENDABLE;
921 fr_dbuff_advance(&dbuff, sizeof(buff));
922 TEST_CHECK(fr_dbuff_extend_lowat(&status, &dbuff, 4) == 0);
924 TEST_CHECK(fr_dbuff_was_extended(status) == 0);
925
926 TEST_CASE("talloc buffer: extend grows and flags report it");
927 TEST_CHECK(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 4, 64) == &dbuff);
928 status = FR_DBUFF_EXTENDABLE;
929 fr_dbuff_advance(&dbuff, 4); /* remaining now 0 */
930 TEST_CHECK(fr_dbuff_extend_lowat(&status, &dbuff, 8) >= 8);
933
934 fr_dbuff_free_talloc(&dbuff);
935}
936
938 /*
939 * Basic tests
940 */
941 { "fr_dbuff_init", test_dbuff_init },
942 { "fr_dbuff_init_no_parent", test_dbuff_init_no_parent },
943 { "fr_dbuff_max", test_dbuff_max },
944 { "fr_dbuff_in", test_dbuff_net_encode },
945 { "fr_dbuff_no_advance", test_dbuff_no_advance },
946 { "fr_dbuff_move", test_dbuff_move },
947 { "fr_dbuff_talloc_extend", test_dbuff_talloc_extend },
948 { "fr_dbuff_talloc_extend_multi_level", test_dbuff_talloc_extend_multi_level },
949 { "fr_dbuff_fd", test_dbuff_fd },
950 { "fr_dbuff_fd_max", test_dbuff_fd_max },
951 { "fr_dbuff_out", test_dbuff_out },
952
953 /*
954 * Child dbuffs, accessors, positioning and lifecycle
955 */
956 { "fr_dbuff_child", test_dbuff_child },
957 { "fr_dbuff_measure", test_dbuff_measure },
958 { "fr_dbuff_set", test_dbuff_set },
959 { "fr_dbuff_advance_extend", test_dbuff_advance_extend },
960 { "fr_dbuff_memset", test_dbuff_memset },
961 { "fr_dbuff_in_memcpy", test_dbuff_in_memcpy },
962 { "fr_dbuff_marker_release", test_dbuff_marker_release },
963 { "fr_dbuff_out_int64v", test_dbuff_out_int64v },
964 { "fr_dbuff_shift", test_dbuff_shift },
965 { "fr_dbuff_update", test_dbuff_update },
966 { "fr_dbuff_trim_reset_talloc", test_dbuff_trim_reset_talloc },
967 { "fr_dbuff_tmp", test_dbuff_tmp },
968 { "fr_dbuff_extend", test_dbuff_extend },
969
971};
972
#define TEST_CHECK(cond)
Definition acutest.h:87
#define TEST_CASE(name)
Definition acutest.h:186
#define TEST_TERMINATOR
Definition acutest.h:64
#define TEST_CHECK_SLEN(_got, _exp)
#define TEST_CHECK_LEN(_got, _exp)
int fr_dbuff_reset_talloc(fr_dbuff_t *dbuff)
Reset a talloced buffer to its initial length, clearing any data stored.
Definition dbuff.c:332
int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len)
Trim a talloced dbuff to the minimum length required to represent the contained string.
Definition dbuff.c:297
void fr_dbuff_update(fr_dbuff_t *dbuff, uint8_t *new_buff, size_t new_len)
Update all markers and pointers in the set of dbuffs to point to new_buff.
Definition dbuff.c:79
size_t fr_dbuff_shift(fr_dbuff_t *dbuff, size_t shift)
Shift the contents of the dbuff, returning the number of bytes we managed to shift.
Definition dbuff.c:116
#define fr_dbuff_in_bytes_partial(_dbuff,...)
Copy a partial byte sequence into a dbuff.
Definition dbuff.h:1460
#define fr_dbuff_behind(_dbuff_or_marker)
How many bytes the dbuff or marker is behind its parent.
Definition dbuff.h:794
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
Definition dbuff.h:1077
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:775
#define FR_DBUFF_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:239
#define fr_dbuff_ptr(_dbuff_or_marker)
Return a pointer to the dbuff.
Definition dbuff.h:866
static void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
Free the talloc buffer associated with a dbuff.
Definition dbuff.h:461
static fr_dbuff_t * fr_dbuff_init_fd(fr_dbuff_t *dbuff, fr_dbuff_uctx_fd_t *fctx, uint8_t *buff, size_t len, int fd, size_t max)
Initialise a special dbuff which automatically reads in more data as the buffer is exhausted.
Definition dbuff.h:493
#define fr_dbuff_len(_dbuff_or_marker)
The length of the underlying buffer.
Definition dbuff.h:784
static size_t fr_dbuff_marker_release_behind(fr_dbuff_marker_t *m)
Trims the linked list back to the specified pointer and return how many bytes marker was behind p.
Definition dbuff.h:1236
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:81
#define fr_dbuff_out_uint64v(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order unsigned integer.
Definition dbuff.h:1856
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:919
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1012
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition dbuff.h:362
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:906
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
Definition dbuff.h:1160
#define fr_dbuff_was_extended(_status)
Check if the dbuff was extended during the last extend call.
Definition dbuff.h:622
fr_dbuff_extend_status_t
Whether the buffer is currently extendable and whether it was extended.
Definition dbuff.h:598
@ FR_DBUFF_EXTENDABLE
dbuff can be extended
Definition dbuff.h:605
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition dbuff.h:890
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
Definition dbuff.h:1737
#define FR_DBUFF_BIND_CURRENT(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:248
#define fr_dbuff_memset(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c.
Definition dbuff.h:1506
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:668
#define fr_dbuff_advance_extend(_dbuff_or_marker, _len)
Advance current'position in dbuff or marker by _len bytes (extending if necessary)
Definition dbuff.h:1144
#define fr_dbuff_end(_dbuff_or_marker)
Return the current 'end' position of a dbuff or marker.
Definition dbuff.h:946
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
Definition dbuff.h:713
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition dbuff.h:751
#define FR_DBUFF_BIND_CURRENT_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:257
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
Definition dbuff.h:1470
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
Definition dbuff.h:1197
#define fr_dbuff_in_uint64v(_dbuff_or_marker, _num)
Copy an integer value into a dbuff or marker using our internal variable length encoding.
Definition dbuff.h:1617
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1355
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
Definition dbuff.h:1572
#define fr_dbuff_set_to_end(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'end' of the buffer.
Definition dbuff.h:1166
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:230
static void fr_dbuff_marker_release(fr_dbuff_marker_t *m)
Releases the specified marker and any markers added before it.
Definition dbuff.h:1215
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
Definition dbuff.h:309
#define fr_dbuff_is_extendable(_status)
Check if a dbuff can be extended again.
Definition dbuff.h:618
#define fr_dbuff_move(_out, _in, _len)
Copy in as many bytes as possible from one dbuff or marker to another.
Definition dbuff.h:1661
#define FR_DBUFF_BIND_END_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:268
#define fr_dbuff_ahead(_dbuff_or_marker)
How many bytes the dbuff or marker is ahead of its parent.
Definition dbuff.h:804
#define FR_DBUFF_MAX_BIND_CURRENT(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
Definition dbuff.h:326
static size_t fr_dbuff_marker_release_ahead(fr_dbuff_marker_t *m)
Trims the linked list back to the specified pointer and return how many bytes marker was ahead of p.
Definition dbuff.h:1255
static fr_dbuff_t * fr_dbuff_init_talloc(TALLOC_CTX *ctx, fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx, size_t init, size_t max)
Initialise a special dbuff which automatically extends as additional data is written.
Definition dbuff.h:419
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
Definition dbuff.h:1804
#define fr_dbuff_out_int64v(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order signed integer.
Definition dbuff.h:1896
#define fr_dbuff_set_end(_dst, _end)
Set a new 'end' position in a dbuff or marker.
Definition dbuff.h:1055
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:522
static void test_dbuff_set(void)
Test fr_dbuff_set (by size_t, pointer, marker) and fr_dbuff_set_end.
TEST_LIST
static void test_dbuff_init_no_parent(void)
Definition dbuff_tests.c:39
static void test_dbuff_extend(void)
Test the extension-request API: fr_dbuff_extend, fr_dbuff_extend_lowat, fr_dbuff_is_extendable and fr...
static void fd_body(fr_dbuff_t *dbuff, uint8_t const data[])
static void test_dbuff_fd_shell(fr_dbuff_fd_test_body body, uint8_t const data[], size_t datasize, uint8_t buff[], size_t buffsize, size_t max)
static void test_dbuff_advance_extend(void)
Test fr_dbuff_advance_extend against a talloc-backed (extensible) dbuff.
void(* fr_dbuff_fd_test_body)(fr_dbuff_t *dbuff, uint8_t const data[])
Definition dbuff_tests.c:10
static void test_dbuff_talloc_extend(void)
Test extensible dbuffs.
static void test_dbuff_out(void)
Test functions that read from dbuffs.
static void test_dbuff_max(void)
Definition dbuff_tests.c:49
static void test_dbuff_talloc_extend_multi_level(void)
static void test_dbuff_in_memcpy(void)
Test fr_dbuff_in_memcpy, fr_dbuff_in_memcpy_partial and fr_dbuff_in_bytes_partial.
static void test_dbuff_init(void)
Definition dbuff_tests.c:12
static void max_body(fr_dbuff_t *dbuff, uint8_t const data[])
static void test_dbuff_no_advance(void)
static void test_dbuff_tmp(void)
Test FR_DBUFF_TMP, the compound-literal dbuff.
static void test_dbuff_measure(void)
Test the measurement / accessor macros against both a dbuff and a marker.
static void test_dbuff_child(void)
Test the child-dbuff macros: FR_DBUFF, FR_DBUFF_ABS, FR_DBUFF_BIND_CURRENT, FR_DBUFF_BIND_CURRENT_ABS...
static void test_dbuff_memset(void)
Test fr_dbuff_memset.
static void test_dbuff_update(void)
Test fr_dbuff_update repoints the dbuff and its markers after a buffer move.
static void test_dbuff_trim_reset_talloc(void)
Test fr_dbuff_trim_talloc, fr_dbuff_reset_talloc and fr_dbuff_free_talloc.
static void test_dbuff_net_encode(void)
Test the various dbuff_net_encode() functions and macros.
Definition dbuff_tests.c:75
static void test_dbuff_move(void)
static void test_dbuff_fd(void)
static void test_dbuff_shift(void)
Test fr_dbuff_shift moves unconsumed content to the front of the buffer.
static void test_dbuff_fd_max(void)
static void test_dbuff_marker_release(void)
Test fr_dbuff_marker_release, fr_dbuff_marker_release_behind and _ahead.
static void test_dbuff_out_int64v(void)
Test fr_dbuff_out_int64v, which sign-extends based on the most significant bit.
static fr_slen_t in
Definition dict.h:882
Test enumeration values.
Definition dict_test.h:92
talloc_free(hp)
unsigned short uint16_t
uint8_t * p
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
static fr_slen_t data
Definition value.h:1340