Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: mbed-os/TESTS/mbed_hal/rtc_time/main.cpp
- Revision:
- 0:4beb2ea291ec
diff -r 000000000000 -r 4beb2ea291ec mbed-os/TESTS/mbed_hal/rtc_time/main.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os/TESTS/mbed_hal/rtc_time/main.cpp Mon Mar 16 13:12:31 2020 +0000
@@ -0,0 +1,260 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2017 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.
+ */
+
+#include "utest/utest.h"
+#include "unity/unity.h"
+#include "greentea-client/test_env.h"
+
+#include "mbed.h"
+#include "mbed_mktime.h"
+
+// Limit the test range to 1935 for IAR only. From the IAR C/C++ Development Guide:
+// "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;
+
+/*
+ * regular is_leap_year, see platform/mbed_mktime.c for the optimized 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;
+}
+
+/*
+ * Test the optimized version of _rtc_is_leap_year against the generic version.
+ */
+void test_is_leap_year() {
+ for (int i = 70; i < 138; ++i) {
+ bool expected = is_leap_year(i);
+ bool actual_value = _rtc_is_leap_year(i);
+
+ if (expected != actual_value) {
+ printf ("leap year failed with i = %d\r\n", i);
+ }
+ TEST_ASSERT_EQUAL(expected, actual_value);
+ }
+}
+
+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 out of range values for _rtc_mktime.
+ * The function operates from the 1st of january 1970 at 00:00:00 to the 19th
+ * of january 2038 at 03:14:07.
+ */
+void test_mk_time_out_of_range() {
+ tm invalid_lower_bound = make_time_info(
+ 69,
+ 11,
+ 31,
+ 23,
+ 59,
+ 59
+ );
+
+ tm valid_lower_bound = make_time_info(
+ 70,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0
+ );
+
+ tm valid_upper_bound = make_time_info(
+ 138,
+ 0,
+ 19,
+ 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() {
+ for (size_t year = 70; year < MKTIME_YR_MAX; ++year) {
+ for (size_t month = 0; month < 12; ++month) {
+ 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) {
+ tm time_info = make_time_info(
+ year,
+ month,
+ day,
+ hour,
+ hour % 2 ? 59 : 0,
+ hour % 2 ? 59 : 0
+ );
+
+ time_t expected = mktime(&time_info);
+ time_t actual_value = _rtc_mktime(&time_info);
+
+ char msg[128] = "";
+ if (expected != actual_value) {
+ snprintf(
+ msg, sizeof(msg),
+ "year = %d, month = %d, day = %d, diff = %ld",
+ year, month, day, expected - actual_value
+ );
+ }
+
+ TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual_value, msg);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * test value out of range for localtime
+ */
+void test_local_time_limit() {
+ struct tm dummy_value;
+ TEST_ASSERT_FALSE(_rtc_localtime((time_t) -1, &dummy_value));
+ TEST_ASSERT_FALSE(_rtc_localtime((time_t) INT_MIN, &dummy_value));
+}
+
+/*
+ * test _rtc_localtime over a large set of values.
+ */
+void test_local_time() {
+ for (uint32_t i = 0; i < LOCALTIME_MAX; i += 3451) {
+ time_t copy = (time_t) i;
+ struct tm* expected = localtime(©);
+ 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) {
+ greentea_case_failure_abort_handler(source, reason);
+ return STATUS_CONTINUE;
+}
+
+Case cases[] = {
+ Case("test is leap year", test_is_leap_year, greentea_failure_handler),
+ Case("test mk time out of range values", test_mk_time_out_of_range, greentea_failure_handler),
+ Case("mk time", test_mk_time, greentea_failure_handler),
+ Case("test local time", test_local_time, greentea_failure_handler),
+ Case("test local time limits", test_local_time_limit, greentea_failure_handler),
+};
+
+utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
+ GREENTEA_SETUP(1200, "default_auto");
+ return greentea_test_setup_handler(number_of_cases);
+}
+
+Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
+
+int main() {
+ return Harness::run(specification);
+}