2021-02-16 13:27:17 +01:00
|
|
|
/* 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,
|
2022-01-10 14:36:47 +01:00
|
|
|
MEMCPY_BUFFER_SZ - (offset + sz));
|
2021-02-16 13:27:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2022-01-10 14:36:47 +01:00
|
|
|
MEMCPY_BUFFER_SZ - (dst_offset + sz));
|
2021-02-16 13:27:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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[] = {
|
2022-01-10 14:36:47 +01:00
|
|
|
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),
|
2021-02-16 13:27:17 +01:00
|
|
|
cmocka_unit_test_setup_teardown(test_memcpy_copy_part_of_itself_to_itself,
|
|
|
|
setup_test, teardown_test),
|
|
|
|
};
|
|
|
|
|
2021-08-25 16:27:35 +02:00
|
|
|
return cb_run_group_tests(tests, NULL, NULL);
|
2021-02-16 13:27:17 +01:00
|
|
|
}
|