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(&parameter_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(&parameter_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(&parameter_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(&parameter_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(&parameter_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(&parameter_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