Patrick Georgi has submitted this change. ( https://review.coreboot.org/c/coreboot/+/50799 )
Change subject: tests: Add lib/memcpy-test test case ......................................................................
tests: Add lib/memcpy-test test case
Signed-off-by: Jakub Czapiga jacz@semihalf.com Change-Id: I00464ec2db23867712cd2efd7f6cad92e3ee361a Reviewed-on: https://review.coreboot.org/c/coreboot/+/50799 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Paul Fagerburg pfagerburg@chromium.org --- M tests/lib/Makefile.inc A tests/lib/memcpy-test.c 2 files changed, 199 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Paul Fagerburg: Looks good to me, approved
diff --git a/tests/lib/Makefile.inc b/tests/lib/Makefile.inc index fb243c2..1640ce0 100644 --- a/tests/lib/Makefile.inc +++ b/tests/lib/Makefile.inc @@ -17,6 +17,7 @@ tests-y += memset-test tests-y += memcmp-test tests-y += memchr-test +tests-y += memcpy-test
string-test-srcs += tests/lib/string-test.c string-test-srcs += src/lib/string.c @@ -88,3 +89,5 @@ memchr-test-srcs += tests/lib/memchr-test.c memchr-test-srcs += src/lib/memchr.c
+memcpy-test-srcs += tests/lib/memcpy-test.c + diff --git a/tests/lib/memcpy-test.c b/tests/lib/memcpy-test.c new file mode 100644 index 0000000..842a5f0 --- /dev/null +++ b/tests/lib/memcpy-test.c @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* Include memcpy() source code and alter its name to compare results with libc memcpy() */ +#define memcpy cb_memcpy +#include "../lib/memcpy.c" +#undef memcpy + +#include <stdlib.h> +#include <tests/test.h> +#include <commonlib/helpers.h> +#include <types.h> + +#define MEMCPY_BUFFER_SZ (4 * KiB) + +/* Prototype of memcpy() from string.h was changed to cb_memcpy(). + It has to be defined again. */ +void *memcpy(void *dest, const void *src, size_t n); + +struct test_memcpy_data { + u8 *buffer_from; + u8 *buffer_to; + u8 *helper_buffer; +}; + +int setup_test(void **state) +{ + struct test_memcpy_data *s = malloc(sizeof(struct test_memcpy_data)); + + if (!s) + return -1; + + s->buffer_from = malloc(MEMCPY_BUFFER_SZ); + s->buffer_to = malloc(MEMCPY_BUFFER_SZ); + s->helper_buffer = malloc(MEMCPY_BUFFER_SZ); + + if (!s->buffer_from || !s->buffer_to || !s->helper_buffer) { + free(s->buffer_from); + free(s->buffer_to); + free(s->helper_buffer); + free(s); + return -1; + } + + /* Fill buffers with different values (other than zero) to make them distinguishable. + The helper buffer is often used as a backup of destination buffer so it has the + same value. */ + memset(s->buffer_from, 0xAB, MEMCPY_BUFFER_SZ); + memset(s->buffer_to, 0xBC, MEMCPY_BUFFER_SZ); + memset(s->helper_buffer, 0xBC, MEMCPY_BUFFER_SZ); + + *state = s; + + return 0; +} + +int teardown_test(void **state) +{ + struct test_memcpy_data *s = *state; + + free(s->buffer_from); + free(s->buffer_to); + free(s->helper_buffer); + free(s); + + return 0; +} + +/* Fill buffer with values from provided range [start; end] in circular way. */ +static void fill_buffer_data_range(u8 *buffer, size_t sz, u8 start_value, u8 end_value) +{ + for (size_t i = 0; i < sz; ++i) + buffer[i] = (start_value + i) % (end_value - start_value + 1); +} + +static void test_memcpy_full_buffer_copy(void **state) +{ + struct test_memcpy_data *s = *state; + void *res_cb; + + fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 0, 255); + + res_cb = cb_memcpy(s->buffer_to, s->buffer_from, MEMCPY_BUFFER_SZ); + + assert_ptr_equal(s->buffer_to, res_cb); + assert_memory_equal(s->buffer_from, s->buffer_to, MEMCPY_BUFFER_SZ); +} + +static void test_memcpy_zero_size(void **state) +{ + struct test_memcpy_data *s = *state; + void *res_cb; + + fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 'A', 'Z'); + + /* Expect no change in destination buffer. */ + res_cb = cb_memcpy(s->buffer_to, s->buffer_from, 0); + assert_ptr_equal(s->buffer_to, res_cb); + assert_memory_equal(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ); +} + +static void test_memcpy_buffer_part(void **state) +{ + struct test_memcpy_data *s = *state; + void *res_cb; + const size_t offset = MEMCPY_BUFFER_SZ / 4; + const size_t sz = MEMCPY_BUFFER_SZ / 2; + + /* Self-test for correct data ranges */ + assert_true(offset + sz <= MEMCPY_BUFFER_SZ); + + fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, '0', '9'); + + /* Expect only *sz* bytes of buffer to be copied. Helper buffer is used as template. */ + res_cb = cb_memcpy(s->buffer_to + offset, s->buffer_from, sz); + assert_ptr_equal(s->buffer_to + offset, res_cb); + assert_memory_equal(s->buffer_to, s->helper_buffer, offset); + assert_memory_equal(s->buffer_to + offset, s->buffer_from, sz); + assert_memory_equal(s->buffer_to + offset + sz, s->helper_buffer + offset + sz, + MEMCPY_BUFFER_SZ - (offset + sz)); +} + +static void test_memcpy_buffer_part_unaligned(void **state) +{ + struct test_memcpy_data *s = *state; + void *res_cb; + const size_t dst_offset = MEMCPY_BUFFER_SZ / 8 + 3; + const size_t src_offset = MEMCPY_BUFFER_SZ / 4 - 3; + const size_t sz = MEMCPY_BUFFER_SZ / 4 + 7; + + /* Self-test for correct data ranges */ + assert_true(dst_offset + sz <= MEMCPY_BUFFER_SZ); + assert_true(src_offset + sz <= MEMCPY_BUFFER_SZ); + + fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 0x13, 0xB7); + + res_cb = cb_memcpy(s->buffer_to + dst_offset, s->buffer_from + src_offset, sz); + assert_ptr_equal(s->buffer_to + dst_offset, res_cb); + assert_memory_equal(s->buffer_to, s->helper_buffer, dst_offset); + assert_memory_equal(s->buffer_to + dst_offset, s->buffer_from + src_offset, sz); + assert_memory_equal(s->buffer_to + dst_offset + sz, s->helper_buffer + dst_offset + sz, + MEMCPY_BUFFER_SZ - (dst_offset + sz)); +} + +static void test_memcpy_copy_to_itself(void **state) +{ + struct test_memcpy_data *s = *state; + void *res_cb; + + fill_buffer_data_range(s->buffer_to, MEMCPY_BUFFER_SZ, 'G', 'X'); + memcpy(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ); + + /* Expect no change in source/destination buffer. */ + res_cb = cb_memcpy(s->buffer_to, s->buffer_to, MEMCPY_BUFFER_SZ); + assert_ptr_equal(s->buffer_to, res_cb); + assert_memory_equal(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ); +} + +static void test_memcpy_copy_part_of_itself_to_itself(void **state) +{ + struct test_memcpy_data *s = *state; + void *res_cb; + const size_t offset = MEMCPY_BUFFER_SZ / 8; + const size_t sz = MEMCPY_BUFFER_SZ - offset; + + /* Self-test for correct data ranges */ + assert_true(offset + sz <= MEMCPY_BUFFER_SZ); + + fill_buffer_data_range(s->buffer_to, MEMCPY_BUFFER_SZ, 'd', 'v'); + memcpy(s->helper_buffer, s->buffer_to, MEMCPY_BUFFER_SZ); + + /* Expect only *sz* bytes to be overwritten and *offset* bytes to be left at the end. */ + res_cb = cb_memcpy(s->buffer_to, s->buffer_to + offset, sz); + assert_ptr_equal(s->buffer_to, res_cb); + assert_memory_equal(s->buffer_to, s->helper_buffer + offset, sz); + assert_memory_equal(s->buffer_to + sz, s->helper_buffer + sz, offset); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_memcpy_full_buffer_copy, + setup_test, teardown_test), + cmocka_unit_test_setup_teardown(test_memcpy_zero_size, + setup_test, teardown_test), + cmocka_unit_test_setup_teardown(test_memcpy_buffer_part, + setup_test, teardown_test), + cmocka_unit_test_setup_teardown(test_memcpy_buffer_part_unaligned, + setup_test, teardown_test), + cmocka_unit_test_setup_teardown(test_memcpy_copy_to_itself, + setup_test, teardown_test), + cmocka_unit_test_setup_teardown(test_memcpy_copy_part_of_itself_to_itself, + setup_test, teardown_test), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +}