Nicolas Borla / Mbed OS ROME2_Robot_Firmware
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(&copy);
+        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);
+}