1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/comparator.h>
8 #include <zephyr/drivers/comparator/fake_comp.h>
9 #include <zephyr/fff.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/shell/shell.h>
12 #include <zephyr/shell/shell_dummy.h>
13 #include <zephyr/ztest.h>
14
15 DEFINE_FFF_GLOBALS;
16
17 #define FAKE_COMP_NODE DT_NODELABEL(fake_comp)
18 #define FAKE_COMP_NAME DEVICE_DT_NAME(FAKE_COMP_NODE)
19
20 #define TEST_TRIGGER_DELAY K_SECONDS(1)
21
22 #define TEST_AWAIT_TRIGGER_TIMEOUT_BELOW_MIN_CMD \
23 ("comp await_trigger " FAKE_COMP_NAME " 0")
24
25 #define TEST_AWAIT_TRIGGER_TIMEOUT_ABOVE_MAX_CMD \
26 ("comp await_trigger " FAKE_COMP_NAME " " \
27 STRINGIFY(CONFIG_COMPARATOR_SHELL_AWAIT_TRIGGER_MAX_TIMEOUT + 1))
28
29 #define TEST_AWAIT_TRIGGER_TIMEOUT_BROKEN_CMD \
30 ("comp await_trigger " FAKE_COMP_NAME " d")
31
32 static const struct shell *test_sh;
33 static const struct device *test_dev = DEVICE_DT_GET(FAKE_COMP_NODE);
34 static comparator_callback_t test_callback;
35 static void *test_callback_user_data;
36 static struct k_spinlock test_callback_spinlock;
37 static struct k_work_delayable test_trigger_dwork;
38
test_get_output_stub_1(const struct device * dev)39 static int test_get_output_stub_1(const struct device *dev)
40 {
41 ARG_UNUSED(dev);
42
43 return 1;
44 }
45
test_get_output_stub_0(const struct device * dev)46 static int test_get_output_stub_0(const struct device *dev)
47 {
48 ARG_UNUSED(dev);
49
50 return 0;
51 }
52
test_get_output_stub_eio(const struct device * dev)53 static int test_get_output_stub_eio(const struct device *dev)
54 {
55 ARG_UNUSED(dev);
56
57 return -EIO;
58 }
59
test_set_trigger_stub_ok(const struct device * dev,enum comparator_trigger trigger)60 static int test_set_trigger_stub_ok(const struct device *dev, enum comparator_trigger trigger)
61 {
62 ARG_UNUSED(dev);
63 ARG_UNUSED(trigger);
64
65 return 0;
66 }
67
test_set_trigger_stub_eio(const struct device * dev,enum comparator_trigger trigger)68 static int test_set_trigger_stub_eio(const struct device *dev, enum comparator_trigger trigger)
69 {
70 ARG_UNUSED(dev);
71 ARG_UNUSED(trigger);
72
73 return -EIO;
74 }
75
test_set_trigger_callback_mock_0(const struct device * dev,comparator_callback_t callback,void * user_data)76 static int test_set_trigger_callback_mock_0(const struct device *dev,
77 comparator_callback_t callback,
78 void *user_data)
79 {
80 ARG_UNUSED(dev);
81
82 K_SPINLOCK(&test_callback_spinlock) {
83 test_callback = callback;
84 test_callback_user_data = user_data;
85 }
86
87 return 0;
88 }
89
test_set_trigger_callback_stub_0(const struct device * dev,comparator_callback_t callback,void * user_data)90 static int test_set_trigger_callback_stub_0(const struct device *dev,
91 comparator_callback_t callback,
92 void *user_data)
93 {
94 ARG_UNUSED(dev);
95 ARG_UNUSED(callback);
96 ARG_UNUSED(user_data);
97
98 return 0;
99 }
100
test_set_trigger_callback_stub_eio(const struct device * dev,comparator_callback_t callback,void * user_data)101 static int test_set_trigger_callback_stub_eio(const struct device *dev,
102 comparator_callback_t callback,
103 void *user_data)
104 {
105 ARG_UNUSED(dev);
106 ARG_UNUSED(callback);
107 ARG_UNUSED(user_data);
108
109 return -EIO;
110 }
111
test_trigger_is_pending_stub_1(const struct device * dev)112 static int test_trigger_is_pending_stub_1(const struct device *dev)
113 {
114 ARG_UNUSED(dev);
115
116 return 1;
117 }
118
test_trigger_is_pending_stub_0(const struct device * dev)119 static int test_trigger_is_pending_stub_0(const struct device *dev)
120 {
121 ARG_UNUSED(dev);
122
123 return 0;
124 }
125
test_trigger_is_pending_stub_eio(const struct device * dev)126 static int test_trigger_is_pending_stub_eio(const struct device *dev)
127 {
128 ARG_UNUSED(dev);
129
130 return -EIO;
131 }
132
133
test_trigger_handler(struct k_work * work)134 static void test_trigger_handler(struct k_work *work)
135 {
136 ARG_UNUSED(work);
137
138 test_callback(test_dev, test_callback_user_data);
139 }
140
test_schedule_trigger(void)141 static void test_schedule_trigger(void)
142 {
143 k_work_schedule(&test_trigger_dwork, TEST_TRIGGER_DELAY);
144 }
145
test_cancel_trigger(void)146 static void test_cancel_trigger(void)
147 {
148 struct k_work_sync sync;
149
150 k_work_cancel_delayable_sync(&test_trigger_dwork, &sync);
151 }
152
test_setup(void)153 static void *test_setup(void)
154 {
155 k_work_init_delayable(&test_trigger_dwork, test_trigger_handler);
156 test_sh = shell_backend_dummy_get_ptr();
157 WAIT_FOR(shell_ready(test_sh), 20000, k_msleep(1));
158 zassert_true(shell_ready(test_sh), "timed out waiting for dummy shell backend");
159 return NULL;
160 }
161
test_after(void * f)162 static void test_after(void *f)
163 {
164 ARG_UNUSED(f);
165
166 test_cancel_trigger();
167 }
168
ZTEST(comparator_shell,test_get_output)169 ZTEST(comparator_shell, test_get_output)
170 {
171 int ret;
172 const char *out;
173 size_t out_size;
174
175 shell_backend_dummy_clear_output(test_sh);
176 comp_fake_comp_get_output_fake.custom_fake = test_get_output_stub_1;
177 ret = shell_execute_cmd(test_sh, "comp get_output " FAKE_COMP_NAME);
178 zassert_ok(ret);
179 zassert_equal(comp_fake_comp_get_output_fake.call_count, 1);
180 zassert_equal(comp_fake_comp_get_output_fake.arg0_val, test_dev);
181 out = shell_backend_dummy_get_output(test_sh, &out_size);
182 zassert_str_equal(out, "\r\n1\r\n");
183
184 comp_fake_comp_get_output_fake.custom_fake = test_get_output_stub_0;
185 ret = shell_execute_cmd(test_sh, "comp get_output " FAKE_COMP_NAME);
186 zassert_ok(ret);
187 zassert_equal(comp_fake_comp_get_output_fake.call_count, 2);
188 zassert_equal(comp_fake_comp_get_output_fake.arg0_val, test_dev);
189 out = shell_backend_dummy_get_output(test_sh, &out_size);
190 zassert_str_equal(out, "\r\n0\r\n");
191
192 comp_fake_comp_get_output_fake.custom_fake = test_get_output_stub_eio;
193 ret = shell_execute_cmd(test_sh, "comp get_output " FAKE_COMP_NAME);
194 zassert_equal(ret, -EIO);
195 zassert_equal(comp_fake_comp_get_output_fake.call_count, 3);
196 zassert_equal(comp_fake_comp_get_output_fake.arg0_val, test_dev);
197 out = shell_backend_dummy_get_output(test_sh, &out_size);
198 zassert_str_equal(out, "\r\nfailed to get output\r\n");
199 }
200
ZTEST(comparator_shell,test_set_trigger)201 ZTEST(comparator_shell, test_set_trigger)
202 {
203 int ret;
204 const char *out;
205 size_t out_size;
206
207 comp_fake_comp_set_trigger_fake.custom_fake = test_set_trigger_stub_ok;
208
209 ret = shell_execute_cmd(test_sh, "comp set_trigger " FAKE_COMP_NAME " NONE");
210 zassert_ok(ret);
211 zassert_equal(comp_fake_comp_set_trigger_fake.call_count, 1);
212 zassert_equal(comp_fake_comp_set_trigger_fake.arg0_val, test_dev);
213 zassert_equal(comp_fake_comp_set_trigger_fake.arg1_val, COMPARATOR_TRIGGER_NONE);
214
215 ret = shell_execute_cmd(test_sh, "comp set_trigger " FAKE_COMP_NAME " RISING_EDGE");
216 zassert_ok(ret);
217 zassert_equal(comp_fake_comp_set_trigger_fake.call_count, 2);
218 zassert_equal(comp_fake_comp_set_trigger_fake.arg0_val, test_dev);
219 zassert_equal(comp_fake_comp_set_trigger_fake.arg1_val, COMPARATOR_TRIGGER_RISING_EDGE);
220
221 ret = shell_execute_cmd(test_sh, "comp set_trigger " FAKE_COMP_NAME " FALLING_EDGE");
222 zassert_ok(ret);
223 zassert_equal(comp_fake_comp_set_trigger_fake.call_count, 3);
224 zassert_equal(comp_fake_comp_set_trigger_fake.arg0_val, test_dev);
225 zassert_equal(comp_fake_comp_set_trigger_fake.arg1_val, COMPARATOR_TRIGGER_FALLING_EDGE);
226
227 ret = shell_execute_cmd(test_sh, "comp set_trigger " FAKE_COMP_NAME " BOTH_EDGES");
228 zassert_ok(ret);
229 zassert_equal(comp_fake_comp_set_trigger_fake.call_count, 4);
230 zassert_equal(comp_fake_comp_set_trigger_fake.arg0_val, test_dev);
231 zassert_equal(comp_fake_comp_set_trigger_fake.arg1_val, COMPARATOR_TRIGGER_BOTH_EDGES);
232
233 ret = shell_execute_cmd(test_sh, "comp set_trigger " FAKE_COMP_NAME " INVALID");
234 zassert_equal(ret, -EINVAL);
235 zassert_equal(comp_fake_comp_set_trigger_fake.call_count, 4);
236
237 comp_fake_comp_set_trigger_fake.custom_fake = test_set_trigger_stub_eio;
238
239 shell_backend_dummy_clear_output(test_sh);
240 ret = shell_execute_cmd(test_sh, "comp set_trigger " FAKE_COMP_NAME " BOTH_EDGES");
241 zassert_equal(ret, -EIO);
242 zassert_equal(comp_fake_comp_set_trigger_fake.call_count, 5);
243 zassert_equal(comp_fake_comp_set_trigger_fake.arg0_val, test_dev);
244 zassert_equal(comp_fake_comp_set_trigger_fake.arg1_val, COMPARATOR_TRIGGER_BOTH_EDGES);
245 out = shell_backend_dummy_get_output(test_sh, &out_size);
246 zassert_str_equal(out, "\r\nfailed to set trigger\r\n");
247 }
248
ZTEST(comparator_shell,test_await_trigger_set_callback_fail)249 ZTEST(comparator_shell, test_await_trigger_set_callback_fail)
250 {
251 int ret;
252 const char *out;
253 size_t out_size;
254
255 shell_backend_dummy_clear_output(test_sh);
256 comp_fake_comp_set_trigger_callback_fake.custom_fake = test_set_trigger_callback_stub_eio;
257 ret = shell_execute_cmd(test_sh, "comp await_trigger " FAKE_COMP_NAME);
258 zassert_ok(0);
259 zassert_equal(comp_fake_comp_set_trigger_callback_fake.call_count, 1);
260 zassert_equal(comp_fake_comp_set_trigger_callback_fake.return_val, 0);
261 out = shell_backend_dummy_get_output(test_sh, &out_size);
262 zassert_str_equal(out, "\r\nfailed to set trigger callback\r\n");
263 }
264
ZTEST(comparator_shell,test_await_trigger_timeout)265 ZTEST(comparator_shell, test_await_trigger_timeout)
266 {
267 int ret;
268 const char *out;
269 size_t out_size;
270
271 shell_backend_dummy_clear_output(test_sh);
272 comp_fake_comp_set_trigger_callback_fake.custom_fake = test_set_trigger_callback_stub_0;
273 ret = shell_execute_cmd(test_sh, "comp await_trigger " FAKE_COMP_NAME);
274 zassert_ok(0);
275 zassert_equal(comp_fake_comp_set_trigger_callback_fake.call_count, 2);
276 zassert_equal(comp_fake_comp_set_trigger_callback_fake.return_val_history[0], 0);
277 zassert_equal(comp_fake_comp_set_trigger_callback_fake.return_val_history[1], 0);
278 out = shell_backend_dummy_get_output(test_sh, &out_size);
279 zassert_str_equal(out, "\r\ntimed out\r\n");
280 }
281
ZTEST(comparator_shell,test_await_trigger_invalid_timeout_arg)282 ZTEST(comparator_shell, test_await_trigger_invalid_timeout_arg)
283 {
284 int ret;
285
286 ret = shell_execute_cmd(test_sh, TEST_AWAIT_TRIGGER_TIMEOUT_BELOW_MIN_CMD);
287 zassert_not_ok(ret);
288 zassert_equal(comp_fake_comp_set_trigger_callback_fake.call_count, 0);
289
290 ret = shell_execute_cmd(test_sh, TEST_AWAIT_TRIGGER_TIMEOUT_ABOVE_MAX_CMD);
291 zassert_not_ok(ret);
292 zassert_equal(comp_fake_comp_set_trigger_callback_fake.call_count, 0);
293
294 ret = shell_execute_cmd(test_sh, TEST_AWAIT_TRIGGER_TIMEOUT_BROKEN_CMD);
295 zassert_not_ok(ret);
296 zassert_equal(comp_fake_comp_set_trigger_callback_fake.call_count, 0);
297 }
298
ZTEST(comparator_shell,test_await_trigger)299 ZTEST(comparator_shell, test_await_trigger)
300 {
301 int ret;
302 const char *out;
303 size_t out_size;
304 comparator_api_set_trigger_callback seq[2];
305
306 shell_backend_dummy_clear_output(test_sh);
307 seq[0] = test_set_trigger_callback_mock_0;
308 seq[1] = test_set_trigger_callback_stub_0;
309 comp_fake_comp_set_trigger_callback_fake.custom_fake_seq = seq;
310 comp_fake_comp_set_trigger_callback_fake.custom_fake_seq_len = ARRAY_SIZE(seq);
311 test_schedule_trigger();
312 ret = shell_execute_cmd(test_sh, "comp await_trigger " FAKE_COMP_NAME);
313 zassert_ok(0);
314 zassert_equal(comp_fake_comp_set_trigger_callback_fake.call_count, 2);
315 zassert_equal(comp_fake_comp_set_trigger_callback_fake.arg0_history[0], test_dev);
316 zassert_not_equal(comp_fake_comp_set_trigger_callback_fake.arg1_history[0], NULL);
317 zassert_equal(comp_fake_comp_set_trigger_callback_fake.return_val_history[0], 0);
318 zassert_equal(comp_fake_comp_set_trigger_callback_fake.arg0_history[1], test_dev);
319 zassert_equal(comp_fake_comp_set_trigger_callback_fake.arg1_history[1], NULL);
320 zassert_equal(comp_fake_comp_set_trigger_callback_fake.return_val_history[1], 0);
321 out = shell_backend_dummy_get_output(test_sh, &out_size);
322 zassert_str_equal(out, "\r\ntriggered\r\n");
323 }
324
ZTEST(comparator_shell,test_trigger_is_pending)325 ZTEST(comparator_shell, test_trigger_is_pending)
326 {
327 int ret;
328 const char *out;
329 size_t out_size;
330
331 shell_backend_dummy_clear_output(test_sh);
332 comp_fake_comp_trigger_is_pending_fake.custom_fake = test_trigger_is_pending_stub_1;
333 ret = shell_execute_cmd(test_sh, "comp trigger_is_pending " FAKE_COMP_NAME);
334 zassert_ok(ret);
335 zassert_equal(comp_fake_comp_trigger_is_pending_fake.call_count, 1);
336 zassert_equal(comp_fake_comp_trigger_is_pending_fake.arg0_val, test_dev);
337 out = shell_backend_dummy_get_output(test_sh, &out_size);
338 zassert_str_equal(out, "\r\n1\r\n");
339
340 comp_fake_comp_trigger_is_pending_fake.custom_fake = test_trigger_is_pending_stub_0;
341 ret = shell_execute_cmd(test_sh, "comp trigger_is_pending " FAKE_COMP_NAME);
342 zassert_ok(ret);
343 zassert_equal(comp_fake_comp_trigger_is_pending_fake.call_count, 2);
344 zassert_equal(comp_fake_comp_trigger_is_pending_fake.arg0_val, test_dev);
345 out = shell_backend_dummy_get_output(test_sh, &out_size);
346 zassert_str_equal(out, "\r\n0\r\n");
347
348 comp_fake_comp_trigger_is_pending_fake.custom_fake = test_trigger_is_pending_stub_eio;
349 ret = shell_execute_cmd(test_sh, "comp trigger_is_pending " FAKE_COMP_NAME);
350 zassert_equal(ret, -EIO);
351 zassert_equal(comp_fake_comp_trigger_is_pending_fake.call_count, 3);
352 zassert_equal(comp_fake_comp_trigger_is_pending_fake.arg0_val, test_dev);
353 out = shell_backend_dummy_get_output(test_sh, &out_size);
354 zassert_str_equal(out, "\r\nfailed to get trigger status\r\n");
355 }
356
357 ZTEST_SUITE(comparator_shell, NULL, test_setup, test_after, NULL, NULL);
358