u-boot/test/lib/membuf.c
Simon Glass 142a3cb63c membuf: Add some tests
Add tests for the membuf implementation.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-04-03 16:54:49 -06:00

239 lines
5.2 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2024 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <membuf.h>
#include <os.h>
#include <rand.h>
#include <string.h>
#include <test/lib.h>
#include <test/test.h>
#include <test/ut.h>
#define TEST_SIZE 16
#define TEST_COUNT 10000
static void membuf_zero(struct membuf *mb)
{
memset(mb->start, '\0', mb->end - mb->start);
}
static int membuf_check(struct unit_test_state *uts, struct membuf *mb,
int value)
{
/* head is out of range */
ut_assert(!(mb->head < mb->start || mb->head >= mb->end));
/* tail is out of range */
ut_assert(!(mb->tail < mb->start || mb->tail >= mb->end));
return 0;
}
/* write from 1 to test_size bytes, and check they come back OK */
static int lib_test_membuf_one(struct unit_test_state *uts)
{
char in[TEST_SIZE * 2], out[TEST_SIZE * 2];
struct membuf mb;
int size, ret, test_size, i;
ut_assertok(membuf_new(&mb, TEST_SIZE));
/* setup in test */
for (i = 0; i < TEST_SIZE; i++) {
in[i] = (i & 63) + '0';
in[i + TEST_SIZE] = in[i];
}
test_size = TEST_SIZE;
for (i = 1; i < TEST_COUNT; i++) {
membuf_zero(&mb);
size = rand() % test_size;
// now write patterns and check they come back OK
ret = membuf_put(&mb, in, 0);
ret = membuf_put(&mb, in, size);
ut_asserteq(size, ret);
ret = membuf_put(&mb, in, 0);
ut_assertok(membuf_check(uts, &mb, i));
ret = membuf_get(&mb, out, 0);
ret = membuf_get(&mb, out, size);
ut_asserteq(size, ret);
ret = membuf_get(&mb, out, 0);
ut_assertok(membuf_check(uts, &mb, i));
ut_asserteq_mem(in, out, size);
}
return 0;
}
LIB_TEST(lib_test_membuf_one, 0);
/* write random number of bytes, and check they come back OK */
static int lib_test_membuf_random(struct unit_test_state *uts)
{
char in[TEST_SIZE * 2];
char buf[TEST_SIZE * 2];
struct membuf mb;
int size, ret, test_size, i;
char *inptr, *outptr;
int max_avail, min_free;
ut_assertok(membuf_new(&mb, TEST_SIZE));
for (i = 0; i < TEST_SIZE; i++) {
in[i] = (i & 63) + '0';
in[i + TEST_SIZE] = in[i];
}
test_size = TEST_SIZE;
inptr = in;
outptr = in;
min_free = TEST_COUNT;
max_avail = 0;
membuf_zero(&mb);
for (i = 0; i < TEST_COUNT; i++) {
size = rand() % test_size;
if (membuf_free(&mb) < min_free)
min_free = membuf_free(&mb);
ret = membuf_put(&mb, inptr, size);
ut_assertok(membuf_check(uts, &mb, i));
inptr += ret;
if (inptr >= in + TEST_SIZE)
inptr -= TEST_SIZE;
size = rand() % (test_size - 1);
if (membuf_avail(&mb) > max_avail)
max_avail = membuf_avail(&mb);
ret = membuf_get(&mb, buf, size);
ut_assertok(membuf_check(uts, &mb, i));
ut_asserteq_mem(buf, outptr, ret);
outptr += ret;
if (outptr >= in + TEST_SIZE)
outptr -= TEST_SIZE;
}
return 0;
}
LIB_TEST(lib_test_membuf_random, 0);
/* test membuf_extend() with split segments */
static int lib_test_membuf_extend(struct unit_test_state *uts)
{
char in[TEST_SIZE * 2];
char buf[TEST_SIZE * 2];
struct membuf mb;
int ret, test_size, i, cur;
char *data;
ut_assertok(membuf_new(&mb, TEST_SIZE));
for (i = 0; i < TEST_SIZE; i++) {
in[i] = (i & 63) + '0';
in[i + TEST_SIZE] = in[i];
}
test_size = TEST_SIZE - 1;
for (cur = 0; cur <= test_size; cur++) {
ut_assertok(membuf_new(&mb, TEST_SIZE));
membuf_zero(&mb);
/*
* add some bytes, then remove them - this will force the membuf
* to have data split into two segments when we fill it
*/
ret = membuf_putraw(&mb, TEST_SIZE / 2, true, &data);
membuf_getraw(&mb, ret, true, &data);
ut_asserteq(TEST_SIZE / 2, ret);
/* fill it */
ret = membuf_put(&mb, in, cur);
ut_assertok(membuf_check(uts, &mb, cur));
ut_asserteq(cur, ret);
/* extend the buffer */
ut_assertok(membuf_extend_by(&mb, TEST_SIZE, -1));
ut_assertok(membuf_check(uts, &mb, cur));
/* check our data is still there */
ret = membuf_get(&mb, buf, TEST_SIZE * 2);
ut_assertok(membuf_check(uts, &mb, cur));
ut_asserteq(cur, ret);
ut_asserteq_mem(in, buf, cur);
membuf_uninit(&mb);
}
return 0;
}
LIB_TEST(lib_test_membuf_extend, 0);
/* test membuf_readline() with generated data */
static int lib_test_membuf_readline(struct unit_test_state *uts)
{
char *buf;
int size, cur, i, ret, readptr, cmpptr;
struct membuf mb;
char *data;
char str[256];
char *s;
ut_assertok(membuf_new(&mb, 1024));
membuf_zero(&mb);
/* Use the README as test data */
ut_assertok(os_read_file("README", (void **)&buf, &size));
cur = 0;
readptr = 0;
cmpptr = 0;
for (i = 0; i < 100000; i++, cur += 1) {
/* fill the buffer with up to 'cur' bytes */
ret = membuf_putraw(&mb, cur, false, &data);
if (ret > 0) {
int can_read = min(ret, size - readptr);
memcpy(data, &buf[readptr], can_read);
readptr += can_read;
membuf_putraw(&mb, can_read, true, &data);
ut_assertok(membuf_check(uts, &mb, i));
}
/* read a line and compare */
ret = membuf_readline(&mb, str, 256, 0, true);
ut_assertok(membuf_check(uts, &mb, i));
if (ret) {
char *ptr;
s = &buf[cmpptr];
ptr = strchr(s, '\n');
*ptr = '\0';
ut_asserteq_str(s, str);
cmpptr += strlen(s) + 1;
*ptr = '\n';
} else {
ut_assert(membuf_free(&mb));
}
}
membuf_dispose(&mb);
os_free(buf);
return 0;
}
LIB_TEST(lib_test_membuf_readline, 0);