3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2016-2017 Nest Labs, Inc.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 * This file implements a process to effect a functional test for
23 * the CHIP date and time support utilities.
32 #include <support/TimeUtils.h>
33 #include <support/UnitTestRegistration.h>
34 #include <support/logging/CHIPLogging.h>
43 void TestAssert(bool assert, const char * msg)
52 struct OrdinalDateTestValue
60 OrdinalDateTestValue StandardYearOrdinalDates[] =
430 OrdinalDateTestValue LeapYearOrdinalDates[] =
802 void TestOrdinalDateConversion()
804 for (uint16_t year = 0; year <= 10000; year++)
806 OrdinalDateTestValue * testValue = (IsLeapYear(year)) ? LeapYearOrdinalDates : StandardYearOrdinalDates;
808 for (; testValue->DayOfYear != 0; testValue++)
810 uint16_t outDayOfYear = 0;
811 uint8_t outMonth = 0, outDayOfMonth = 0;
813 OrdinalDateToCalendarDate(year, testValue->DayOfYear, outMonth, outDayOfMonth);
815 TestAssert(outMonth == testValue->Month, "OrdinalDateToCalendarDate returned invalid month");
816 TestAssert(outDayOfMonth == testValue->DayOfMonth, "OrdinalDateToCalendarDate returned invalid day-of-month");
818 CalendarDateToOrdinalDate(year, testValue->Month, testValue->DayOfMonth, outDayOfYear);
820 TestAssert(outDayOfYear == testValue->DayOfYear, "CalendarDateToOrdinalDate returned invalid day-of-year");
825 void TestDaysSinceEpochConversion()
827 uint32_t daysSinceEpoch = 0;
829 for (uint16_t year = kEpochYear; year <= kMaxYearInDaysSinceEpoch32; year++)
831 for (uint8_t month = kJanuary; month <= kDecember; month++)
833 for (uint8_t dayOfMonth = 1; dayOfMonth <= DaysInMonth(year, month); dayOfMonth++)
835 // Test CalendarDateToDaysSinceEpoch()
837 uint32_t calculatedDaysSinceEpoch;
839 CalendarDateToDaysSinceEpoch(year, month, dayOfMonth, calculatedDaysSinceEpoch);
841 if (calculatedDaysSinceEpoch != daysSinceEpoch)
842 printf("%04u/%02u/%02u %u %u\n", year, month, dayOfMonth, daysSinceEpoch, calculatedDaysSinceEpoch);
844 TestAssert(calculatedDaysSinceEpoch == daysSinceEpoch,
845 "CalendarDateToDaysSinceEpoch() returned unexpected value");
848 // Test DaysSinceEpochToCalendarDate()
850 uint16_t calculatedYear;
851 uint8_t calculatedMonth, calculatedDayOfMonth;
853 DaysSinceEpochToCalendarDate(daysSinceEpoch, calculatedYear, calculatedMonth, calculatedDayOfMonth);
855 if (calculatedYear != year || calculatedMonth != month || calculatedDayOfMonth != dayOfMonth)
856 printf("%04u/%02u/%02u %04u/%02u/%02u\n", year, month, dayOfMonth, calculatedYear, calculatedMonth,
857 calculatedDayOfMonth);
859 TestAssert(calculatedYear == year, "DaysSinceEpochToCalendarDate() returned unexpected year value");
860 TestAssert(calculatedMonth == month, "DaysSinceEpochToCalendarDate() returned unexpected month value");
861 TestAssert(calculatedDayOfMonth == dayOfMonth,
862 "DaysSinceEpochToCalendarDate() returned unexpected dayOfMonth value");
871 void TestSecondsSinceEpochConversion()
873 uint32_t daysSinceEpoch = 0;
874 uint32_t timeOfDay = 0; // in seconds
876 for (uint16_t year = kEpochYear; year <= kMaxYearInSecondsSinceEpoch32; year++)
878 for (uint8_t month = kJanuary; month <= kDecember; month++)
880 for (uint8_t dayOfMonth = 1; dayOfMonth <= DaysInMonth(year, month); dayOfMonth++)
882 // Test 10 different times of day per calendar day (this keeps the total runtime manageable).
883 for (uint8_t i = 0; i < 10; i++)
885 uint32_t secondsSinceEpoch = daysSinceEpoch * kSecondsPerDay + timeOfDay;
887 uint8_t hour = static_cast<uint8_t>(timeOfDay / kSecondsPerHour);
888 uint8_t minute = static_cast<uint8_t>((timeOfDay - (hour * kSecondsPerHour)) / kSecondsPerMinute);
889 uint8_t second = static_cast<uint8_t>(timeOfDay - (hour * kSecondsPerHour + minute * kSecondsPerMinute));
891 #define VERIFY_TEST_AGAINST_GMTTIME 0
892 #if VERIFY_TEST_AGAINST_GMTTIME
894 time_t epochTimeT = static_cast<time_t>(secondsSinceEpoch);
896 struct tm * gmt = gmtime(&epochTimeT);
898 TestAssert(year == gmt->tm_year + 1900, "gmtime() mismatch: year");
899 TestAssert(month == gmt->tm_mon + 1, "gmtime() mismatch: month");
900 TestAssert(dayOfMonth == gmt->tm_mday, "gmtime() mismatch: dayOfMonth");
901 TestAssert(hour == gmt->tm_hour, "gmtime() mismatch: hour");
902 TestAssert(minute == gmt->tm_min, "gmtime() mismatch: minute");
903 TestAssert(second == gmt->tm_sec, "gmtime() mismatch: second");
907 // Test SecondsSinceEpochToCalendarTime()
909 uint16_t calculatedYear;
910 uint8_t calculatedMonth, calculatedDayOfMonth, calculatedHour, calculatedMinute, calculatedSecond;
912 SecondsSinceEpochToCalendarTime(secondsSinceEpoch, calculatedYear, calculatedMonth, calculatedDayOfMonth,
913 calculatedHour, calculatedMinute, calculatedSecond);
915 TestAssert(calculatedYear == year, "SecondsSinceEpochToCalendarTime() returned unexpected year value");
916 TestAssert(calculatedMonth == month, "SecondsSinceEpochToCalendarTime() returned unexpected month value");
917 TestAssert(calculatedDayOfMonth == dayOfMonth,
918 "SecondsSinceEpochToCalendarTime() returned unexpected dayOfMonth value");
919 TestAssert(calculatedHour == hour, "SecondsSinceEpochToCalendarTime() returned unexpected hour value");
920 TestAssert(calculatedMinute == minute,
921 "SecondsSinceEpochToCalendarTime() returned unexpected minute value");
922 TestAssert(calculatedSecond == second,
923 "SecondsSinceEpochToCalendarTime() returned unexpected second value");
926 // Test CalendarTimeToSecondsSinceEpoch()
929 uint32_t calculatedSecondsSinceEpoch;
931 CalendarTimeToSecondsSinceEpoch(year, month, dayOfMonth, hour, minute, second, calculatedSecondsSinceEpoch);
933 TestAssert(calculatedSecondsSinceEpoch == secondsSinceEpoch,
934 "CalendarTimeToSecondsSinceEpoch() returned unexpected value");
937 // Iterate through times of day by skipping a large prime number of seconds.
938 timeOfDay = (timeOfDay + 10007) % kSecondsPerDay;
947 void TestChipEpochTimeConversion()
949 uint32_t daysSinceEpoch = 0;
950 uint32_t timeOfDay = 0; // in seconds
952 for (uint16_t year = kChipEpochBaseYear; year <= kChipEpochMaxYear; year++)
954 for (uint8_t month = kJanuary; month <= kDecember; month++)
956 for (uint8_t dayOfMonth = 1; dayOfMonth <= DaysInMonth(year, month); dayOfMonth++)
958 // Test 10 different times of day per calendar day (this keeps the total runtime manageable).
959 for (uint8_t i = 0; i < 10; i++)
961 uint32_t chipEpochTime = daysSinceEpoch * kSecondsPerDay + timeOfDay;
963 uint8_t hour = static_cast<uint8_t>(timeOfDay / kSecondsPerHour);
964 uint8_t minute = static_cast<uint8_t>((timeOfDay - (hour * kSecondsPerHour)) / kSecondsPerMinute);
965 uint8_t second = static_cast<uint8_t>(timeOfDay - (hour * kSecondsPerHour + minute * kSecondsPerMinute));
967 #if VERIFY_TEST_AGAINST_GMTTIME
969 time_t epochTimeT = static_cast<time_t>(chipEpochTime) + kChipEpochSecondsSinceUnixEpoch;
971 struct tm * gmt = gmtime(&epochTimeT);
973 TestAssert(year == gmt->tm_year + 1900, "chip epoch gmtime() mismatch: year");
974 TestAssert(month == gmt->tm_mon + 1, "chip epoch gmtime() mismatch: month");
975 TestAssert(dayOfMonth == gmt->tm_mday, "chip epoch gmtime() mismatch: dayOfMonth");
976 TestAssert(hour == gmt->tm_hour, "chip epoch gmtime() mismatch: hour");
977 TestAssert(minute == gmt->tm_min, "chip epoch gmtime() mismatch: minute");
978 TestAssert(second == gmt->tm_sec, "chip epoch gmtime() mismatch: second");
982 // Test ChipEpochToCalendarTime()
984 uint16_t calculatedYear;
985 uint8_t calculatedMonth, calculatedDayOfMonth, calculatedHour, calculatedMinute, calculatedSecond;
987 ChipEpochToCalendarTime(chipEpochTime, calculatedYear, calculatedMonth, calculatedDayOfMonth,
988 calculatedHour, calculatedMinute, calculatedSecond);
990 TestAssert(calculatedYear == year, "ChipEpochToCalendarTime() returned unexpected year value");
991 TestAssert(calculatedMonth == month, "ChipEpochToCalendarTime() returned unexpected month value");
992 TestAssert(calculatedDayOfMonth == dayOfMonth,
993 "ChipEpochToCalendarTime() returned unexpected dayOfMonth value");
994 TestAssert(calculatedHour == hour, "ChipEpochToCalendarTime() returned unexpected hour value");
995 TestAssert(calculatedMinute == minute, "ChipEpochToCalendarTime() returned unexpected minute value");
996 TestAssert(calculatedSecond == second, "ChipEpochToCalendarTime() returned unexpected second value");
999 // Test CalendarTimeToSecondsSinceEpoch()
1002 uint32_t calculatedChipEpochTime;
1004 CalendarToChipEpochTime(year, month, dayOfMonth, hour, minute, second, calculatedChipEpochTime);
1006 TestAssert(calculatedChipEpochTime == chipEpochTime,
1007 "CalendarTimeToSecondsSinceEpoch() returned unexpected value");
1010 // Iterate through times of day by skipping a large prime number of seconds.
1011 timeOfDay = (timeOfDay + 10007) % kSecondsPerDay;
1020 int TestTimeUtils(void)
1022 TestOrdinalDateConversion();
1023 TestDaysSinceEpochConversion();
1024 TestSecondsSinceEpochConversion();
1025 TestChipEpochTimeConversion();
1027 printf("All tests passed\n");
1032 CHIP_REGISTER_TEST_SUITE(TestTimeUtils);