1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/types.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/sys/util.h>
10 #include <string.h>
11 #include <stdio.h>
12
13 struct parameter {
14 struct parameter *next;
15 const char *fn;
16 const char *name;
17 uintptr_t value;
18 };
19
20 #ifndef KERNEL
21
22 #include <stdlib.h>
23 #include <stdarg.h>
24
free_parameter(struct parameter * param)25 static void free_parameter(struct parameter *param)
26 {
27 free(param);
28 }
29
alloc_parameter(void)30 static struct parameter *alloc_parameter(void)
31 {
32 struct parameter *param;
33
34 param = calloc(1, sizeof(struct parameter));
35 if (!param) {
36 PRINT("Failed to allocate mock parameter\n");
37 ztest_test_fail();
38 }
39
40 return param;
41 }
42
z_init_mock(void)43 void z_init_mock(void)
44 {
45 }
46
printk(const char * fmt,...)47 void printk(const char *fmt, ...)
48 {
49 va_list ap;
50
51 va_start(ap, fmt);
52 vprintf(fmt, ap);
53 va_end(ap);
54 }
55
vprintk(const char * fmt,va_list ap)56 void vprintk(const char *fmt, va_list ap)
57 {
58 vprintf(fmt, ap);
59 }
60
snprintk(char * str,size_t size,const char * fmt,...)61 int snprintk(char *str, size_t size, const char *fmt, ...)
62 {
63 va_list ap;
64 int ret;
65
66 va_start(ap, fmt);
67 ret = snprintf(str, size, fmt, ap);
68 va_end(ap);
69
70 return ret;
71 }
72
73 #else
74
75 /*
76 * FIXME: move to sys_io.h once the argument signature for bitmap has
77 * been fixed to void* or similar GH-2825
78 */
79 #define BITS_PER_UL (8 * sizeof(unsigned long int))
80 #define DEFINE_BITFIELD(name, bits) \
81 unsigned long(name)[DIV_ROUND_UP(bits, BITS_PER_UL)]
82
sys_bitfield_find_first_clear(const unsigned long * bitmap,const unsigned int bits)83 static inline int sys_bitfield_find_first_clear(const unsigned long *bitmap,
84 const unsigned int bits)
85 {
86 const size_t words = DIV_ROUND_UP(bits, BITS_PER_UL);
87 size_t cnt;
88 unsigned int long neg_bitmap;
89
90 /*
91 * By bitwise negating the bitmap, we are actually implementing
92 * ffc (find first clear) using ffs (find first set).
93 */
94 for (cnt = 0; cnt < words; cnt++) {
95 neg_bitmap = ~bitmap[cnt];
96 if (neg_bitmap == 0) {
97 /* All full. Try next word. */
98 continue;
99 } else if (neg_bitmap == ~0UL) {
100 /* First bit is free */
101 return cnt * BITS_PER_UL;
102 } else {
103 const unsigned int bit = (cnt * BITS_PER_UL) +
104 __builtin_ffsl(neg_bitmap) - 1;
105 /* Ensure first free bit is within total bits count */
106 if (bit < bits) {
107 return bit;
108 } else {
109 return -1;
110 }
111 }
112 }
113 return -1;
114 }
115
116 static DEFINE_BITFIELD(params_allocation, CONFIG_ZTEST_PARAMETER_COUNT);
117 static struct parameter params[CONFIG_ZTEST_PARAMETER_COUNT];
118
free_parameter(struct parameter * param)119 static void free_parameter(struct parameter *param)
120 {
121 unsigned int allocation_index = param - params;
122
123 if (param == NULL) {
124 return;
125 }
126 __ASSERT(allocation_index < CONFIG_ZTEST_PARAMETER_COUNT,
127 "param %p given to free is not in the static buffer %p:%u",
128 param, params, CONFIG_ZTEST_PARAMETER_COUNT);
129 sys_bitfield_clear_bit((mem_addr_t)params_allocation, allocation_index);
130 }
131
alloc_parameter(void)132 static struct parameter *alloc_parameter(void)
133 {
134 int allocation_index;
135 struct parameter *param;
136
137 allocation_index = sys_bitfield_find_first_clear(
138 params_allocation, CONFIG_ZTEST_PARAMETER_COUNT);
139 if (allocation_index == -1) {
140 printk("No more mock parameters available for allocation\n");
141 ztest_test_fail();
142 }
143 sys_bitfield_set_bit((mem_addr_t)params_allocation, allocation_index);
144 param = params + allocation_index;
145 (void)memset(param, 0, sizeof(*param));
146 return param;
147 }
148
z_init_mock(void)149 void z_init_mock(void)
150 {
151 }
152
153 #endif
154
find_and_delete_value(struct parameter * param,const char * fn,const char * name)155 static struct parameter *find_and_delete_value(struct parameter *param,
156 const char *fn, const char *name)
157 {
158 struct parameter *value;
159
160 if (!param->next) {
161 return NULL;
162 }
163
164 if (strcmp(param->next->name, name) || strcmp(param->next->fn, fn)) {
165 return find_and_delete_value(param->next, fn, name);
166 }
167
168 value = param->next;
169 param->next = param->next->next;
170 value->next = NULL;
171
172 return value;
173 }
174
insert_value(struct parameter * param,const char * fn,const char * name,uintptr_t val)175 static void insert_value(struct parameter *param, const char *fn,
176 const char *name, uintptr_t val)
177 {
178 struct parameter *value;
179
180 value = alloc_parameter();
181 value->fn = fn;
182 value->name = name;
183 value->value = val;
184
185 /* Seek to end of linked list to ensure correct discovery order in find_and_delete_value */
186 while (param->next) {
187 param = param->next;
188 }
189
190 /* Append to end of linked list */
191 value->next = param->next;
192 param->next = value;
193 }
194
195 static struct parameter parameter_list = { NULL, "", "", 0 };
196 static struct parameter return_value_list = { NULL, "", "", 0 };
197
z_ztest_expect_value(const char * fn,const char * name,uintptr_t val)198 void z_ztest_expect_value(const char *fn, const char *name, uintptr_t val)
199 {
200 insert_value(¶meter_list, fn, name, val);
201 }
202
z_ztest_check_expected_value(const char * fn,const char * name,uintptr_t val)203 void z_ztest_check_expected_value(const char *fn, const char *name,
204 uintptr_t val)
205 {
206 struct parameter *param;
207 uintptr_t expected;
208
209 param = find_and_delete_value(¶meter_list, fn, name);
210 if (!param) {
211 PRINT("Failed to find parameter %s for %s\n", name, fn);
212 ztest_test_fail();
213 }
214
215 expected = param->value;
216 free_parameter(param);
217
218 if (expected != val) {
219 /* We need to cast these values since the toolchain doesn't
220 * provide inttypes.h
221 */
222 PRINT("%s:%s received wrong value: Got %lu, expected %lu\n", fn,
223 name, (unsigned long)val, (unsigned long)expected);
224 ztest_test_fail();
225 }
226 }
227
z_ztest_expect_data(const char * fn,const char * name,void * val)228 void z_ztest_expect_data(const char *fn, const char *name, void *val)
229 {
230 insert_value(¶meter_list, fn, name, (uintptr_t)val);
231 }
232
z_ztest_check_expected_data(const char * fn,const char * name,void * data,uint32_t length)233 void z_ztest_check_expected_data(const char *fn, const char *name, void *data,
234 uint32_t length)
235 {
236 struct parameter *param;
237 void *expected;
238
239 param = find_and_delete_value(¶meter_list, fn, name);
240 if (!param) {
241 PRINT("Failed to find parameter %s for %s\n", name, fn);
242 /* No return from this function but for coverity reasons
243 * put a return after to avoid the warning of a null
244 * dereference of param below.
245 */
246 ztest_test_fail();
247 return;
248 }
249
250 expected = (void *)param->value;
251 free_parameter(param);
252
253 if (expected == NULL && data != NULL) {
254 PRINT("%s:%s received data while expected null pointer\n", fn, name);
255 ztest_test_fail();
256 } else if (data == NULL && expected != NULL) {
257 PRINT("%s:%s received null pointer while expected data\n", fn,
258 name);
259 ztest_test_fail();
260 } else if (data != NULL) {
261 if (memcmp(data, expected, length) != 0) {
262 PRINT("%s:%s data provided don't match\n", fn, name);
263 ztest_test_fail();
264 }
265 }
266 }
267
z_ztest_return_data(const char * fn,const char * name,void * val)268 void z_ztest_return_data(const char *fn, const char *name, void *val)
269 {
270 insert_value(¶meter_list, fn, name, (uintptr_t)val);
271 }
272
z_ztest_copy_return_data(const char * fn,const char * name,void * data,uint32_t length)273 void z_ztest_copy_return_data(const char *fn, const char *name, void *data,
274 uint32_t length)
275 {
276 struct parameter *param;
277 void *return_data;
278
279 if (data == NULL) {
280 PRINT("%s:%s received null pointer\n", fn, name);
281 ztest_test_fail();
282 return;
283 }
284
285 param = find_and_delete_value(¶meter_list, fn, name);
286 if (!param) {
287 PRINT("Failed to find parameter %s for %s\n", name, fn);
288 memset(data, 0, length);
289 ztest_test_fail();
290 } else {
291 return_data = (void *)param->value;
292 free_parameter(param);
293 memcpy(data, return_data, length);
294 }
295 }
296
z_ztest_returns_value(const char * fn,uintptr_t value)297 void z_ztest_returns_value(const char *fn, uintptr_t value)
298 {
299 insert_value(&return_value_list, fn, "", value);
300 }
301
z_ztest_get_return_value(const char * fn)302 uintptr_t z_ztest_get_return_value(const char *fn)
303 {
304 uintptr_t value;
305 struct parameter *param =
306 find_and_delete_value(&return_value_list, fn, "");
307
308 if (!param) {
309 PRINT("Failed to find return value for function %s\n", fn);
310 ztest_test_fail();
311 }
312
313 value = param->value;
314 free_parameter(param);
315
316 return value;
317 }
318
free_param_list(struct parameter * param)319 static void free_param_list(struct parameter *param)
320 {
321 struct parameter *next;
322
323 while (param) {
324 next = param->next;
325 free_parameter(param);
326 param = next;
327 }
328 }
329
z_cleanup_mock(void)330 int z_cleanup_mock(void)
331 {
332 int fail = 0;
333
334 if (parameter_list.next) {
335 PRINT("Parameter not used by mock: %s:%s\n",
336 parameter_list.next->fn,
337 parameter_list.next->name);
338 fail = 1;
339 }
340 if (return_value_list.next) {
341 PRINT("Return value no used by mock: %s\n",
342 return_value_list.next->fn);
343 fail = 2;
344 }
345
346 free_param_list(parameter_list.next);
347 free_param_list(return_value_list.next);
348
349 parameter_list.next = NULL;
350 return_value_list.next = NULL;
351
352 return fail;
353 }
354