lib: Add memdup()
[platform/kernel/u-boot.git] / test / lib / string.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
4  *
5  * Unit tests for memory functions
6  *
7  * The architecture dependent implementations run through different lines of
8  * code depending on the alignment and length of memory regions copied or set.
9  * This has to be considered in testing.
10  */
11
12 #include <common.h>
13 #include <command.h>
14 #include <log.h>
15 #include <test/lib.h>
16 #include <test/test.h>
17 #include <test/ut.h>
18
19 /* Xor mask used for marking memory regions */
20 #define MASK 0xA5
21 /* Number of different alignment values */
22 #define SWEEP 16
23 /* Allow for copying up to 32 bytes */
24 #define BUFLEN (SWEEP + 33)
25
26 #define TEST_STR        "hello"
27
28 /**
29  * init_buffer() - initialize buffer
30  *
31  * The buffer is filled with incrementing values xor'ed with the mask.
32  *
33  * @buf:        buffer
34  * @mask:       xor mask
35  */
36 static void init_buffer(u8 buf[], u8 mask)
37 {
38         int i;
39
40         for (i = 0; i < BUFLEN; ++i)
41                 buf[i] = i ^ mask;
42 }
43
44 /**
45  * test_memset() - test result of memset()
46  *
47  * @uts:        unit test state
48  * @buf:        buffer
49  * @mask:       value set by memset()
50  * @offset:     relative start of region changed by memset() in buffer
51  * @len:        length of region changed by memset()
52  * Return:      0 = success, 1 = failure
53  */
54 static int test_memset(struct unit_test_state *uts, u8 buf[], u8 mask,
55                        int offset, int len)
56 {
57         int i;
58
59         for (i = 0; i < BUFLEN; ++i) {
60                 if (i < offset || i >= offset + len) {
61                         ut_asserteq(i, buf[i]);
62                 } else {
63                         ut_asserteq(mask, buf[i]);
64                 }
65         }
66         return 0;
67 }
68
69 /**
70  * lib_memset() - unit test for memset()
71  *
72  * Test memset() with varied alignment and length of the changed buffer.
73  *
74  * @uts:        unit test state
75  * Return:      0 = success, 1 = failure
76  */
77 static int lib_memset(struct unit_test_state *uts)
78 {
79         u8 buf[BUFLEN];
80         int offset, len;
81         void *ptr;
82
83         for (offset = 0; offset <= SWEEP; ++offset) {
84                 for (len = 1; len < BUFLEN - SWEEP; ++len) {
85                         init_buffer(buf, 0);
86                         ptr = memset(buf + offset, MASK, len);
87                         ut_asserteq_ptr(buf + offset, (u8 *)ptr);
88                         if (test_memset(uts, buf, MASK, offset, len)) {
89                                 debug("%s: failure %d, %d\n",
90                                       __func__, offset, len);
91                                 return CMD_RET_FAILURE;
92                         }
93                 }
94         }
95         return 0;
96 }
97
98 LIB_TEST(lib_memset, 0);
99
100 /**
101  * test_memmove() - test result of memcpy() or memmove()
102  *
103  * @uts:        unit test state
104  * @buf:        buffer
105  * @mask:       xor mask used to initialize source buffer
106  * @offset1:    relative start of copied region in source buffer
107  * @offset2:    relative start of copied region in destination buffer
108  * @len:        length of region changed by memset()
109  * Return:      0 = success, 1 = failure
110  */
111 static int test_memmove(struct unit_test_state *uts, u8 buf[], u8 mask,
112                         int offset1, int offset2, int len)
113 {
114         int i;
115
116         for (i = 0; i < BUFLEN; ++i) {
117                 if (i < offset2 || i >= offset2 + len) {
118                         ut_asserteq(i, buf[i]);
119                 } else {
120                         ut_asserteq((i + offset1 - offset2) ^ mask, buf[i]);
121                 }
122         }
123         return 0;
124 }
125
126 /**
127  * lib_memcpy() - unit test for memcpy()
128  *
129  * Test memcpy() with varied alignment and length of the copied buffer.
130  *
131  * @uts:        unit test state
132  * Return:      0 = success, 1 = failure
133  */
134 static int lib_memcpy(struct unit_test_state *uts)
135 {
136         u8 buf1[BUFLEN];
137         u8 buf2[BUFLEN];
138         int offset1, offset2, len;
139         void *ptr;
140
141         init_buffer(buf1, MASK);
142
143         for (offset1 = 0; offset1 <= SWEEP; ++offset1) {
144                 for (offset2 = 0; offset2 <= SWEEP; ++offset2) {
145                         for (len = 1; len < BUFLEN - SWEEP; ++len) {
146                                 init_buffer(buf2, 0);
147                                 ptr = memcpy(buf2 + offset2, buf1 + offset1,
148                                              len);
149                                 ut_asserteq_ptr(buf2 + offset2, (u8 *)ptr);
150                                 if (test_memmove(uts, buf2, MASK, offset1,
151                                                  offset2, len)) {
152                                         debug("%s: failure %d, %d, %d\n",
153                                               __func__, offset1, offset2, len);
154                                         return CMD_RET_FAILURE;
155                                 }
156                         }
157                 }
158         }
159         return 0;
160 }
161
162 LIB_TEST(lib_memcpy, 0);
163
164 /**
165  * lib_memmove() - unit test for memmove()
166  *
167  * Test memmove() with varied alignment and length of the copied buffer.
168  *
169  * @uts:        unit test state
170  * Return:      0 = success, 1 = failure
171  */
172 static int lib_memmove(struct unit_test_state *uts)
173 {
174         u8 buf[BUFLEN];
175         int offset1, offset2, len;
176         void *ptr;
177
178         for (offset1 = 0; offset1 <= SWEEP; ++offset1) {
179                 for (offset2 = 0; offset2 <= SWEEP; ++offset2) {
180                         for (len = 1; len < BUFLEN - SWEEP; ++len) {
181                                 init_buffer(buf, 0);
182                                 ptr = memmove(buf + offset2, buf + offset1,
183                                               len);
184                                 ut_asserteq_ptr(buf + offset2, (u8 *)ptr);
185                                 if (test_memmove(uts, buf, 0, offset1, offset2,
186                                                  len)) {
187                                         debug("%s: failure %d, %d, %d\n",
188                                               __func__, offset1, offset2, len);
189                                         return CMD_RET_FAILURE;
190                                 }
191                         }
192                 }
193         }
194         return 0;
195 }
196
197 LIB_TEST(lib_memmove, 0);
198
199 /** lib_memdup() - unit test for memdup() */
200 static int lib_memdup(struct unit_test_state *uts)
201 {
202         char buf[BUFLEN];
203         size_t len;
204         char *p, *q;
205
206         /* Zero size should do nothing */
207         p = memdup(NULL, 0);
208         ut_assertnonnull(p);
209         free(p);
210
211         p = memdup(buf, 0);
212         ut_assertnonnull(p);
213         free(p);
214
215         strcpy(buf, TEST_STR);
216         len = sizeof(TEST_STR);
217         p = memdup(buf, len);
218         ut_asserteq_mem(p, buf, len);
219
220         q = memdup(p, len);
221         ut_asserteq_mem(q, buf, len);
222         free(q);
223         free(p);
224
225         return 0;
226 }
227 LIB_TEST(lib_memdup, 0);