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