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_DATA("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 DEFINE_BITFIELD(name, bits) unsigned long(name)[DIV_ROUND_UP(bits, BITS_PER_LONG)]
80
sys_bitfield_find_first_clear(const unsigned long * bitmap,const unsigned int bits)81 static inline int sys_bitfield_find_first_clear(const unsigned long *bitmap,
82 const unsigned int bits)
83 {
84 const size_t words = DIV_ROUND_UP(bits, BITS_PER_LONG);
85 size_t cnt;
86 unsigned int long neg_bitmap;
87
88 /*
89 * By bitwise negating the bitmap, we are actually implementing
90 * ffc (find first clear) using ffs (find first set).
91 */
92 for (cnt = 0; cnt < words; cnt++) {
93 neg_bitmap = ~bitmap[cnt];
94 if (neg_bitmap == 0) {
95 /* All full. Try next word. */
96 continue;
97 } else if (neg_bitmap == ~0UL) {
98 /* First bit is free */
99 return cnt * BITS_PER_LONG;
100 } else {
101 const unsigned int bit =
102 (cnt * BITS_PER_LONG) + __builtin_ffsl(neg_bitmap) - 1;
103 /* Ensure first free bit is within total bits count */
104 if (bit < bits) {
105 return bit;
106 } else {
107 return -1;
108 }
109 }
110 }
111 return -1;
112 }
113
114 static DEFINE_BITFIELD(params_allocation, CONFIG_ZTEST_PARAMETER_COUNT);
115 static struct parameter params[CONFIG_ZTEST_PARAMETER_COUNT];
116
free_parameter(struct parameter * param)117 static void free_parameter(struct parameter *param)
118 {
119 unsigned int allocation_index = param - params;
120
121 if (param == NULL) {
122 return;
123 }
124 __ASSERT(allocation_index < CONFIG_ZTEST_PARAMETER_COUNT,
125 "param %p given to free is not in the static buffer %p:%u", param, params,
126 CONFIG_ZTEST_PARAMETER_COUNT);
127 sys_bitfield_clear_bit((mem_addr_t)params_allocation, allocation_index);
128 }
129
alloc_parameter(void)130 static struct parameter *alloc_parameter(void)
131 {
132 int allocation_index;
133 struct parameter *param;
134
135 allocation_index =
136 sys_bitfield_find_first_clear(params_allocation, CONFIG_ZTEST_PARAMETER_COUNT);
137 if (allocation_index == -1) {
138 printk("No more mock parameters available for allocation\n");
139 ztest_test_fail();
140 }
141 sys_bitfield_set_bit((mem_addr_t)params_allocation, allocation_index);
142 param = params + allocation_index;
143 (void)memset(param, 0, sizeof(*param));
144 return param;
145 }
146
z_init_mock(void)147 void z_init_mock(void)
148 {
149 }
150
151 #endif
152
find_and_delete_value(struct parameter * param,const char * fn,const char * name)153 static struct parameter *find_and_delete_value(struct parameter *param, const char *fn,
154 const char *name)
155 {
156 struct parameter *value;
157
158 if (!param->next) {
159 return NULL;
160 }
161
162 if (strcmp(param->next->name, name) || strcmp(param->next->fn, fn)) {
163 return find_and_delete_value(param->next, fn, name);
164 }
165
166 value = param->next;
167 param->next = param->next->next;
168 value->next = NULL;
169
170 return value;
171 }
172
insert_value(struct parameter * param,const char * fn,const char * name,uintptr_t val)173 static void insert_value(struct parameter *param, const char *fn, const char *name, uintptr_t val)
174 {
175 struct parameter *value;
176
177 value = alloc_parameter();
178 value->fn = fn;
179 value->name = name;
180 value->value = val;
181
182 /* Seek to end of linked list to ensure correct discovery order in find_and_delete_value */
183 while (param->next) {
184 param = param->next;
185 }
186
187 /* Append to end of linked list */
188 value->next = param->next;
189 param->next = value;
190 }
191
192 static struct parameter parameter_list = {NULL, "", "", 0};
193 static struct parameter return_value_list = {NULL, "", "", 0};
194
z_ztest_expect_value(const char * fn,const char * name,uintptr_t val)195 void z_ztest_expect_value(const char *fn, const char *name, uintptr_t val)
196 {
197 insert_value(¶meter_list, fn, name, val);
198 }
199
z_ztest_check_expected_value(const char * fn,const char * name,uintptr_t val)200 void z_ztest_check_expected_value(const char *fn, const char *name, uintptr_t val)
201 {
202 struct parameter *param;
203 uintptr_t expected;
204
205 param = find_and_delete_value(¶meter_list, fn, name);
206 if (!param) {
207 PRINT_DATA("Failed to find parameter %s for %s\n", name, fn);
208 ztest_test_fail();
209 }
210
211 expected = param->value;
212 free_parameter(param);
213
214 if (expected != val) {
215 /* We need to cast these values since the toolchain doesn't
216 * provide inttypes.h
217 */
218 PRINT_DATA("%s:%s received wrong value: Got %lu, expected %lu\n", fn, name,
219 (unsigned long)val, (unsigned long)expected);
220 ztest_test_fail();
221 }
222 }
223
z_ztest_expect_data(const char * fn,const char * name,void * val)224 void z_ztest_expect_data(const char *fn, const char *name, void *val)
225 {
226 insert_value(¶meter_list, fn, name, (uintptr_t)val);
227 }
228
z_ztest_check_expected_data(const char * fn,const char * name,void * data,uint32_t length)229 void z_ztest_check_expected_data(const char *fn, const char *name, void *data, uint32_t length)
230 {
231 struct parameter *param;
232 void *expected;
233
234 param = find_and_delete_value(¶meter_list, fn, name);
235 if (!param) {
236 PRINT_DATA("Failed to find parameter %s for %s\n", name, fn);
237 /* No return from this function but for coverity reasons
238 * put a return after to avoid the warning of a null
239 * dereference of param below.
240 */
241 ztest_test_fail();
242 return;
243 }
244
245 expected = (void *)param->value;
246 free_parameter(param);
247
248 if (expected == NULL && data != NULL) {
249 PRINT_DATA("%s:%s received data while expected null pointer\n", fn, name);
250 ztest_test_fail();
251 } else if (data == NULL && expected != NULL) {
252 PRINT_DATA("%s:%s received null pointer while expected data\n", fn, name);
253 ztest_test_fail();
254 } else if (data != NULL) {
255 if (memcmp(data, expected, length) != 0) {
256 PRINT_DATA("%s:%s data provided don't match\n", fn, name);
257 ztest_test_fail();
258 }
259 }
260 }
261
z_ztest_return_data(const char * fn,const char * name,void * val)262 void z_ztest_return_data(const char *fn, const char *name, void *val)
263 {
264 insert_value(¶meter_list, fn, name, (uintptr_t)val);
265 }
266
z_ztest_copy_return_data(const char * fn,const char * name,void * data,uint32_t length)267 void z_ztest_copy_return_data(const char *fn, const char *name, void *data, uint32_t length)
268 {
269 struct parameter *param;
270 void *return_data;
271
272 if (data == NULL) {
273 PRINT_DATA("%s:%s received null pointer\n", fn, name);
274 ztest_test_fail();
275 return;
276 }
277
278 param = find_and_delete_value(¶meter_list, fn, name);
279 if (!param) {
280 PRINT_DATA("Failed to find parameter %s for %s\n", name, fn);
281 memset(data, 0, length);
282 ztest_test_fail();
283 } else {
284 return_data = (void *)param->value;
285 free_parameter(param);
286 memcpy(data, return_data, length);
287 }
288 }
289
z_ztest_returns_value(const char * fn,uintptr_t value)290 void z_ztest_returns_value(const char *fn, uintptr_t value)
291 {
292 insert_value(&return_value_list, fn, "", value);
293 }
294
z_ztest_get_return_value(const char * fn)295 uintptr_t z_ztest_get_return_value(const char *fn)
296 {
297 uintptr_t value;
298 struct parameter *param = find_and_delete_value(&return_value_list, fn, "");
299
300 if (!param) {
301 PRINT_DATA("Failed to find return value for function %s\n", fn);
302 ztest_test_fail();
303 }
304
305 value = param->value;
306 free_parameter(param);
307
308 return value;
309 }
310
free_param_list(struct parameter * param)311 static void free_param_list(struct parameter *param)
312 {
313 struct parameter *next;
314
315 while (param) {
316 next = param->next;
317 free_parameter(param);
318 param = next;
319 }
320 }
321
z_cleanup_mock(void)322 int z_cleanup_mock(void)
323 {
324 int fail = 0;
325
326 if (parameter_list.next) {
327 PRINT_DATA("Parameter not used by mock: %s:%s\n", parameter_list.next->fn,
328 parameter_list.next->name);
329 fail = 1;
330 }
331 if (return_value_list.next) {
332 PRINT_DATA("Return value no used by mock: %s\n", return_value_list.next->fn);
333 fail = 2;
334 }
335
336 free_param_list(parameter_list.next);
337 free_param_list(return_value_list.next);
338
339 parameter_list.next = NULL;
340 return_value_list.next = NULL;
341
342 return fail;
343 }
344