5#include <freeradius-devel/util/dbuff.h>
14 uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04 };
40{
uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04 };
43 TEST_CASE(
"Confirm init returns parentless dbuff");
51 uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
55 TEST_CASE(
"Confirm max constrains available space");
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;
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
96 TEST_CASE(
"Generate wire format unsigned 16-bit value");
104 TEST_CASE(
"Generate wire format unsigned 16-bit value using marker");
111 TEST_CASE(
"Generate wire format unsigned 32-bit value");
118 TEST_CASE(
"Generate wire format unsigned 64-bit value");
125 TEST_CASE(
"Generate wire format signed 16-bit value");
132 TEST_CASE(
"Generate wire format signed 32-bit value");
139 TEST_CASE(
"Generate wire format signed 64-bit value");
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];
152 for (num_bytes = 1; (val & ~((uint64_t) 0xff)) != 0; num_bytes++) val >>= 8;
156 for (
int j = num_bytes; --j >= 0; ) {
170 TEST_CHECK(memcmp(&float_out, &float_in,
sizeof(
float)) == 0);
172 TEST_CASE(
"Generate wire-format double");
178 TEST_CHECK(memcmp(&double_out, &double_in,
sizeof(
double)) == 0);
180 TEST_CASE(
"Refuse to write to too-small space");
185 TEST_CASE(
"Input bytes using dbuff current position");
203 uint8_t in[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
206 size_t init_remaining;
208 TEST_CASE(
"Confirm no-advance dbuff operations don't affect ancestors' position");
211 no_advance_dbuff =
FR_DBUFF(&dbuff);
223 uint8_t buff1[26], buff2[26], buff3[10];
227 memcpy(buff1,
"abcdefghijklmnopqrstuvwxyz",
sizeof(buff1));
228 memcpy(buff2,
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
sizeof(buff2));
229 memcpy(buff3,
"0123456789",
sizeof(buff3));
240 TEST_CHECK(memcmp(dbuff1.start,
"ABCDEFGHIJKLMnopqrstuvwxyz", 26) == 0);
246 TEST_CHECK(memcmp(dbuff2.start,
"ABCD0123456789OPQRSTUVWXYZ", 26) == 0);
253 TEST_CHECK(memcmp(dbuff1.start,
"ABCDEFGHIJKLMHIJKLMtuvwxyz", 26) == 0);
259 TEST_CHECK(memcmp(dbuff2.start,
"ABCD0123456789HIJKLMtuWXYZ", 26) == 0);
269 fr_dbuff_uctx_talloc_t tctx1, tctx2;
271 uint8_t const value[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
281 TEST_CASE(
"Markers track extended buffer");
283 TEST_CASE(
"Already-written content stays with the buffer");
285 TEST_CASE(
"Refuse to extend past specified maximum");
287 TEST_CASE(
"Extend move destination if possible and input length demands");
303 fr_dbuff_uctx_talloc_t tctx;
311 TEST_CASE(
"Check that dbuff2 inherits extend fields");
318 TEST_CASE(
"Check that FR_DBUFF_MAX_BIND_CURRENT() is not extensible");
337 fr_dbuff_uctx_fd_t fctx;
359 TEST_CASE(
"Leftover byte plus data from next extend");
371 uint8_t const data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
372 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
390 TEST_CASE(
"Confirm that max precludes another shift/extend");
396 uint8_t const data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
397 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
409 uint8_t const buff1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
419 uint64_t u64val2 = 0;
424 float fval1 = 1.5, fval2 = 0;
425 double dval1 = 2048.0625, dval2 = 0;
430 TEST_CASE(
"Check dbuff reads of unsigned integers");
441 TEST_CASE(
"Don't walk off the end of the buffer");
444 TEST_CASE(
"Check dbuff reads using markers");
452 TEST_CASE(
"Check dbuff reads of signed integers");
464 TEST_CASE(
"Check dbuff reads of floating point values");
468 TEST_CHECK(memcmp(&fval1, &fval2,
sizeof(fval1)) == 0);
473 TEST_CHECK(memcmp(&dval1, &dval2,
sizeof(dval1)) == 0);
475 TEST_CASE(
"Check variable length uint64_t read");
489 memset(buff3, 0,
sizeof(buff3));
501 memset(buff3, 0,
sizeof(buff3));
521 TEST_CASE(
"FR_DBUFF: start bound to parent 'current', parent not advanced");
532 TEST_CASE(
"FR_DBUFF_ABS: start bound to parent 'start', parent not advanced");
542 TEST_CASE(
"FR_DBUFF_BIND_CURRENT: writes advance parent 'current'");
550 TEST_CASE(
"FR_DBUFF_BIND_CURRENT_ABS: start bound to parent 'start', writes advance parent 'current'");
560 TEST_CASE(
"FR_DBUFF_BIND_END_ABS: writes advance parent 'end' (producer side)");
568 TEST_CASE(
"FR_DBUFF_MAX: caps available space, non-bind variant leaves parent alone");
576 TEST_CASE(
"FR_DBUFF_MAX: _max larger than remaining is clamped to remaining");
602 TEST_CASE(
"marker behind then ahead of parent");
611 TEST_CASE(
"marker accessors resolve through parent");
634 TEST_CASE(
"fr_dbuff_set by size_t offset, pointer, and out-of-range");
650 TEST_CASE(
"fr_dbuff_set_end trims the 'end' pointer");
666 fr_dbuff_uctx_talloc_t tctx;
670 TEST_CASE(
"advance within the initial allocation");
674 TEST_CASE(
"advance past the current size triggers an extend");
678 TEST_CASE(
"advance past max fails and does not advance");
698 TEST_CASE(
"memset that does not fit returns bytes needed and does not advance");
707 uint8_t const src[] = { 0x11, 0x22, 0x33, 0x44 };
708 uint8_t sbuf[4] = { 0x0a, 0x0b, 0x0c, 0x0d };
709 char const *str =
"abc";
713 TEST_CASE(
"exact copy from a byte buffer");
721 TEST_CHECK(_fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(&dbuff), &dbuff, src,
sizeof(src)) == 4);
725 TEST_CASE(
"copy from a C string with SIZE_MAX uses strlen");
730 TEST_CASE(
"copy that does not fit fails entirely and does not advance");
732 TEST_CHECK(_fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(&dbuff), &dbuff, src,
sizeof(src)) == -2);
735 TEST_CASE(
"copy from another dbuff, source is not advanced");
743 TEST_CASE(
"SIZE_MAX with a dbuff source copies the source's remaining bytes");
746 TEST_CHECK(_fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(&dbuff), &dbuff, &src_dbuff.
p, &src_dbuff, SIZE_MAX) == 4);
749 TEST_CASE(
"partial copy writes as much as fits and reports it");
751 TEST_CHECK(_fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(&dbuff), &dbuff, src,
sizeof(src)) == 2);
755 TEST_CASE(
"in_bytes_partial truncates to the available space");
768 TEST_CASE(
"plain release trims the marker list back to the previous marker");
778 TEST_CASE(
"release_behind returns how far the marker trailed the parent");
787 TEST_CASE(
"release_ahead returns how far the marker led the parent");
796 uint8_t const pos[] = { 0x7f, 0xff };
797 uint8_t const neg[] = { 0xff, 0x00 };
806 TEST_CASE(
"negative two-byte value is sign extended");
816 TEST_CASE(
"not enough data returns bytes needed");
827 memcpy(
buff,
"ABCDEFGH",
sizeof(
buff));
831 TEST_CASE(
"shift discards consumed bytes and moves the rest down");
852 TEST_CASE(
"relative offsets are preserved against the new buffer");
865 fr_dbuff_uctx_talloc_t tctx;
868 TEST_CHECK(talloc_array_length(dbuff.buff) == 32);
871 TEST_CASE(
"trim to content length (SIZE_MAX)");
873 TEST_CHECK(talloc_array_length(dbuff.buff) == 4);
878 TEST_CHECK(talloc_array_length(dbuff.buff) == 2);
880 TEST_CASE(
"reset restores the initial length and clears the position");
882 TEST_CHECK(talloc_array_length(dbuff.buff) == 32);
885 TEST_CASE(
"free_talloc releases the buffer");
896 TEST_CASE(
"compound literal points at the supplied buffer and is writable");
912 fr_dbuff_uctx_talloc_t tctx;
915 TEST_CASE(
"fixed buffer: extend returns remaining and never grows");
919 TEST_CASE(
"fixed buffer at end: cannot satisfy lowat");
926 TEST_CASE(
"talloc buffer: extend grows and flags report it");
#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.
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.
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.
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.
#define fr_dbuff_in_bytes_partial(_dbuff,...)
Copy a partial byte sequence into a dbuff.
#define fr_dbuff_behind(_dbuff_or_marker)
How many bytes the dbuff or marker is behind its parent.
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
#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...
#define FR_DBUFF_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define fr_dbuff_ptr(_dbuff_or_marker)
Return a pointer to the dbuff.
static void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
Free the talloc buffer associated with a dbuff.
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.
#define fr_dbuff_len(_dbuff_or_marker)
The length of the underlying buffer.
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.
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
#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.
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
#define fr_dbuff_was_extended(_status)
Check if the dbuff was extended during the last extend call.
fr_dbuff_extend_status_t
Whether the buffer is currently extendable and whether it was extended.
@ FR_DBUFF_EXTENDABLE
dbuff can be extended
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
#define FR_DBUFF_BIND_CURRENT(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define fr_dbuff_memset(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c.
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
#define fr_dbuff_advance_extend(_dbuff_or_marker, _len)
Advance current'position in dbuff or marker by _len bytes (extending if necessary)
#define fr_dbuff_end(_dbuff_or_marker)
Return the current 'end' position of a dbuff or marker.
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
#define FR_DBUFF_BIND_CURRENT_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
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.
#define fr_dbuff_in_uint64v(_dbuff_or_marker, _num)
Copy an integer value into a dbuff or marker using our internal variable length encoding.
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
#define fr_dbuff_set_to_end(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'end' of the buffer.
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
static void fr_dbuff_marker_release(fr_dbuff_marker_t *m)
Releases the specified marker and any markers added before it.
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
#define fr_dbuff_is_extendable(_status)
Check if a dbuff can be extended again.
#define fr_dbuff_move(_out, _in, _len)
Copy in as many bytes as possible from one dbuff or marker to another.
#define FR_DBUFF_BIND_END_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define fr_dbuff_ahead(_dbuff_or_marker)
How many bytes the dbuff or marker is ahead of its parent.
#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.
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.
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.
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
#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.
#define fr_dbuff_set_end(_dst, _end)
Set a new 'end' position in a dbuff or marker.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static void test_dbuff_set(void)
Test fr_dbuff_set (by size_t, pointer, marker) and fr_dbuff_set_end.
static void test_dbuff_init_no_parent(void)
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[])
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)
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)
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.
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 char buff[sizeof("18446744073709551615")+3]