1 /*
2  * Copyright (c) 2023 Legrand North America, LLC.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/code_under_test.h>
8 
9 
10 #include <zephyr/ztest.h>
11 #include <zephyr/fff.h>
12 #include <zephyr/fff_extensions.h>
13 
14 #include "fakes/called_API.h"
15 
16 
17 #define RESET_HISTORY_AND_FAKES() \
18 	ZEPHYR_CALLED_API_FFF_FAKES_LIST(RESET_FAKE) \
19 	FFF_RESET_HISTORY()
20 
21 DEFINE_FFF_GLOBALS;
22 
23 
24 /*
25  * Custom Fakes:
26  */
27 
28 struct called_API_open_custom_fake_context {
29 	/* Written to code under test by custom fake */
30 	const struct called_API_info * const instance_out;
31 
32 	int result;
33 };
34 
called_API_open_custom_fake(const struct called_API_info ** instance_out)35 int called_API_open_custom_fake(
36 	const struct called_API_info **instance_out)
37 {
38 	RETURN_HANDLED_CONTEXT(
39 		called_API_open,
40 		struct called_API_open_custom_fake_context,
41 		result,  /* return field name in _fake_context struct */
42 		context, /* Name of context ptr variable used below */
43 		{
44 			if (context != NULL) {
45 				if (context->result == 0) {
46 					if (instance_out != NULL) {
47 						*instance_out = context->instance_out;
48 					}
49 				}
50 
51 				return context->result;
52 			}
53 
54 			return called_API_open_fake.return_val;
55 		}
56 	);
57 }
58 
59 /*
60  * Tests
61  */
62 
ZTEST(fff_fake_contexts_tests,test_code_under_test)63 ZTEST(fff_fake_contexts_tests, test_code_under_test)
64 {
65 	struct test_case {
66 		const char *description_oneliner;
67 
68 		void **expected_call_history;
69 
70 		/* Last FFF sequence entry is reused for excess calls.
71 		 * Have an extra entry that returns a distinct failure (-E2BIG)
72 		 *
73 		 * Expect one less call than _len, or 0 if sequence ptr is NULL
74 		 *
75 		 * Configure to return -E2BIG if excess calls.
76 		 */
77 		int    called_API_open_custom_fake_contexts_len;
78 		struct called_API_open_custom_fake_context *
79 		       called_API_open_custom_fake_contexts;
80 
81 		int  called_API_close_fake_return_val_seq_len;
82 		int *called_API_close_fake_return_val_seq;
83 
84 		int result_expected;
85 	}
86 	const test_cases[] = {
87 		{
88 			.description_oneliner = "First called_API_open() returns -EINVAL",
89 			.expected_call_history = (void * [])
90 			{
91 				called_API_open,
92 				NULL, /* mark end of array */
93 			},
94 
95 			.called_API_open_custom_fake_contexts_len = 2,
96 			.called_API_open_custom_fake_contexts =
97 				(struct called_API_open_custom_fake_context [])
98 			{
99 				{
100 					.result = -EINVAL,
101 				},
102 				{
103 					.result = -E2BIG, /* for excessive calls */
104 				},
105 			},
106 
107 			.called_API_close_fake_return_val_seq = NULL,
108 
109 			.result_expected = -EINVAL,
110 		},
111 		{
112 			.description_oneliner = "First called_API_close() returns -EINVAL",
113 			.expected_call_history = (void * [])
114 			{
115 				called_API_open,
116 				called_API_close,
117 				NULL, /* mark end of array */
118 			},
119 
120 			.called_API_open_custom_fake_contexts_len = 2,
121 			.called_API_open_custom_fake_contexts =
122 				(struct called_API_open_custom_fake_context [])
123 			{
124 				{
125 					.result = 0,
126 				},
127 				{
128 					.result = -E2BIG, /* for excessive calls */
129 				},
130 			},
131 
132 			.called_API_close_fake_return_val_seq_len = 2,
133 			.called_API_close_fake_return_val_seq = (int [])
134 			{
135 				-EINVAL,
136 				-E2BIG, /* for excessive calls */
137 			},
138 
139 			.result_expected = -EINVAL,
140 		},
141 		{
142 			.description_oneliner = "Second called_API_open() returns -EINVAL",
143 			.expected_call_history = (void * [])
144 			{
145 				called_API_open,
146 				called_API_close,
147 				called_API_open,
148 				NULL, /* mark end of array */
149 			},
150 
151 			.called_API_open_custom_fake_contexts_len = 3,
152 			.called_API_open_custom_fake_contexts =
153 				(struct called_API_open_custom_fake_context [])
154 			{
155 				{
156 					.result = 0,
157 				},
158 				{
159 					.result = -EINVAL,
160 				},
161 				{
162 					.result = -E2BIG, /* for excessive calls */
163 				},
164 			},
165 
166 			.called_API_close_fake_return_val_seq_len = 2,
167 			.called_API_close_fake_return_val_seq = (int [])
168 			{
169 				0,
170 				-E2BIG, /* for excessive calls */
171 			},
172 
173 			.result_expected = -EINVAL,
174 		},
175 		{
176 			.description_oneliner = "Second called_API_close() returns -EINVAL",
177 			.expected_call_history = (void * [])
178 			{
179 				called_API_open,
180 				called_API_close,
181 				called_API_open,
182 				called_API_close,
183 				NULL, /* mark end of array */
184 			},
185 
186 			.called_API_open_custom_fake_contexts_len = 3,
187 			.called_API_open_custom_fake_contexts =
188 				(struct called_API_open_custom_fake_context [])
189 			{
190 				{
191 					.result = 0,
192 				},
193 				{
194 					.result = 0,
195 				},
196 				{
197 					.result = -E2BIG, /* for excessive calls */
198 				},
199 			},
200 
201 			.called_API_close_fake_return_val_seq_len = 3,
202 			.called_API_close_fake_return_val_seq = (int [])
203 			{
204 				0,
205 				-EINVAL,
206 				-E2BIG, /* for excessive calls */
207 			},
208 
209 			.result_expected = -EINVAL,
210 		},
211 		{
212 			.description_oneliner = "All calls return no error",
213 			.expected_call_history = (void * [])
214 			{
215 				called_API_open,
216 				called_API_close,
217 				called_API_open,
218 				called_API_close,
219 				NULL, /* mark end of array */
220 			},
221 
222 			.called_API_open_custom_fake_contexts_len = 3,
223 			.called_API_open_custom_fake_contexts =
224 				(struct called_API_open_custom_fake_context [])
225 			{
226 				{
227 					.result = 0,
228 				},
229 				{
230 					.result = 0,
231 				},
232 				{
233 					.result = -E2BIG, /* for excessive calls */
234 				},
235 			},
236 
237 			.called_API_close_fake_return_val_seq_len = 3,
238 			.called_API_close_fake_return_val_seq = (int [])
239 			{
240 				0,
241 				0,
242 				-E2BIG, /* for excessive calls */
243 			},
244 
245 			.result_expected = 0,
246 		},
247 
248 	};
249 
250 	for (int i = 0; i < ARRAY_SIZE(test_cases); ++i) {
251 		const struct test_case * const tc = &test_cases[i];
252 
253 
254 		printk("Checking test_cases[%i]: %s\n", i,
255 			(tc->description_oneliner != NULL) ? tc->description_oneliner : "");
256 
257 		/*
258 		 * Set up pre-conditions
259 		 */
260 		RESET_HISTORY_AND_FAKES();
261 
262 		/* NOTE: Point to the return type field in the first returns struct.
263 		 *       This custom_fake:
264 		 *	 - uses *_fake.return_val_seq and CONTAINER_OF()
265 		 *	     to determine the beginning of the array of structures.
266 		 *	 - uses *_fake.return_val_seq_id to index into
267 		 *	     the array of structures.
268 		 *       This overloading is to allow the return_val_seq to
269 		 *       also contain call-specific output parameters to be
270 		 *       applied by the custom_fake.
271 		 */
272 		called_API_open_fake.return_val = -E2BIG; /* for excessive calls */
273 		SET_RETURN_SEQ(called_API_open,
274 			&tc->called_API_open_custom_fake_contexts[0].result,
275 			tc->called_API_open_custom_fake_contexts_len);
276 		called_API_open_fake.custom_fake = called_API_open_custom_fake;
277 
278 		/* NOTE: This uses the standard _fake without contexts */
279 		called_API_close_fake.return_val = -E2BIG; /* for excessive calls */
280 		SET_RETURN_SEQ(called_API_close,
281 			tc->called_API_close_fake_return_val_seq,
282 			tc->called_API_close_fake_return_val_seq_len);
283 
284 
285 		/*
286 		 * Call code_under_test
287 		 */
288 		int result = code_under_test();
289 
290 
291 		/*
292 		 * Verify expected behavior of code_under_test:
293 		 *   - call history, args per call
294 		 *   - results
295 		 *   - outputs
296 		 */
297 		if (tc->expected_call_history != NULL) {
298 			for (int j = 0; j < fff.call_history_idx; ++j) {
299 				zassert_equal(fff.call_history[j],
300 						tc->expected_call_history[j], NULL);
301 			}
302 			zassert_is_null(tc->expected_call_history[
303 						fff.call_history_idx], NULL);
304 		} else {
305 			zassert_equal(fff.call_history_idx, 0, NULL);
306 		}
307 
308 
309 		const int called_API_open_fake_call_count_expected =
310 			(tc->called_API_open_custom_fake_contexts == NULL) ? 0 :
311 			 tc->called_API_open_custom_fake_contexts_len - 1;
312 
313 		zassert_equal(called_API_open_fake.call_count,
314 			      called_API_open_fake_call_count_expected, NULL);
315 		for (int j = 0; j < called_API_open_fake_call_count_expected; ++j) {
316 			zassert_not_null(called_API_open_fake.arg0_history[j], NULL);
317 		}
318 
319 
320 		const int called_API_close_fake_call_count_expected =
321 			(tc->called_API_close_fake_return_val_seq == NULL) ? 0 :
322 			 tc->called_API_close_fake_return_val_seq_len - 1;
323 
324 		zassert_equal(called_API_close_fake.call_count,
325 			called_API_close_fake_call_count_expected, NULL);
326 		for (int j = 0; j < called_API_close_fake_call_count_expected; ++j) {
327 			/* Verify code_under_test returns value provided by open. */
328 			zassert_equal(called_API_close_fake.arg0_history[j],
329 				tc->called_API_open_custom_fake_contexts[j]
330 					.instance_out, NULL);
331 		}
332 
333 
334 		zassert_equal(result, tc->result_expected, NULL);
335 	}
336 }
337 
338 ZTEST_SUITE(fff_fake_contexts_tests, NULL, NULL, NULL, NULL, NULL);
339