memcpy-test.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 /* Include memcpy() source code and alter its name to compare results with libc memcpy() */ 4 #define memcpy cb_memcpy 5 #include "../lib/memcpy.c" 6 #undef memcpy 7 8 #include <stdlib.h> 9 #include <tests/test.h> 10 #include <commonlib/helpers.h> 11 #include <types.h> 12 13 #define MEMCPY_BUFFER_SZ (4 * KiB) 14 15 /* Prototype of memcpy() from string.h was changed to cb_memcpy(). 16 It has to be defined again. */ 17 void *memcpy(void *dest, const void *src, size_t n); 18 19 struct test_memcpy_data { 20 u8 *buffer_from; 21 u8 *buffer_to; 22 u8 *helper_buffer; 23 }; 24 25 int setup_test(void **state) 26 { 27 struct test_memcpy_data *s = malloc(sizeof(struct test_memcpy_data)); 28 29 if (!s) 30 return -1; 31 32 s->buffer_from = malloc(MEMCPY_BUFFER_SZ); 33 s->buffer_to = malloc(MEMCPY_BUFFER_SZ); 34 s->helper_buffer = malloc(MEMCPY_BUFFER_SZ); 35 36 if (!s->buffer_from || !s->buffer_to || !s->helper_buffer) { 37 free(s->buffer_from); 38 free(s->buffer_to); 39 free(s->helper_buffer); 40 free(s); 41 return -1; 42 } 43 44 /* Fill buffers with different values (other than zero) to make them distinguishable. 45 The helper buffer is often used as a backup of destination buffer so it has the 46 same value. */ 47 memset(s->buffer_from, 0xAB, MEMCPY_BUFFER_SZ); 48 memset(s->buffer_to, 0xBC, MEMCPY_BUFFER_SZ); 49 memset(s->helper_buffer, 0xBC, MEMCPY_BUFFER_SZ); 50 51 *state = s; 52 53 return 0; 54 } 55 56 int teardown_test(void **state) 57 { 58 struct test_memcpy_data *s = *state; 59 60 free(s->buffer_from); 61 free(s->buffer_to); 62 free(s->helper_buffer); 63 free(s); 64 65 return 0; 66 } 67 68 /* Fill buffer with values from provided range [start; end] in circular way. */ 69 static void fill_buffer_data_range(u8 *buffer, size_t sz, u8 start_value, u8 end_value) 70 { 71 for (size_t i = 0; i < sz; ++i) 72 buffer[i] = (start_value + i) % (end_value - start_value + 1); 73 } 74 75 static void test_memcpy_full_buffer_copy(void **state) 76 { 77 struct test_memcpy_data *s = *state; 78 void *res_cb; 79 80 fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 0, 255); 81 82 res_cb = cb_memcpy(s->buffer_to, s->buffer_from, MEMCPY_BUFFER_SZ); 83 84 assert_ptr_equal(s->buffer_to, res_cb); 85 assert_memory_equal(s->buffer_from, s->buffer_to, MEMCPY_BUFFER_SZ); 86 } 87 88 static void test_memcpy_zero_size(void **state) 89 { 90 struct test_memcpy_data *s = *state; 91 void *res_cb; 92 93 fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 'A', 'Z'); 94 95 /* Expect no change in destination buffer. */ 96 res_cb = cb_memcpy(s->buffer_to, s->buffer_from, 0); 97 assert_ptr_equal(s->buffer_to, res_cb); 98 assert_memory_equal(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ); 99 } 100 101 static void test_memcpy_buffer_part(void **state) 102 { 103 struct test_memcpy_data *s = *state; 104 void *res_cb; 105 const size_t offset = MEMCPY_BUFFER_SZ / 4; 106 const size_t sz = MEMCPY_BUFFER_SZ / 2; 107 108 /* Self-test for correct data ranges */ 109 assert_true(offset + sz <= MEMCPY_BUFFER_SZ); 110 111 fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, '0', '9'); 112 113 /* Expect only *sz* bytes of buffer to be copied. Helper buffer is used as template. */ 114 res_cb = cb_memcpy(s->buffer_to + offset, s->buffer_from, sz); 115 assert_ptr_equal(s->buffer_to + offset, res_cb); 116 assert_memory_equal(s->buffer_to, s->helper_buffer, offset); 117 assert_memory_equal(s->buffer_to + offset, s->buffer_from, sz); 118 assert_memory_equal(s->buffer_to + offset + sz, s->helper_buffer + offset + sz, 119 MEMCPY_BUFFER_SZ - (offset + sz)); 120 } 121 122 static void test_memcpy_buffer_part_unaligned(void **state) 123 { 124 struct test_memcpy_data *s = *state; 125 void *res_cb; 126 const size_t dst_offset = MEMCPY_BUFFER_SZ / 8 + 3; 127 const size_t src_offset = MEMCPY_BUFFER_SZ / 4 - 3; 128 const size_t sz = MEMCPY_BUFFER_SZ / 4 + 7; 129 130 /* Self-test for correct data ranges */ 131 assert_true(dst_offset + sz <= MEMCPY_BUFFER_SZ); 132 assert_true(src_offset + sz <= MEMCPY_BUFFER_SZ); 133 134 fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 0x13, 0xB7); 135 136 res_cb = cb_memcpy(s->buffer_to + dst_offset, s->buffer_from + src_offset, sz); 137 assert_ptr_equal(s->buffer_to + dst_offset, res_cb); 138 assert_memory_equal(s->buffer_to, s->helper_buffer, dst_offset); 139 assert_memory_equal(s->buffer_to + dst_offset, s->buffer_from + src_offset, sz); 140 assert_memory_equal(s->buffer_to + dst_offset + sz, s->helper_buffer + dst_offset + sz, 141 MEMCPY_BUFFER_SZ - (dst_offset + sz)); 142 } 143 144 static void test_memcpy_copy_to_itself(void **state) 145 { 146 struct test_memcpy_data *s = *state; 147 void *res_cb; 148 149 fill_buffer_data_range(s->buffer_to, MEMCPY_BUFFER_SZ, 'G', 'X'); 150 memcpy(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ); 151 152 /* Expect no change in source/destination buffer. */ 153 res_cb = cb_memcpy(s->buffer_to, s->buffer_to, MEMCPY_BUFFER_SZ); 154 assert_ptr_equal(s->buffer_to, res_cb); 155 assert_memory_equal(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ); 156 } 157 158 static void test_memcpy_copy_part_of_itself_to_itself(void **state) 159 { 160 struct test_memcpy_data *s = *state; 161 void *res_cb; 162 const size_t offset = MEMCPY_BUFFER_SZ / 8; 163 const size_t sz = MEMCPY_BUFFER_SZ - offset; 164 165 /* Self-test for correct data ranges */ 166 assert_true(offset + sz <= MEMCPY_BUFFER_SZ); 167 168 fill_buffer_data_range(s->buffer_to, MEMCPY_BUFFER_SZ, 'd', 'v'); 169 memcpy(s->helper_buffer, s->buffer_to, MEMCPY_BUFFER_SZ); 170 171 /* Expect only *sz* bytes to be overwritten and *offset* bytes to be left at the end. */ 172 res_cb = cb_memcpy(s->buffer_to, s->buffer_to + offset, sz); 173 assert_ptr_equal(s->buffer_to, res_cb); 174 assert_memory_equal(s->buffer_to, s->helper_buffer + offset, sz); 175 assert_memory_equal(s->buffer_to + sz, s->helper_buffer + sz, offset); 176 } 177 178 int main(void) 179 { 180 const struct CMUnitTest tests[] = { 181 cmocka_unit_test_setup_teardown(test_memcpy_full_buffer_copy, setup_test, 182 teardown_test), 183 cmocka_unit_test_setup_teardown(test_memcpy_zero_size, setup_test, 184 teardown_test), 185 cmocka_unit_test_setup_teardown(test_memcpy_buffer_part, setup_test, 186 teardown_test), 187 cmocka_unit_test_setup_teardown(test_memcpy_buffer_part_unaligned, setup_test, 188 teardown_test), 189 cmocka_unit_test_setup_teardown(test_memcpy_copy_to_itself, setup_test, 190 teardown_test), 191 cmocka_unit_test_setup_teardown(test_memcpy_copy_part_of_itself_to_itself, 192 setup_test, teardown_test), 193 }; 194 195 return cb_run_group_tests(tests, NULL, NULL); 196 }