Skip to content

Commit 434787b

Browse files
authored
Merge pull request #4499 from c1728p9/fix_rtc_api_time_conversion
Fix rtc api time conversion
2 parents e98a744 + 6b020a3 commit 434787b

File tree

13 files changed

+629
-142
lines changed

13 files changed

+629
-142
lines changed

TESTS/mbed_hal/rtc_time/main.cpp

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "utest/utest.h"
18+
#include "unity/unity.h"
19+
#include "greentea-client/test_env.h"
20+
21+
#include "mbed.h"
22+
#include "mbed_mktime.h"
23+
24+
using namespace utest::v1;
25+
26+
/*
27+
* regular is_leap_year, see platform/mbed_mktime.c for the optimized version
28+
*/
29+
bool is_leap_year(int year) {
30+
year = 1900 + year;
31+
if (year % 4) {
32+
return false;
33+
} else if (year % 100) {
34+
return true;
35+
} else if (year % 400) {
36+
return false;
37+
}
38+
return true;
39+
}
40+
41+
/*
42+
* Test the optimized version of _rtc_is_leap_year against the generic version.
43+
*/
44+
void test_is_leap_year() {
45+
for (int i = 70; i < 138; ++i) {
46+
bool expected = is_leap_year(i);
47+
bool actual_value = _rtc_is_leap_year(i);
48+
49+
if (expected != actual_value) {
50+
printf ("leap year failed with i = %d\r\n", i);
51+
}
52+
TEST_ASSERT_EQUAL(expected, actual_value);
53+
}
54+
}
55+
56+
struct tm make_time_info(int year, int month, int day, int hours, int minutes, int seconds) {
57+
struct tm timeinfo;
58+
timeinfo.tm_year = year;
59+
timeinfo.tm_mon = month;
60+
timeinfo.tm_mday = day;
61+
timeinfo.tm_hour = hours;
62+
timeinfo.tm_min = minutes;
63+
timeinfo.tm_sec = seconds;
64+
return timeinfo;
65+
}
66+
67+
/*
68+
* test out of range values for _rtc_mktime.
69+
* The function operates from the 1st of january 1970 at 00:00:00 to the 19th
70+
* of january 2038 at 03:14:07.
71+
*/
72+
void test_mk_time_out_of_range() {
73+
tm invalid_lower_bound = make_time_info(
74+
69,
75+
11,
76+
31,
77+
23,
78+
59,
79+
59
80+
);
81+
82+
tm valid_lower_bound = make_time_info(
83+
70,
84+
0,
85+
1,
86+
0,
87+
0,
88+
0
89+
);
90+
91+
tm valid_upper_bound = make_time_info(
92+
138,
93+
0,
94+
19,
95+
3,
96+
14,
97+
7
98+
);
99+
100+
tm invalid_upper_bound = make_time_info(
101+
138,
102+
0,
103+
19,
104+
3,
105+
14,
106+
8
107+
);
108+
109+
TEST_ASSERT_EQUAL_INT(((time_t) -1), _rtc_mktime(&invalid_lower_bound));
110+
TEST_ASSERT_EQUAL_INT(((time_t) 0), _rtc_mktime(&valid_lower_bound));
111+
TEST_ASSERT_EQUAL_INT(((time_t) INT_MAX), _rtc_mktime(&valid_upper_bound));
112+
TEST_ASSERT_EQUAL_INT(((time_t) -1), _rtc_mktime(&invalid_upper_bound));
113+
}
114+
115+
/*
116+
* test mktime over a large set of values
117+
*/
118+
void test_mk_time() {
119+
for (size_t year = 70; year < 137; ++year) {
120+
for (size_t month = 0; month < 12; ++month) {
121+
for (size_t day = 1; day < 32; ++day) {
122+
if (month == 1 && is_leap_year(year) && day == 29) {
123+
break;
124+
} else if(month == 1 && !is_leap_year(year) && day == 28) {
125+
break;
126+
} else if (
127+
day == 31 &&
128+
(month == 3 || month == 5 || month == 8 || month == 10)
129+
) {
130+
break;
131+
}
132+
133+
for (size_t hour = 0; hour < 24; ++hour) {
134+
tm time_info = make_time_info(
135+
year,
136+
month,
137+
day,
138+
hour,
139+
hour % 2 ? 59 : 0,
140+
hour % 2 ? 59 : 0
141+
);
142+
143+
time_t expected = mktime(&time_info);
144+
time_t actual_value = _rtc_mktime(&time_info);
145+
146+
char msg[128] = "";
147+
if (expected != actual_value) {
148+
snprintf(
149+
msg, sizeof(msg),
150+
"year = %d, month = %d, day = %d, diff = %ld",
151+
year, month, day, expected - actual_value
152+
);
153+
}
154+
155+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual_value, msg);
156+
}
157+
}
158+
}
159+
}
160+
}
161+
162+
/*
163+
* test value out of range for localtime
164+
*/
165+
void test_local_time_limit() {
166+
struct tm dummy_value;
167+
TEST_ASSERT_FALSE(_rtc_localtime((time_t) -1, &dummy_value));
168+
TEST_ASSERT_FALSE(_rtc_localtime((time_t) INT_MIN, &dummy_value));
169+
}
170+
171+
/*
172+
* test _rtc_localtime over a large set of values.
173+
*/
174+
void test_local_time() {
175+
for (uint32_t i = 0; i < INT_MAX; i += 3451) {
176+
time_t copy = (time_t) i;
177+
struct tm* expected = localtime(&copy);
178+
struct tm actual_value;
179+
bool result = _rtc_localtime((time_t) i, &actual_value);
180+
181+
if (
182+
expected->tm_sec != actual_value.tm_sec ||
183+
expected->tm_min != actual_value.tm_min ||
184+
expected->tm_hour != actual_value.tm_hour ||
185+
expected->tm_mday != actual_value.tm_mday ||
186+
expected->tm_mon != actual_value.tm_mon ||
187+
expected->tm_year != actual_value.tm_year ||
188+
expected->tm_wday != actual_value.tm_wday ||
189+
expected->tm_yday != actual_value.tm_yday ||
190+
result == false
191+
) {
192+
printf("error: i = %lu\r\n", i);
193+
}
194+
195+
TEST_ASSERT_TRUE(result);
196+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
197+
expected->tm_sec, actual_value.tm_sec, "invalid seconds"
198+
);
199+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
200+
expected->tm_min, actual_value.tm_min, "invalid minutes"
201+
);
202+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
203+
expected->tm_hour, actual_value.tm_hour, "invalid hours"
204+
);
205+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
206+
expected->tm_mday, actual_value.tm_mday, "invalid day"
207+
);
208+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
209+
expected->tm_mon, actual_value.tm_mon, "invalid month"
210+
);
211+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
212+
expected->tm_year, actual_value.tm_year, "invalid year"
213+
);
214+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
215+
expected->tm_wday, actual_value.tm_wday, "invalid weekday"
216+
);
217+
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
218+
expected->tm_yday, actual_value.tm_yday, "invalid year day"
219+
);
220+
}
221+
}
222+
223+
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason) {
224+
greentea_case_failure_abort_handler(source, reason);
225+
return STATUS_CONTINUE;
226+
}
227+
228+
Case cases[] = {
229+
Case("test is leap year", test_is_leap_year, greentea_failure_handler),
230+
Case("test mk time out of range values", test_mk_time_out_of_range, greentea_failure_handler),
231+
Case("mk time", test_mk_time, greentea_failure_handler),
232+
Case("test local time", test_local_time, greentea_failure_handler),
233+
Case("test local time limits", test_local_time_limit, greentea_failure_handler),
234+
};
235+
236+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
237+
GREENTEA_SETUP(1200, "default_auto");
238+
return greentea_test_setup_handler(number_of_cases);
239+
}
240+
241+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
242+
243+
int main() {
244+
return Harness::run(specification);
245+
}

0 commit comments

Comments
 (0)