mirror of https://github.com/ARMmbed/mbed-os.git
Add tests for extended RTC.
parent
dc5a66dc5c
commit
fcdaeccea1
|
@ -0,0 +1,138 @@
|
||||||
|
"""
|
||||||
|
mbed SDK
|
||||||
|
Copyright (c) 2011-2013 ARM Limited
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from mbed_host_tests import BaseHostTest
|
||||||
|
import time
|
||||||
|
import calendar
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
class RTC_time_calc_test(BaseHostTest):
|
||||||
|
"""
|
||||||
|
This is the host part of the test to verify if:
|
||||||
|
- _rtc_mktime function converts a calendar time into time since UNIX epoch as a time_t,
|
||||||
|
- _rtc_localtime function converts a given time in seconds since epoch into calendar time.
|
||||||
|
|
||||||
|
The same algoritm to generate next calendar time to be tested is used by both parts of the test.
|
||||||
|
We will check if correct time since UNIX epoch is calculated for the first and the last day
|
||||||
|
of each month and across valid years.
|
||||||
|
|
||||||
|
Mbed part of the test sends calculated time since UNIX epoch.
|
||||||
|
This part validates given value and responds to indicate pass or fail.
|
||||||
|
Additionally it sends also encoded day of week and day of year which
|
||||||
|
will be needed to verify _rtc_localtime.
|
||||||
|
|
||||||
|
Support for both types of RTC devices is provided:
|
||||||
|
- RTCs which handles all leap years in the mentioned year range correctly. Leap year is determined by checking if
|
||||||
|
the year counter value is divisible by 400, 100, and 4. No problem here.
|
||||||
|
- RTCs which handles leap years correctly up to 2100. The RTC does a simple bit comparison to see if the two
|
||||||
|
lowest order bits of the year counter are zero. In this case 2100 year will be considered
|
||||||
|
incorrectly as a leap year, so the last valid point in time will be 28.02.2100 23:59:59 and next day will be
|
||||||
|
29.02.2100 (invalid). So after 28.02.2100 the day counter will be off by a day.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
edge_date = datetime.datetime(2100, 2, 28, 0, 0, 0)
|
||||||
|
|
||||||
|
years = [1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980,
|
||||||
|
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
|
2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106]
|
||||||
|
year_id = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
full_leap_year_support = False
|
||||||
|
|
||||||
|
RTC_FULL_LEAP_YEAR_SUPPORT = 0
|
||||||
|
RTC_PARTIAL_LEAP_YEAR_SUPPORT = 1
|
||||||
|
|
||||||
|
def _set_leap_year_support(self, key, value, timestamp):
|
||||||
|
if (int(value) == self.RTC_FULL_LEAP_YEAR_SUPPORT):
|
||||||
|
self.full_leap_year_support = True
|
||||||
|
else:
|
||||||
|
self.full_leap_year_support = False
|
||||||
|
|
||||||
|
self.first = True
|
||||||
|
self.date = datetime.datetime(1970, 1, 1, 23, 0, 0)
|
||||||
|
self.year_id = 0
|
||||||
|
|
||||||
|
def _verify_timestamp(self, key, value, timestamp):
|
||||||
|
# week day in python is counted from sunday(0) and on mbed side week day is counted from monday(0).
|
||||||
|
# year day in python is counted from 1 and on mbed side year day is counted from 0.
|
||||||
|
week_day = ((self.date.timetuple().tm_wday + 1) % 7)
|
||||||
|
year_day = self.date.timetuple().tm_yday - 1
|
||||||
|
|
||||||
|
# Fix for RTC which not have full leap year support.
|
||||||
|
if (not self.full_leap_year_support):
|
||||||
|
if self.date >= self.edge_date:
|
||||||
|
# After 28.02.2100 we should be one day off - add this day and store original
|
||||||
|
date_org = self.date
|
||||||
|
self.date += datetime.timedelta(days = 1)
|
||||||
|
|
||||||
|
# Adjust week day.
|
||||||
|
week_day = ((self.date.timetuple().tm_wday + 1) % 7)
|
||||||
|
|
||||||
|
# Adjust year day.
|
||||||
|
if (self.date.year == 2100):
|
||||||
|
year_day = self.date.timetuple().tm_yday - 1
|
||||||
|
else:
|
||||||
|
year_day = date_org.timetuple().tm_yday - 1
|
||||||
|
|
||||||
|
# Last day in year
|
||||||
|
if (self.date.month == 1 and self.date.day == 1):
|
||||||
|
if (self.date.year == 2101):
|
||||||
|
# Exception for year 2100 - ivalid handled by RTC without full leap year support
|
||||||
|
year_day = 365
|
||||||
|
else:
|
||||||
|
year_day = date_org.timetuple().tm_yday - 1
|
||||||
|
|
||||||
|
t = (self.date.year , self.date.month, self.date.day, self.date.hour, self.date.minute, self.date.second, 0, 0, 0)
|
||||||
|
|
||||||
|
expected_timestamp = calendar.timegm(t)
|
||||||
|
actual_timestamp = int(value) & 0xffffffff # convert to unsigned int
|
||||||
|
|
||||||
|
# encode week day and year day in the response
|
||||||
|
response = (week_day << 16) | year_day
|
||||||
|
|
||||||
|
if (actual_timestamp == expected_timestamp):
|
||||||
|
# response contains encoded week day and year day
|
||||||
|
self.send_kv("passed", str(response))
|
||||||
|
else:
|
||||||
|
self.send_kv("failed", 0)
|
||||||
|
print "expected = %d, result = %d" % (expected_timestamp , actual_timestamp)
|
||||||
|
|
||||||
|
# calculate next date
|
||||||
|
if (self.first):
|
||||||
|
days_range = calendar.monthrange(self.date.year, self.date.month)
|
||||||
|
self.date = self.date.replace(day = days_range[1], minute = 59, second = 59)
|
||||||
|
self.first = not self.first
|
||||||
|
else:
|
||||||
|
self.date += datetime.timedelta(days = 1)
|
||||||
|
if (self.date.month == 1):
|
||||||
|
self.year_id += 1
|
||||||
|
self.date = self.date.replace(year = self.years[self.year_id])
|
||||||
|
self.date = self.date.replace(day = 1, minute = 0, second = 0)
|
||||||
|
self.first = not self.first
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.register_callback('timestamp', self._verify_timestamp)
|
||||||
|
self.register_callback('leap_year_setup', self._set_leap_year_support)
|
||||||
|
|
||||||
|
def result(self):
|
||||||
|
return self.__result
|
||||||
|
|
||||||
|
def teardown(self):
|
||||||
|
pass
|
|
@ -21,23 +21,15 @@
|
||||||
#include "mbed.h"
|
#include "mbed.h"
|
||||||
#include "mbed_mktime.h"
|
#include "mbed_mktime.h"
|
||||||
|
|
||||||
// Limit the test range to 1935 for IAR only. From the IAR C/C++ Development Guide:
|
#define LAST_VALID_YEAR 206
|
||||||
// "The 32-bit interface supports years from 1900 up to 2035 and uses a 32-bit integer
|
|
||||||
// for time_t."
|
|
||||||
#ifdef __ICCARM__
|
|
||||||
#define LOCALTIME_MAX 2082758400 // 1st of january 2036 at 00:00:00
|
|
||||||
#define MKTIME_YR_MAX 136
|
|
||||||
#else
|
|
||||||
#define LOCALTIME_MAX INT_MAX
|
|
||||||
#define MKTIME_YR_MAX 137
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
||||||
/*
|
static rtc_leap_year_support_t rtc_leap_year_support;
|
||||||
* regular is_leap_year, see platform/mbed_mktime.c for the optimized version
|
|
||||||
*/
|
/* Regular is_leap_year, see platform/mbed_mktime.c for the optimised version. */
|
||||||
bool is_leap_year(int year) {
|
bool is_leap_year(int year)
|
||||||
|
{
|
||||||
year = 1900 + year;
|
year = 1900 + year;
|
||||||
if (year % 4) {
|
if (year % 4) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -49,212 +41,173 @@ bool is_leap_year(int year) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Test the optimised version of _rtc_is_leap_year() against the generic version.
|
||||||
* Test the optimized version of _rtc_is_leap_year against the generic version.
|
*
|
||||||
|
* Note: This test case is designed for both types of RTC devices:
|
||||||
|
* - RTC devices which handle correctly leap years in whole range (1970 - 2106).
|
||||||
|
* - RTC devices which does not handle correctly leap years in whole range (1970 - 2106).
|
||||||
|
* This RTC devices uses simpler leap year detection and incorrectly treat 2100 as a leap year.
|
||||||
|
* rtc_leap_year_support variable specifies which device is tested.
|
||||||
|
*
|
||||||
|
* Given is year in valid range.
|
||||||
|
* When _rtc_is_leap_year() function is called.
|
||||||
|
* Then _rtc_is_leap_year() returns true if given year is a leap year; false otherwise.
|
||||||
*/
|
*/
|
||||||
void test_is_leap_year() {
|
void test_is_leap_year()
|
||||||
for (int i = 70; i < 138; ++i) {
|
{
|
||||||
|
for (int i = 70; i <= LAST_VALID_YEAR; ++i) {
|
||||||
bool expected = is_leap_year(i);
|
bool expected = is_leap_year(i);
|
||||||
bool actual_value = _rtc_is_leap_year(i);
|
|
||||||
|
/* Add exception for year 2100. */
|
||||||
|
if (rtc_leap_year_support == RTC_4_YEAR_LEAP_YEAR_SUPPORT && i == 200) {
|
||||||
|
expected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool actual_value = _rtc_is_leap_year(i, rtc_leap_year_support);
|
||||||
|
|
||||||
if (expected != actual_value) {
|
if (expected != actual_value) {
|
||||||
printf ("leap year failed with i = %d\r\n", i);
|
printf("Leap year failed with i = %d\r\n", i);
|
||||||
}
|
}
|
||||||
TEST_ASSERT_EQUAL(expected, actual_value);
|
TEST_ASSERT_EQUAL(expected, actual_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tm make_time_info(int year, int month, int day, int hours, int minutes, int seconds) {
|
/* Structure to test border values for _rtc_maketime(). */
|
||||||
struct tm timeinfo = {
|
typedef struct
|
||||||
seconds, // tm_sec
|
{
|
||||||
minutes, // tm_min
|
struct tm timeinfo;
|
||||||
hours, // tm_hour
|
time_t exp_seconds; // if result is false then exp_seconds is irrelevant
|
||||||
day, // tm_mday
|
bool result;
|
||||||
month, // tm_mon
|
} test_mk_time_struct;
|
||||||
year, // tm_year
|
|
||||||
0, // tm_wday
|
|
||||||
0, // tm_yday
|
|
||||||
0, // tm_isdst
|
|
||||||
};
|
|
||||||
return timeinfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/* Array which contains data to test boundary values for the RTC devices which handles correctly leap years in
|
||||||
* test out of range values for _rtc_mktime.
|
* whole range (1970 - 2106).
|
||||||
* The function operates from the 1st of january 1970 at 00:00:00 to the 19th
|
* Expected range: the 1st of January 1970 at 00:00:00 (seconds: 0) to the 7th of February 2106 at 06:28:15 (seconds: UINT_MAX).
|
||||||
* of january 2038 at 03:14:07.
|
|
||||||
*/
|
*/
|
||||||
void test_mk_time_out_of_range() {
|
test_mk_time_struct test_mk_time_arr_full[] = {
|
||||||
tm invalid_lower_bound = make_time_info(
|
{{ 0, 0, 0, 1, 0, 70, 0, 0, 0 }, (time_t) 0, true}, // valid lower bound - the 1st of January 1970 at 00:00:00
|
||||||
69,
|
{{ 59, 59, 23, 31, 11, 59, 0, 0, 0 }, (time_t) 0, false }, // invalid lower bound - the 31st of December 1969 at 23:59:59
|
||||||
11,
|
|
||||||
31,
|
|
||||||
23,
|
|
||||||
59,
|
|
||||||
59
|
|
||||||
);
|
|
||||||
|
|
||||||
tm valid_lower_bound = make_time_info(
|
{{ 15, 28, 6, 7, 1, 206, 0, 0, 0 }, (time_t)(UINT_MAX), true }, // valid upper bound - the 7th of February 2106 at 06:28:15
|
||||||
70,
|
{{ 16, 28, 6, 7, 1, 206, 0, 0, 0 }, (time_t) 0, false }, // invalid upper bound - the 7th of February 2106 at 06:28:16
|
||||||
0,
|
};
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
tm valid_upper_bound = make_time_info(
|
/* Array which contains data to test boundary values for the RTC devices which does not handle correctly leap years in
|
||||||
138,
|
* whole range (1970 - 2106). On this platforms we will be one day off after 28.02.2100 since 2100 year will be
|
||||||
0,
|
* incorrectly treated as a leap year.
|
||||||
19,
|
* Expected range: the 1st of January 1970 at 00:00:00 (seconds: 0) to the 6th of February 2106 at 06:28:15 (seconds: UINT_MAX).
|
||||||
3,
|
|
||||||
14,
|
|
||||||
7
|
|
||||||
);
|
|
||||||
|
|
||||||
tm invalid_upper_bound = make_time_info(
|
|
||||||
138,
|
|
||||||
0,
|
|
||||||
19,
|
|
||||||
3,
|
|
||||||
14,
|
|
||||||
8
|
|
||||||
);
|
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(((time_t) -1), _rtc_mktime(&invalid_lower_bound));
|
|
||||||
TEST_ASSERT_EQUAL_INT(((time_t) 0), _rtc_mktime(&valid_lower_bound));
|
|
||||||
TEST_ASSERT_EQUAL_INT(((time_t) INT_MAX), _rtc_mktime(&valid_upper_bound));
|
|
||||||
TEST_ASSERT_EQUAL_INT(((time_t) -1), _rtc_mktime(&invalid_upper_bound));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* test mktime over a large set of values
|
|
||||||
*/
|
*/
|
||||||
void test_mk_time() {
|
test_mk_time_struct test_mk_time_arr_partial[] = {
|
||||||
for (size_t year = 70; year < MKTIME_YR_MAX; ++year) {
|
{{ 0, 0, 0, 1, 0, 70, 0, 0, 0 }, (time_t) 0, true}, // valid lower bound - the 1st of January 1970 at 00:00:00
|
||||||
for (size_t month = 0; month < 12; ++month) {
|
{{ 59, 59, 23, 31, 11, 59, 0, 0, 0 }, (time_t) 0, false }, // invalid lower bound - the 31st of December 1969 at 23:59:59
|
||||||
for (size_t day = 1; day < 32; ++day) {
|
|
||||||
if (month == 1 && is_leap_year(year) && day == 29) {
|
|
||||||
break;
|
|
||||||
} else if(month == 1 && !is_leap_year(year) && day == 28) {
|
|
||||||
break;
|
|
||||||
} else if (
|
|
||||||
day == 31 &&
|
|
||||||
(month == 3 || month == 5 || month == 8 || month == 10)
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t hour = 0; hour < 24; ++hour) {
|
{{ 15, 28, 6, 6, 1, 206, 0, 0, 0 }, (time_t)(UINT_MAX), true }, // valid upper bound - the 6th of February 2106 at 06:28:15
|
||||||
tm time_info = make_time_info(
|
{{ 16, 28, 6, 6, 1, 206, 0, 0, 0 }, (time_t) 0, false }, // invalid upper bound - the 6th of February 2106 at 06:28:16
|
||||||
year,
|
};
|
||||||
month,
|
|
||||||
day,
|
|
||||||
hour,
|
|
||||||
hour % 2 ? 59 : 0,
|
|
||||||
hour % 2 ? 59 : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
time_t expected = mktime(&time_info);
|
/* Test boundary values for _rtc_maketime().
|
||||||
time_t actual_value = _rtc_mktime(&time_info);
|
*
|
||||||
|
* Note: This test case is designed for both types of RTC devices:
|
||||||
|
* - RTC devices which handle correctly leap years in whole range (1970 - 2106).
|
||||||
|
* - RTC devices which does not handle correctly leap years in whole range (1970 - 2106).
|
||||||
|
* This RTC devices uses simpler leap year detection and incorrectly treat 2100 as a leap year.
|
||||||
|
* rtc_leap_year_support variable specifies which device is tested.
|
||||||
|
*
|
||||||
|
* Given is boundary calendar time.
|
||||||
|
* When _rtc_maketime() function is called to convert the calendar time into timestamp.
|
||||||
|
* Then if given calendar time is valid function returns true and conversion result, otherwise returns false.
|
||||||
|
*/
|
||||||
|
void test_mk_time_boundary()
|
||||||
|
{
|
||||||
|
test_mk_time_struct *pTestCases;
|
||||||
|
|
||||||
char msg[128] = "";
|
/* Select array with test cases. */
|
||||||
if (expected != actual_value) {
|
if (rtc_leap_year_support == RTC_FULL_LEAP_YEAR_SUPPORT) {
|
||||||
snprintf(
|
pTestCases = test_mk_time_arr_full;
|
||||||
msg, sizeof(msg),
|
} else {
|
||||||
"year = %d, month = %d, day = %d, diff = %ld",
|
pTestCases = test_mk_time_arr_partial;
|
||||||
year, month, day, expected - actual_value
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual_value, msg);
|
for (int i = 0; i < (sizeof(test_mk_time_arr_full) / (sizeof(test_mk_time_struct))); i++) {
|
||||||
}
|
time_t seconds;
|
||||||
}
|
bool result = _rtc_maketime(&pTestCases[i].timeinfo, &seconds, rtc_leap_year_support);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(pTestCases[i].result, result);
|
||||||
|
|
||||||
|
/* If the result is false, then we have conversion error - skip checking seconds. */
|
||||||
|
if (pTestCases[i].result) {
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(pTestCases[i].exp_seconds, seconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Test _rtc_maketime() function - call with invalid parameters.
|
||||||
* test value out of range for localtime
|
*
|
||||||
|
* Given is _rtc_maketime() function.
|
||||||
|
* When _rtc_maketime() function is called with invalid parameter.
|
||||||
|
* Then _rtc_maketime() function returns false.
|
||||||
*/
|
*/
|
||||||
void test_local_time_limit() {
|
void test_mk_time_invalid_param()
|
||||||
struct tm dummy_value;
|
{
|
||||||
TEST_ASSERT_FALSE(_rtc_localtime((time_t) -1, &dummy_value));
|
time_t seconds;
|
||||||
TEST_ASSERT_FALSE(_rtc_localtime((time_t) INT_MIN, &dummy_value));
|
struct tm timeinfo;
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(false, _rtc_maketime(NULL, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT ));
|
||||||
|
TEST_ASSERT_EQUAL(false, _rtc_maketime(NULL, &seconds, RTC_4_YEAR_LEAP_YEAR_SUPPORT ));
|
||||||
|
TEST_ASSERT_EQUAL(false, _rtc_maketime(&timeinfo, NULL, RTC_FULL_LEAP_YEAR_SUPPORT ));
|
||||||
|
TEST_ASSERT_EQUAL(false, _rtc_maketime(&timeinfo, NULL, RTC_4_YEAR_LEAP_YEAR_SUPPORT ));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Test _rtc_localtime() function - call with invalid parameters.
|
||||||
* test _rtc_localtime over a large set of values.
|
*
|
||||||
|
* Given is _rtc_localtime() function.
|
||||||
|
* When _rtc_localtime() function is called with invalid parameter.
|
||||||
|
* Then _rtc_localtime() function returns false.
|
||||||
*/
|
*/
|
||||||
void test_local_time() {
|
void test_local_time_invalid_param()
|
||||||
for (uint32_t i = 0; i < LOCALTIME_MAX; i += 3451) {
|
{
|
||||||
time_t copy = (time_t) i;
|
TEST_ASSERT_EQUAL(false, _rtc_localtime(1, NULL, RTC_FULL_LEAP_YEAR_SUPPORT ));
|
||||||
struct tm* expected = localtime(©);
|
TEST_ASSERT_EQUAL(false, _rtc_localtime(1, NULL, RTC_4_YEAR_LEAP_YEAR_SUPPORT ));
|
||||||
struct tm actual_value;
|
|
||||||
bool result = _rtc_localtime((time_t) i, &actual_value);
|
|
||||||
|
|
||||||
if (
|
|
||||||
expected->tm_sec != actual_value.tm_sec ||
|
|
||||||
expected->tm_min != actual_value.tm_min ||
|
|
||||||
expected->tm_hour != actual_value.tm_hour ||
|
|
||||||
expected->tm_mday != actual_value.tm_mday ||
|
|
||||||
expected->tm_mon != actual_value.tm_mon ||
|
|
||||||
expected->tm_year != actual_value.tm_year ||
|
|
||||||
expected->tm_wday != actual_value.tm_wday ||
|
|
||||||
expected->tm_yday != actual_value.tm_yday ||
|
|
||||||
result == false
|
|
||||||
) {
|
|
||||||
printf("error: i = %lu\r\n", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_ASSERT_TRUE(result);
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
|
||||||
expected->tm_sec, actual_value.tm_sec, "invalid seconds"
|
|
||||||
);
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
|
||||||
expected->tm_min, actual_value.tm_min, "invalid minutes"
|
|
||||||
);
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
|
||||||
expected->tm_hour, actual_value.tm_hour, "invalid hours"
|
|
||||||
);
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
|
||||||
expected->tm_mday, actual_value.tm_mday, "invalid day"
|
|
||||||
);
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
|
||||||
expected->tm_mon, actual_value.tm_mon, "invalid month"
|
|
||||||
);
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
|
||||||
expected->tm_year, actual_value.tm_year, "invalid year"
|
|
||||||
);
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
|
||||||
expected->tm_wday, actual_value.tm_wday, "invalid weekday"
|
|
||||||
);
|
|
||||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
|
||||||
expected->tm_yday, actual_value.tm_yday, "invalid year day"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason) {
|
utest::v1::status_t teardown_handler_t(const Case * const source, const size_t passed, const size_t failed,
|
||||||
greentea_case_failure_abort_handler(source, reason);
|
const failure_t reason)
|
||||||
return STATUS_CONTINUE;
|
{
|
||||||
|
return greentea_case_teardown_handler(source, passed, failed, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t full_leap_year_case_setup_handler_t(const Case * const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
rtc_leap_year_support = RTC_FULL_LEAP_YEAR_SUPPORT;
|
||||||
|
|
||||||
|
return greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t partial_leap_year_case_setup_handler_t(const Case * const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
rtc_leap_year_support = RTC_4_YEAR_LEAP_YEAR_SUPPORT;
|
||||||
|
|
||||||
|
return greentea_case_setup_handler(source, index_of_case);
|
||||||
}
|
}
|
||||||
|
|
||||||
Case cases[] = {
|
Case cases[] = {
|
||||||
Case("test is leap year", test_is_leap_year, greentea_failure_handler),
|
Case("test is leap year - RTC leap years full support", full_leap_year_case_setup_handler_t, test_is_leap_year, teardown_handler_t),
|
||||||
Case("test mk time out of range values", test_mk_time_out_of_range, greentea_failure_handler),
|
Case("test is leap year - RTC leap years partial support", partial_leap_year_case_setup_handler_t, test_is_leap_year, teardown_handler_t),
|
||||||
Case("mk time", test_mk_time, greentea_failure_handler),
|
Case("test make time boundary values - RTC leap years full support", full_leap_year_case_setup_handler_t, test_mk_time_boundary, teardown_handler_t),
|
||||||
Case("test local time", test_local_time, greentea_failure_handler),
|
Case("test make time boundary values - RTC leap years partial support", partial_leap_year_case_setup_handler_t, test_mk_time_boundary, teardown_handler_t),
|
||||||
Case("test local time limits", test_local_time_limit, greentea_failure_handler),
|
Case("test make time - invalid param", test_mk_time_invalid_param, teardown_handler_t),
|
||||||
|
Case("test local time - invalid param", test_local_time_invalid_param, teardown_handler_t),
|
||||||
};
|
};
|
||||||
|
|
||||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
|
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||||
GREENTEA_SETUP(1200, "default_auto");
|
{
|
||||||
|
GREENTEA_SETUP(20, "default_auto");
|
||||||
return greentea_test_setup_handler(number_of_cases);
|
return greentea_test_setup_handler(number_of_cases);
|
||||||
}
|
}
|
||||||
|
|
||||||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
return Harness::run(specification);
|
return Harness::run(specification);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016, ARM Limited, All Rights Reserved
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the mbed device part of the test to verify if:
|
||||||
|
* - _rtc_maketime() function converts a calendar time into time since UNIX epoch as a time_t,
|
||||||
|
* - _rtc_localtime() function converts a given time in seconds since epoch into calendar time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mbed.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "mbed_mktime.h"
|
||||||
|
|
||||||
|
#define LAST_VALID_YEAR 206
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
static rtc_leap_year_support_t rtc_leap_year_support;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* regular is_leap_year, see platform/mbed_mktime.c for the optimised version
|
||||||
|
*/
|
||||||
|
bool is_leap_year(int year)
|
||||||
|
{
|
||||||
|
year = 1900 + year;
|
||||||
|
if (year % 4) {
|
||||||
|
return false;
|
||||||
|
} else if (year % 100) {
|
||||||
|
return true;
|
||||||
|
} else if (year % 400) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tm make_time_info(int year, int month, int day, int hours, int minutes, int seconds)
|
||||||
|
{
|
||||||
|
struct tm timeinfo =
|
||||||
|
{ seconds, // tm_sec
|
||||||
|
minutes, // tm_min
|
||||||
|
hours, // tm_hour
|
||||||
|
day, // tm_mday
|
||||||
|
month, // tm_mon
|
||||||
|
year, // tm_year
|
||||||
|
0, // tm_wday
|
||||||
|
0, // tm_yday
|
||||||
|
0, // tm_isdst
|
||||||
|
};
|
||||||
|
return timeinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test _rtc_maketime() and _rtc_localtime() across wide range
|
||||||
|
*
|
||||||
|
* Note: This test functions handles both types of RTC devices:
|
||||||
|
* - devices which supports full leap years support in range 1970 - 2106.
|
||||||
|
* - devices which supports parial leap years support and incorrectly treats 2100 year as a leap year.
|
||||||
|
*
|
||||||
|
* Given is valid calendar time.
|
||||||
|
* When _rtc_maketime() is used to generate timestamp from calendar time and _rtc_localtime() is used to convert
|
||||||
|
* timestamp to calendar time.
|
||||||
|
* Then both operations gives valid results.
|
||||||
|
*/
|
||||||
|
void test_case_mktime_localtime()
|
||||||
|
{
|
||||||
|
char _key[11] =
|
||||||
|
{ };
|
||||||
|
char _value[128] =
|
||||||
|
{ };
|
||||||
|
|
||||||
|
size_t years[] = {70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
|
||||||
|
100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
||||||
|
199, 200, 201, 202, 203, 204, 205};
|
||||||
|
|
||||||
|
/* Inform host part of the test about tested RTC type. */
|
||||||
|
greentea_send_kv("leap_year_setup", rtc_leap_year_support);
|
||||||
|
|
||||||
|
/* Check the first and last last day of each month. */
|
||||||
|
for (size_t year_id = 0; year_id < (sizeof(years) /sizeof(size_t)) ; ++year_id) {
|
||||||
|
for (size_t month = 0; month < 12; ++month) {
|
||||||
|
for (size_t dayid = 0; dayid < 2; ++dayid) {
|
||||||
|
|
||||||
|
size_t year = years[year_id];
|
||||||
|
|
||||||
|
size_t day = 0;
|
||||||
|
/* Test the first and the last day of each month:
|
||||||
|
* day 0 - first,
|
||||||
|
* day 1 - last
|
||||||
|
* */
|
||||||
|
switch (dayid)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
day = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
day = 31;
|
||||||
|
|
||||||
|
if (month == 3 || month == 5 || month == 8 || month == 10) {
|
||||||
|
day = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (month == 1) {
|
||||||
|
day = 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (month == 1 && is_leap_year(year)) {
|
||||||
|
day = 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Additional conditions for RTCs with partial leap year support. */
|
||||||
|
if(month == 1 && year == 200 && rtc_leap_year_support == RTC_4_YEAR_LEAP_YEAR_SUPPORT) {
|
||||||
|
day = 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tm time_info = make_time_info(year, month, day, 23, dayid ? 59 : 0, dayid ? 59 : 0);
|
||||||
|
|
||||||
|
time_t actual_timestamp;
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(_rtc_maketime(&time_info, &actual_timestamp, rtc_leap_year_support));
|
||||||
|
|
||||||
|
greentea_send_kv("timestamp", (int) actual_timestamp);
|
||||||
|
|
||||||
|
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("passed", _key);
|
||||||
|
|
||||||
|
/* Response which indicates success contains encoded week day
|
||||||
|
* and year day needed to verify _rtc_localtime().
|
||||||
|
* Use validated timestamp to generate and validate calendar time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int buf = (unsigned int) strtol(_value, NULL, 10);
|
||||||
|
|
||||||
|
time_info.tm_wday = ((buf >> 16) & 0x0000FFFF);
|
||||||
|
time_info.tm_yday = (buf & 0x0000FFFF);
|
||||||
|
|
||||||
|
tm actual_time_info;
|
||||||
|
|
||||||
|
bool result = _rtc_localtime((time_t) actual_timestamp, &actual_time_info, rtc_leap_year_support);
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(result);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_sec, actual_time_info.tm_sec, "invalid seconds");
|
||||||
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_min, actual_time_info.tm_min, "invalid minutes");
|
||||||
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_hour, actual_time_info.tm_hour, "invalid hours");
|
||||||
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_mday, actual_time_info.tm_mday, "invalid day");
|
||||||
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_mon, actual_time_info.tm_mon, "invalid month");
|
||||||
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_year, actual_time_info.tm_year, "invalid year");
|
||||||
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_wday, actual_time_info.tm_wday, "invalid weekday");
|
||||||
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_yday, actual_time_info.tm_yday, "invalid year day");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t full_leap_year_case_setup_handler_t(const Case * const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
rtc_leap_year_support = RTC_FULL_LEAP_YEAR_SUPPORT;
|
||||||
|
|
||||||
|
return greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t partial_leap_year_case_setup_handler_t(const Case * const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
rtc_leap_year_support = RTC_4_YEAR_LEAP_YEAR_SUPPORT;
|
||||||
|
|
||||||
|
return greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t teardown_handler_t(const Case * const source, const size_t passed, const size_t failed,
|
||||||
|
const failure_t reason)
|
||||||
|
{
|
||||||
|
return greentea_case_teardown_handler(source, passed, failed, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test cases
|
||||||
|
Case cases[] ={
|
||||||
|
Case("test make time and local time - RTC leap years full support", full_leap_year_case_setup_handler_t, test_case_mktime_localtime, teardown_handler_t),
|
||||||
|
Case("test make time and local time - RTC leap years partial support", partial_leap_year_case_setup_handler_t, test_case_mktime_localtime, teardown_handler_t),
|
||||||
|
};
|
||||||
|
|
||||||
|
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(300, "rtc_calc_auto");
|
||||||
|
return greentea_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Harness::run(specification);
|
||||||
|
}
|
Loading…
Reference in New Issue