/ tests / lib / memcpy-test.c
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  }