xref: /aosp_15_r20/external/coreboot/tests/lib/rtc-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <inttypes.h>
4 #include <rtc.h>
5 #include <string.h>
6 #include <tests/test.h>
7 
test_rtc_to_tm_from_unix_time(void ** state)8 static void test_rtc_to_tm_from_unix_time(void **state)
9 {
10 	struct rtc_time tm;
11 	int tim;
12 
13 	/* Zero-day */
14 	tim = 0;
15 	assert_int_equal(0, rtc_to_tm(tim, &tm));
16 	assert_int_equal(1970, tm.year);
17 	assert_int_equal(1, tm.mon);
18 	assert_int_equal(1, tm.mday);
19 	assert_int_equal(0, tm.hour);
20 	assert_int_equal(0, tm.min);
21 	assert_int_equal(0, tm.sec);
22 	assert_int_equal(4, tm.wday); /* Thursday */
23 
24 	/* One second from time base */
25 	tim = 1;
26 	assert_int_equal(0, rtc_to_tm(tim, &tm));
27 	assert_int_equal(1970, tm.year);
28 	assert_int_equal(1, tm.mon);
29 	assert_int_equal(1, tm.mday);
30 	assert_int_equal(0, tm.hour);
31 	assert_int_equal(0, tm.min);
32 	assert_int_equal(1, tm.sec);
33 	assert_int_equal(4, tm.wday); /* Thursday */
34 
35 	/* Full time value */
36 	tim = INT32_MAX;
37 	assert_int_equal(0, rtc_to_tm(tim, &tm));
38 	assert_int_equal(2038, tm.year);
39 	assert_int_equal(1, tm.mon);
40 	assert_int_equal(19, tm.mday);
41 	assert_int_equal(3, tm.hour);
42 	assert_int_equal(14, tm.min);
43 	assert_int_equal(7, tm.sec);
44 	assert_int_equal(2, tm.wday); /* Tuesday */
45 
46 	/* Other common value */
47 	tim = 1618484725;
48 	assert_int_equal(0, rtc_to_tm(tim, &tm));
49 	assert_int_equal(2021, tm.year);
50 	assert_int_equal(4, tm.mon);
51 	assert_int_equal(15, tm.mday);
52 	assert_int_equal(11, tm.hour);
53 	assert_int_equal(5, tm.min);
54 	assert_int_equal(25, tm.sec);
55 	assert_int_equal(4, tm.wday); /* Thursday */
56 
57 	/* Negative value - expect incorrect output */
58 	tim = -1;
59 	assert_int_equal(0, rtc_to_tm(tim, &tm));
60 	assert_int_equal(1970, tm.year);
61 	assert_int_equal(1, tm.mon);
62 	assert_int_equal(1, tm.mday);
63 	assert_int_equal(0, tm.hour);
64 	assert_int_equal(0, tm.min);
65 	assert_int_equal(-1, tm.sec);
66 	assert_int_equal(4, tm.wday); /* Thursday */
67 }
68 
test_mktime(void ** state)69 static void test_mktime(void **state)
70 {
71 	struct rtc_time tm;
72 	struct rtc_time tm2;
73 	memset(&tm, 0, sizeof(tm));
74 	memset(&tm2, 0, sizeof(tm2));
75 
76 	/* Epoch start */
77 	tm = (struct rtc_time){
78 		.year = 1970, .mon = 1, .mday = 1, .hour = 0, .min = 0, .sec = 0,
79 	};
80 	assert_int_equal(0, rtc_mktime(&tm));
81 
82 	/* Last correct value */
83 	tm = (struct rtc_time){
84 		.year = 2038, .mon = 1, .mday = 19, .hour = 3, .min = 14, .sec = 7,
85 	};
86 	assert_int_equal(INT32_MAX, rtc_mktime(&tm));
87 
88 	/* Common non-leap year */
89 	tm = (struct rtc_time){
90 		.year = 1999, .mon = 12, .mday = 6, .hour = 16, .min = 13, .sec = 59,
91 	};
92 	assert_int_equal(944496839, rtc_mktime(&tm));
93 
94 	/* Ensure that February 29 gives the same result as March 1 in non-leap year */
95 	tm = (struct rtc_time){
96 		.year = 2017, .mon = 2, .mday = 29, .hour = 1, .min = 2, .sec = 3,
97 	};
98 	tm2 = (struct rtc_time){
99 		.year = 2017, .mon = 3, .mday = 1, .hour = 1, .min = 2, .sec = 3,
100 	};
101 	assert_int_equal(rtc_mktime(&tm), rtc_mktime(&tm2));
102 
103 	/* Leap year (only division by 4 rule applies) */
104 	tm = (struct rtc_time){
105 		.year = 2004, .mon = 8, .mday = 30, .hour = 13, .min = 45, .sec = 33,
106 	};
107 	assert_int_equal(1093873533, rtc_mktime(&tm));
108 	/* Last day of February in leap year */
109 	tm.mon = 2;
110 	tm.mday = 29;
111 	assert_int_equal(1078062333, rtc_mktime(&tm));
112 	/* Ensure that February 29 and March 1 have different and correct values
113 	   in leap year */
114 	tm = (struct rtc_time){
115 		.year = 2004, .mon = 3, .mday = 1, .hour = 7, .min = 7, .sec = 17,
116 	};
117 	tm2 = (struct rtc_time){
118 		.year = 2004, .mon = 2, .mday = 29, .hour = 7, .min = 7, .sec = 17,
119 	};
120 	/* There should be exactly one day of difference */
121 	assert_int_equal(24 * 60 * 60, rtc_mktime(&tm) - rtc_mktime(&tm2));
122 
123 	/* Leap year (division by 400 rule applies and division by 100 is excluded) */
124 	tm = (struct rtc_time){
125 		.year = 2000, .mon = 6, .mday = 11, .hour = 21, .min = 3, .sec = 6,
126 	};
127 	assert_int_equal(960757386, rtc_mktime(&tm));
128 	tm.mon = 2;
129 	tm.mday = 29;
130 	assert_int_equal(951858186, rtc_mktime(&tm));
131 
132 	tm = (struct rtc_time){
133 		.year = 2000, .mon = 3, .mday = 1, .hour = 10, .min = 55, .sec = 21,
134 	};
135 	tm2 = (struct rtc_time){
136 		.year = 2000, .mon = 2, .mday = 29, .hour = 10, .min = 55, .sec = 21,
137 	};
138 	assert_int_equal(24 * 60 * 60, rtc_mktime(&tm) - rtc_mktime(&tm2));
139 }
140 
assert_rtc_time_equal(struct rtc_time * tm1,struct rtc_time * tm2)141 static void assert_rtc_time_equal(struct rtc_time *tm1, struct rtc_time *tm2)
142 {
143 	assert_int_equal(tm1->sec, tm2->sec);
144 	assert_int_equal(tm1->min, tm2->min);
145 	assert_int_equal(tm1->hour, tm2->hour);
146 	assert_int_equal(tm1->mday, tm2->mday);
147 	assert_int_equal(tm1->mon, tm2->mon);
148 	assert_int_equal(tm1->year, tm2->year);
149 	assert_int_equal(tm1->wday, tm2->wday);
150 }
151 
152 /* This test check if combination of rtc_to_tm and rtc_mktime gives result equal to input.
153    Week day is ignored by rtc_mktime, but is calculated by rtc_to_tm, so it is included
154    in input. */
test_rtc_mktime_with_rtc_to_tm(void ** state)155 static void test_rtc_mktime_with_rtc_to_tm(void **state)
156 {
157 	struct rtc_time tm_in;
158 	struct rtc_time tm_out;
159 	int tim;
160 
161 	memset(&tm_in, 0, sizeof(tm_in));
162 	memset(&tm_out, 0, sizeof(tm_out));
163 
164 	/* Conversion from rtc_time to timestamp and back to rtc_time */
165 	tm_in = (struct rtc_time){
166 		.year = 1970, .mon = 1, .mday = 1, .hour = 0, .min = 0, .sec = 0, .wday = 4,
167 	};
168 	assert_int_equal(0, rtc_to_tm(rtc_mktime(&tm_in), &tm_out));
169 	assert_rtc_time_equal(&tm_in, &tm_out);
170 
171 	tm_in = (struct rtc_time){
172 		.year = 2000, .mon = 2, .mday = 29, .hour = 13, .min = 4, .sec = 15, .wday = 2,
173 	};
174 	assert_int_equal(0, rtc_to_tm(rtc_mktime(&tm_in), &tm_out));
175 	assert_rtc_time_equal(&tm_in, &tm_out);
176 
177 	tm_in = (struct rtc_time){
178 		.year = 2000, .mon = 3, .mday = 1, .hour = 13, .min = 8, .sec = 37, .wday = 3,
179 	};
180 	assert_int_equal(0, rtc_to_tm(rtc_mktime(&tm_in), &tm_out));
181 	assert_rtc_time_equal(&tm_in, &tm_out);
182 
183 	tm_in = (struct rtc_time){
184 		.year = 2017, .mon = 12, .mday = 7, .hour = 8, .min = 18, .sec = 9, .wday = 4,
185 	};
186 	assert_int_equal(0, rtc_to_tm(rtc_mktime(&tm_in), &tm_out));
187 	assert_rtc_time_equal(&tm_in, &tm_out);
188 
189 	tm_in = (struct rtc_time){
190 		.year = 2020, .mon = 2, .mday = 29, .hour = 18, .min = 50, .sec = 0, .wday = 6,
191 	};
192 	assert_int_equal(0, rtc_to_tm(rtc_mktime(&tm_in), &tm_out));
193 	assert_rtc_time_equal(&tm_in, &tm_out);
194 
195 	tm_in = (struct rtc_time){
196 		.year = 2020, .mon = 3, .mday = 1, .hour = 1, .min = 20, .sec = 23, .wday = 0,
197 	};
198 	assert_int_equal(0, rtc_to_tm(rtc_mktime(&tm_in), &tm_out));
199 	assert_rtc_time_equal(&tm_in, &tm_out);
200 
201 
202 	/* Conversion from timestamp to rtc_time and back to timestamp */
203 	tim = 0;
204 	rtc_to_tm(tim, &tm_out);
205 	assert_int_equal(tim, rtc_mktime(&tm_out));
206 
207 	tim = INT32_MAX;
208 	rtc_to_tm(tim, &tm_out);
209 	assert_int_equal(tim, rtc_mktime(&tm_out));
210 
211 	/* 2000-02-29 1:23:34 */
212 	tim = 951787414;
213 	rtc_to_tm(tim, &tm_out);
214 	assert_int_equal(tim, rtc_mktime(&tm_out));
215 
216 	/* 2000-03-01 1:23:34 */
217 	tim = 951873814;
218 	rtc_to_tm(tim, &tm_out);
219 	assert_int_equal(tim, rtc_mktime(&tm_out));
220 
221 	/* 1999-09-09 9:09:09 */
222 	tim = 936868149;
223 	rtc_to_tm(tim, &tm_out);
224 	assert_int_equal(tim, rtc_mktime(&tm_out));
225 
226 	/* 2020-02-29 2:29:02 */
227 	tim = 1582943342;
228 	rtc_to_tm(tim, &tm_out);
229 	assert_int_equal(tim, rtc_mktime(&tm_out));
230 
231 	/* 2020-03-01 3:01:03 */
232 	tim = 1583031663;
233 	rtc_to_tm(tim, &tm_out);
234 	assert_int_equal(tim, rtc_mktime(&tm_out));
235 }
236 
test_leap_day_secday(void ** state)237 static void test_leap_day_secday(void **state)
238 {
239 	const int secday = 60 * 60 * 24;
240 	struct rtc_time tm_in;
241 	struct rtc_time tm_out;
242 	struct rtc_time tm_expected;
243 	int tim;
244 
245 	memset(&tm_in, 0, sizeof(tm_in));
246 	memset(&tm_out, 0, sizeof(tm_out));
247 
248 	/* Non-leap year */
249 	tm_in = (struct rtc_time){
250 		.year = 1999, .mon = 2, .mday = 28, .hour = 5, .min = 37, .sec = 15, .wday = 0,
251 	};
252 	tim = rtc_mktime(&tm_in) + secday;
253 	tm_expected = (struct rtc_time){
254 		.year = 1999, .mon = 3, .mday = 1, .hour = 5, .min = 37, .sec = 15, .wday = 1,
255 	};
256 	assert_int_equal(0, rtc_to_tm(tim, &tm_out));
257 	assert_rtc_time_equal(&tm_out, &tm_expected);
258 
259 	/* Leap-year February 28 to February 29 */
260 	tm_in = (struct rtc_time){
261 		.year = 2000, .mon = 2, .mday = 28, .hour = 0, .min = 33, .sec = 11, .wday = 1,
262 	};
263 	tim = rtc_mktime(&tm_in) + secday;
264 	tm_expected = (struct rtc_time){
265 		.year = 2000, .mon = 2, .mday = 29, .hour = 0, .min = 33, .sec = 11, .wday = 2,
266 	};
267 	assert_int_equal(0, rtc_to_tm(tim, &tm_out));
268 	assert_rtc_time_equal(&tm_out, &tm_expected);
269 
270 	tm_in = (struct rtc_time){
271 		.year = 2004, .mon = 2, .mday = 28, .hour = 9, .min = 13, .sec = 45, .wday = 6,
272 	};
273 	tim = rtc_mktime(&tm_in) + secday;
274 	tm_expected = (struct rtc_time){
275 		.year = 2004, .mon = 2, .mday = 29, .hour = 9, .min = 13, .sec = 45, .wday = 0,
276 	};
277 	assert_int_equal(0, rtc_to_tm(tim, &tm_out));
278 	assert_rtc_time_equal(&tm_out, &tm_expected);
279 
280 	/* Leap-year February 29 to March 1 */
281 	tm_in = (struct rtc_time){
282 		.year = 2000, .mon = 2, .mday = 29, .hour = 22, .min = 50, .sec = 25, .wday = 2,
283 	};
284 	tim = rtc_mktime(&tm_in) + secday;
285 	tm_expected = (struct rtc_time){
286 		.year = 2000, .mon = 3, .mday = 1, .hour = 22, .min = 50, .sec = 25, .wday = 3,
287 	};
288 	assert_int_equal(0, rtc_to_tm(tim, &tm_out));
289 	assert_rtc_time_equal(&tm_out, &tm_expected);
290 
291 	tm_in = (struct rtc_time){
292 		.year = 2004, .mon = 2, .mday = 29, .hour = 17, .min = 56, .sec = 27, .wday = 0,
293 	};
294 	tim = rtc_mktime(&tm_in) + secday;
295 	tm_expected = (struct rtc_time){
296 		.year = 2004, .mon = 3, .mday = 1, .hour = 17, .min = 56, .sec = 27, .wday = 1,
297 	};
298 	assert_int_equal(0, rtc_to_tm(tim, &tm_out));
299 	assert_rtc_time_equal(&tm_out, &tm_expected);
300 }
301 
main(void)302 int main(void)
303 {
304 	const struct CMUnitTest tests[] = {
305 		cmocka_unit_test(test_rtc_to_tm_from_unix_time),
306 		cmocka_unit_test(test_mktime),
307 		cmocka_unit_test(test_rtc_mktime_with_rtc_to_tm),
308 		cmocka_unit_test(test_leap_day_secday),
309 	};
310 
311 	return cb_run_group_tests(tests, NULL, NULL);
312 }
313