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