1 /*
2  * Copyright (c) 2023 Prevas A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 
9 #include <zephyr/drivers/rtc.h>
10 #include <zephyr/drivers/rtc/rtc_fake.h>
11 #include <zephyr/fff.h>
12 #include <zephyr/shell/shell.h>
13 #include <zephyr/shell/shell_dummy.h>
14 #include <zephyr/ztest.h>
15 
16 /**
17  * @addtogroup t_rtc_driver
18  * @{
19  * @defgroup t_rtc_api test_rtc_shell
20  * @}
21  */
22 
23 DEFINE_FFF_GLOBALS;
24 
25 #define FAKE_RTC_NAME DEVICE_DT_NAME(DT_NODELABEL(fake_rtc))
26 
27 /* Helper to mock time  */
28 struct time_mock_val {
29 	int ret_val;
30 	struct rtc_time rtc;
31 };
32 static struct time_mock_val get_time_mock;
33 static struct time_mock_val set_time_mock;
34 
rtc_fake_get_time_mock(const struct device * dev,struct rtc_time * rtc)35 static int rtc_fake_get_time_mock(const struct device *dev, struct rtc_time *rtc)
36 {
37 	ARG_UNUSED(dev);
38 
39 	*rtc = get_time_mock.rtc;
40 	return get_time_mock.ret_val;
41 }
42 
rtc_fake_set_time_mock(const struct device * dev,const struct rtc_time * rtc)43 static int rtc_fake_set_time_mock(const struct device *dev, const struct rtc_time *rtc)
44 {
45 	ARG_UNUSED(dev);
46 
47 	set_time_mock.rtc = *rtc;
48 	return set_time_mock.ret_val;
49 }
50 
configure_set_time_mock(int ret_val)51 static void configure_set_time_mock(int ret_val)
52 {
53 	set_time_mock.ret_val = ret_val;
54 
55 	rtc_fake_set_time_fake.custom_fake = rtc_fake_set_time_mock;
56 }
57 
configure_get_time_mock(int ret_val)58 static void configure_get_time_mock(int ret_val)
59 {
60 	get_time_mock.ret_val = ret_val;
61 	get_time_mock.rtc.tm_year = 2023 - 1900; /* rtc_time year offset */
62 	get_time_mock.rtc.tm_mon = 12 - 1;       /* rtc_time month offset */
63 	get_time_mock.rtc.tm_mday = 24;
64 	get_time_mock.rtc.tm_hour = 12;
65 	get_time_mock.rtc.tm_min = 34;
66 	get_time_mock.rtc.tm_sec = 56;
67 
68 	rtc_fake_get_time_fake.custom_fake = rtc_fake_get_time_mock;
69 }
70 
assert_set_time(int year,int mon,int mday,int hour,int min,int sec)71 static void assert_set_time(int year, int mon, int mday, int hour, int min, int sec)
72 {
73 	const struct rtc_time *rtctime;
74 
75 	zassert_equal(rtc_fake_set_time_fake.call_count, 1, "set_time not called");
76 
77 	rtctime = &set_time_mock.rtc;
78 
79 	zassert_equal(year, rtctime->tm_year + 1900, "Year mismatch");
80 	zassert_equal(mon, rtctime->tm_mon + 1, "Month mismatch");
81 	zassert_equal(mday, rtctime->tm_mday, "Day mismatch");
82 	zassert_equal(hour, rtctime->tm_hour, "Hour mismatch");
83 	zassert_equal(min, rtctime->tm_min, "Minute mismatch");
84 	zassert_equal(sec, rtctime->tm_sec, "Second mismatch");
85 }
86 
ZTEST(rtc_shell,test_rtc_get_ok)87 ZTEST(rtc_shell, test_rtc_get_ok)
88 {
89 	const struct shell *sh = shell_backend_dummy_get_ptr();
90 	int err;
91 
92 	configure_get_time_mock(0);
93 
94 	err = shell_execute_cmd(sh, "rtc get " FAKE_RTC_NAME);
95 	zassert_ok(err, "failed to execute shell command (err %d)", err);
96 	zassert_equal(rtc_fake_get_time_fake.call_count, 1, "get_time not called");
97 }
98 
ZTEST(rtc_shell,test_rtc_get_not_initialized)99 ZTEST(rtc_shell, test_rtc_get_not_initialized)
100 {
101 	const struct shell *sh = shell_backend_dummy_get_ptr();
102 	int err;
103 
104 	configure_get_time_mock(-ENODATA);
105 
106 	err = shell_execute_cmd(sh, "rtc get " FAKE_RTC_NAME);
107 	zassert_ok(err, "shell command (err %d)", err);
108 	zassert_equal(rtc_fake_get_time_fake.call_count, 1, "get_time not called");
109 }
110 
ZTEST(rtc_shell,test_rtc_get_error)111 ZTEST(rtc_shell, test_rtc_get_error)
112 {
113 	const struct shell *sh = shell_backend_dummy_get_ptr();
114 	int err;
115 
116 	configure_get_time_mock(-1);
117 
118 	err = shell_execute_cmd(sh, "rtc get " FAKE_RTC_NAME);
119 	zassert_true(err != 0, "shell command (err %d)", err);
120 	zassert_equal(rtc_fake_get_time_fake.call_count, 1, "get_time not called");
121 }
122 
ZTEST(rtc_shell,test_rtc_set_date)123 ZTEST(rtc_shell, test_rtc_set_date)
124 {
125 	const struct shell *sh = shell_backend_dummy_get_ptr();
126 	int err;
127 
128 	rtc_fake_set_time_fake.return_val = 0;
129 
130 	configure_get_time_mock(0);
131 	configure_set_time_mock(0);
132 
133 	err = shell_execute_cmd(sh, "rtc set " FAKE_RTC_NAME " 2022-05-17");
134 	zassert_ok(err, "failed to execute shell command (err %d)", err);
135 	zassert_equal(rtc_fake_get_time_fake.call_count, 1, "get_time not called");
136 
137 	assert_set_time(2022, 5, 17, get_time_mock.rtc.tm_hour, get_time_mock.rtc.tm_min,
138 			get_time_mock.rtc.tm_sec);
139 }
140 
ZTEST(rtc_shell,test_rtc_set_time)141 ZTEST(rtc_shell, test_rtc_set_time)
142 {
143 	const struct shell *sh = shell_backend_dummy_get_ptr();
144 	int err;
145 
146 	configure_get_time_mock(0);
147 	configure_set_time_mock(0);
148 
149 	err = shell_execute_cmd(sh, "rtc set " FAKE_RTC_NAME " 23:45:16");
150 	zassert_ok(err, "failed to execute shell command (err %d)", err);
151 	zassert_equal(rtc_fake_get_time_fake.call_count, 1, "get_time not called");
152 
153 	assert_set_time(2023, 12, 24, 23, 45, 16);
154 }
155 
ZTEST(rtc_shell,test_rtc_set_full)156 ZTEST(rtc_shell, test_rtc_set_full)
157 {
158 	const struct shell *sh = shell_backend_dummy_get_ptr();
159 	int err;
160 
161 	configure_get_time_mock(0);
162 	configure_set_time_mock(0);
163 
164 	err = shell_execute_cmd(sh, "rtc set " FAKE_RTC_NAME " 2022-05-17T23:45:16");
165 	zassert_ok(err, "failed to execute shell command (err %d)", err);
166 	zassert_equal(rtc_fake_get_time_fake.call_count, 1, "get_time not called");
167 
168 	assert_set_time(2022, 5, 17, 23, 45, 16);
169 }
170 
ZTEST(rtc_shell,test_rtc_set_error)171 ZTEST(rtc_shell, test_rtc_set_error)
172 {
173 	const struct shell *sh = shell_backend_dummy_get_ptr();
174 	int err;
175 
176 	configure_get_time_mock(0);
177 	configure_set_time_mock(-EINVAL);
178 
179 	err = shell_execute_cmd(sh, "rtc set " FAKE_RTC_NAME " 2022:05:17T23:45:16");
180 	zassert_true(err != 0, "failed to execute shell command (err %d)", err);
181 	zassert_equal(rtc_fake_get_time_fake.call_count, 1, "get_time not called");
182 	zassert_equal(rtc_fake_set_time_fake.call_count, 0, "set_time called");
183 }
184 
rtc_shell_setup(void)185 static void *rtc_shell_setup(void)
186 {
187 	const struct shell *sh = shell_backend_dummy_get_ptr();
188 
189 	/* Wait for the initialization of the shell dummy backend. */
190 	WAIT_FOR(shell_ready(sh), 20000, k_msleep(1));
191 	zassert_true(shell_ready(sh), "timed out waiting for dummy shell backend");
192 
193 	return NULL;
194 }
195 
196 ZTEST_SUITE(rtc_shell, NULL, rtc_shell_setup, NULL, NULL, NULL);
197