| // 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); |