127601055SCassio Neri // SPDX-License-Identifier: LGPL-2.1+
227601055SCassio Neri
327601055SCassio Neri #include <kunit/test.h>
427601055SCassio Neri #include <linux/time.h>
527601055SCassio Neri
627601055SCassio Neri /*
727601055SCassio Neri * Traditional implementation of leap year evaluation.
827601055SCassio Neri */
is_leap(long year)927601055SCassio Neri static bool is_leap(long year)
1027601055SCassio Neri {
1127601055SCassio Neri return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
1227601055SCassio Neri }
1327601055SCassio Neri
1427601055SCassio Neri /*
1527601055SCassio Neri * Gets the last day of a month.
1627601055SCassio Neri */
last_day_of_month(long year,int month)1727601055SCassio Neri static int last_day_of_month(long year, int month)
1827601055SCassio Neri {
1927601055SCassio Neri if (month == 2)
2027601055SCassio Neri return 28 + is_leap(year);
2127601055SCassio Neri if (month == 4 || month == 6 || month == 9 || month == 11)
2227601055SCassio Neri return 30;
2327601055SCassio Neri return 31;
2427601055SCassio Neri }
2527601055SCassio Neri
2627601055SCassio Neri /*
2727601055SCassio Neri * Advances a date by one day.
2827601055SCassio Neri */
advance_date(long * year,int * month,int * mday,int * yday)2927601055SCassio Neri static void advance_date(long *year, int *month, int *mday, int *yday)
3027601055SCassio Neri {
3127601055SCassio Neri if (*mday != last_day_of_month(*year, *month)) {
3227601055SCassio Neri ++*mday;
3327601055SCassio Neri ++*yday;
3427601055SCassio Neri return;
3527601055SCassio Neri }
3627601055SCassio Neri
3727601055SCassio Neri *mday = 1;
3827601055SCassio Neri if (*month != 12) {
3927601055SCassio Neri ++*month;
4027601055SCassio Neri ++*yday;
4127601055SCassio Neri return;
4227601055SCassio Neri }
4327601055SCassio Neri
4427601055SCassio Neri *month = 1;
4527601055SCassio Neri *yday = 0;
4627601055SCassio Neri ++*year;
4727601055SCassio Neri }
4827601055SCassio Neri
4927601055SCassio Neri /*
5027601055SCassio Neri * Checks every day in a 160000 years interval centered at 1970-01-01
5127601055SCassio Neri * against the expected result.
5227601055SCassio Neri */
time64_to_tm_test_date_range(struct kunit * test)5327601055SCassio Neri static void time64_to_tm_test_date_range(struct kunit *test)
5427601055SCassio Neri {
5527601055SCassio Neri /*
5627601055SCassio Neri * 80000 years = (80000 / 400) * 400 years
5727601055SCassio Neri * = (80000 / 400) * 146097 days
5827601055SCassio Neri * = (80000 / 400) * 146097 * 86400 seconds
5927601055SCassio Neri */
6027601055SCassio Neri time64_t total_secs = ((time64_t) 80000) / 400 * 146097 * 86400;
6127601055SCassio Neri long year = 1970 - 80000;
6227601055SCassio Neri int month = 1;
6327601055SCassio Neri int mdday = 1;
6427601055SCassio Neri int yday = 0;
6527601055SCassio Neri
6627601055SCassio Neri struct tm result;
6727601055SCassio Neri time64_t secs;
6827601055SCassio Neri s64 days;
6927601055SCassio Neri
7027601055SCassio Neri for (secs = -total_secs; secs <= total_secs; secs += 86400) {
7127601055SCassio Neri
7227601055SCassio Neri time64_to_tm(secs, 0, &result);
7327601055SCassio Neri
7427601055SCassio Neri days = div_s64(secs, 86400);
7527601055SCassio Neri
76133e267eSDavid Gow #define FAIL_MSG "%05ld/%02d/%02d (%2d) : %lld", \
7727601055SCassio Neri year, month, mdday, yday, days
7827601055SCassio Neri
7927601055SCassio Neri KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG);
8027601055SCassio Neri KUNIT_ASSERT_EQ_MSG(test, month - 1, result.tm_mon, FAIL_MSG);
8127601055SCassio Neri KUNIT_ASSERT_EQ_MSG(test, mdday, result.tm_mday, FAIL_MSG);
8227601055SCassio Neri KUNIT_ASSERT_EQ_MSG(test, yday, result.tm_yday, FAIL_MSG);
8327601055SCassio Neri
8427601055SCassio Neri advance_date(&year, &month, &mdday, &yday);
8527601055SCassio Neri }
8627601055SCassio Neri }
8727601055SCassio Neri
8827601055SCassio Neri static struct kunit_case time_test_cases[] = {
89a547c4ceSRae Moar KUNIT_CASE_SLOW(time64_to_tm_test_date_range),
9027601055SCassio Neri {}
9127601055SCassio Neri };
9227601055SCassio Neri
9327601055SCassio Neri static struct kunit_suite time_test_suite = {
9427601055SCassio Neri .name = "time_test_cases",
9527601055SCassio Neri .test_cases = time_test_cases,
9627601055SCassio Neri };
9727601055SCassio Neri
9827601055SCassio Neri kunit_test_suite(time_test_suite);
99*7cbf3b13SJeff Johnson MODULE_DESCRIPTION("time unit test suite");
1002d0a9eb2SThomas Gleixner MODULE_LICENSE("GPL");
101