1 //===-- Unittests for mktime ----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/time/mktime.h"
10 #include "test/ErrnoSetterMatcher.h"
11 #include "utils/UnitTest/Test.h"
12 
13 #include <errno.h>
14 #include <string.h>
15 
16 using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
17 
18 static constexpr time_t OutOfRangeReturnValue = -1;
19 
20 // A helper function to initialize tm data structure.
initialize_tm_data(struct tm * tm_data,int year,int month,int mday,int hour,int min,int sec)21 static inline void initialize_tm_data(struct tm *tm_data, int year, int month,
22                                       int mday, int hour, int min, int sec) {
23   struct tm temp = {.tm_sec = sec,
24                     .tm_min = min,
25                     .tm_hour = hour,
26                     .tm_mday = mday,
27                     .tm_mon = month,
28                     .tm_year = year - 1900};
29   *tm_data = temp;
30 }
31 
call_mktime(struct tm * tm_data,int year,int month,int mday,int hour,int min,int sec)32 static inline time_t call_mktime(struct tm *tm_data, int year, int month,
33                                  int mday, int hour, int min, int sec) {
34   initialize_tm_data(tm_data, year, month, mday, hour, min, sec);
35   return __llvm_libc::mktime(tm_data);
36 }
37 
TEST(MkTime,FailureSetsErrno)38 TEST(MkTime, FailureSetsErrno) {
39   struct tm tm_data;
40   initialize_tm_data(&tm_data, 0, 0, 0, 0, 0, -1);
41   EXPECT_THAT(__llvm_libc::mktime(&tm_data), Fails(EOVERFLOW));
42 }
43 
TEST(MkTime,MktimeTestsInvalidSeconds)44 TEST(MkTime, MktimeTestsInvalidSeconds) {
45   struct tm tm_data;
46   EXPECT_EQ(call_mktime(&tm_data, 0, 0, 0, 0, 0, -1), OutOfRangeReturnValue);
47   EXPECT_EQ(call_mktime(&tm_data, 0, 0, 0, 0, 0, 60), OutOfRangeReturnValue);
48 }
49 
TEST(MkTime,MktimeTestsInvalidMinutes)50 TEST(MkTime, MktimeTestsInvalidMinutes) {
51   struct tm tm_data;
52   EXPECT_EQ(call_mktime(&tm_data, 0, 0, 0, 0, -1, 0), OutOfRangeReturnValue);
53   EXPECT_EQ(call_mktime(&tm_data, 0, 0, 1, 0, 60, 0), OutOfRangeReturnValue);
54 }
55 
TEST(MkTime,MktimeTestsInvalidHours)56 TEST(MkTime, MktimeTestsInvalidHours) {
57   struct tm tm_data;
58   EXPECT_EQ(call_mktime(&tm_data, 0, 0, 0, -1, 0, 0), OutOfRangeReturnValue);
59   EXPECT_EQ(call_mktime(&tm_data, 0, 0, 0, 24, 0, 0), OutOfRangeReturnValue);
60 }
61 
TEST(MkTime,MktimeTestsInvalidYear)62 TEST(MkTime, MktimeTestsInvalidYear) {
63   struct tm tm_data;
64   EXPECT_EQ(call_mktime(&tm_data, 1969, 0, 0, 0, 0, 0), OutOfRangeReturnValue);
65 }
66 
TEST(MkTime,MktimeTestsInvalidEndOf32BitEpochYear)67 TEST(MkTime, MktimeTestsInvalidEndOf32BitEpochYear) {
68   if (sizeof(time_t) != 4)
69     return;
70   struct tm tm_data;
71   // 2038-01-19 03:14:08 tests overflow of the second in 2038.
72   EXPECT_EQ(call_mktime(&tm_data, 2038, 0, 19, 3, 14, 8),
73             OutOfRangeReturnValue);
74   // 2038-01-19 03:15:07 tests overflow of the minute in 2038.
75   EXPECT_EQ(call_mktime(&tm_data, 2038, 0, 19, 3, 15, 7),
76             OutOfRangeReturnValue);
77   // 2038-01-19 04:14:07 tests overflow of the hour in 2038.
78   EXPECT_EQ(call_mktime(&tm_data, 2038, 0, 19, 4, 14, 7),
79             OutOfRangeReturnValue);
80   // 2038-01-20 03:14:07 tests overflow of the day in 2038.
81   EXPECT_EQ(call_mktime(&tm_data, 2038, 0, 20, 3, 14, 7),
82             OutOfRangeReturnValue);
83   // 2038-02-19 03:14:07 tests overflow of the month in 2038.
84   EXPECT_EQ(call_mktime(&tm_data, 2038, 1, 19, 3, 14, 7),
85             OutOfRangeReturnValue);
86   // 2039-01-19 03:14:07 tests overflow of the year.
87   EXPECT_EQ(call_mktime(&tm_data, 2039, 0, 19, 3, 14, 7),
88             OutOfRangeReturnValue);
89 }
90 
TEST(MkTime,MktimeTestsInvalidMonths)91 TEST(MkTime, MktimeTestsInvalidMonths) {
92   struct tm tm_data;
93   // Before Jan of 1970
94   EXPECT_EQ(call_mktime(&tm_data, 1970, -1, 15, 0, 0, 0),
95             OutOfRangeReturnValue);
96   // After Dec of 1970
97   EXPECT_EQ(call_mktime(&tm_data, 1970, 12, 15, 0, 0, 0),
98             OutOfRangeReturnValue);
99 }
100 
TEST(MkTime,MktimeTestsInvalidDays)101 TEST(MkTime, MktimeTestsInvalidDays) {
102   struct tm tm_data;
103   // -1 day of Jan, 1970
104   EXPECT_EQ(call_mktime(&tm_data, 1970, 0, -1, 0, 0, 0), OutOfRangeReturnValue);
105   // 32 day of Jan, 1970
106   EXPECT_EQ(call_mktime(&tm_data, 1970, 0, 32, 0, 0, 0), OutOfRangeReturnValue);
107   // 29 day of Feb, 1970
108   EXPECT_EQ(call_mktime(&tm_data, 1970, 1, 29, 0, 0, 0), OutOfRangeReturnValue);
109   // 30 day of Feb, 1972
110   EXPECT_EQ(call_mktime(&tm_data, 1972, 1, 30, 0, 0, 0), OutOfRangeReturnValue);
111   // 31 day of Apr, 1970
112   EXPECT_EQ(call_mktime(&tm_data, 1970, 3, 31, 0, 0, 0), OutOfRangeReturnValue);
113 }
114 
TEST(MkTime,MktimeTestsStartEpochYear)115 TEST(MkTime, MktimeTestsStartEpochYear) {
116   // Thu Jan 1 00:00:00 1970
117   struct tm tm_data;
118   EXPECT_EQ(call_mktime(&tm_data, 1970, 0, 1, 0, 0, 0), static_cast<time_t>(0));
119   EXPECT_EQ(4, tm_data.tm_wday);
120   EXPECT_EQ(0, tm_data.tm_yday);
121 }
122 
TEST(MkTime,MktimeTestsEpochYearRandomTime)123 TEST(MkTime, MktimeTestsEpochYearRandomTime) {
124   // Thu Jan 1 12:50:50 1970
125   struct tm tm_data;
126   EXPECT_EQ(call_mktime(&tm_data, 1970, 0, 1, 12, 50, 50),
127             static_cast<time_t>(46250));
128   EXPECT_EQ(4, tm_data.tm_wday);
129   EXPECT_EQ(0, tm_data.tm_yday);
130 }
131 
TEST(MkTime,MktimeTestsEndOf32BitEpochYear)132 TEST(MkTime, MktimeTestsEndOf32BitEpochYear) {
133   struct tm tm_data;
134   // Test for maximum value of a signed 32-bit integer.
135   // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC.
136   EXPECT_EQ(call_mktime(&tm_data, 2038, 0, 19, 3, 14, 7),
137             static_cast<time_t>(0x7FFFFFFF));
138   EXPECT_EQ(2, tm_data.tm_wday);
139   EXPECT_EQ(18, tm_data.tm_yday);
140 }
141 
TEST(MkTime,MktimeTests64BitYear)142 TEST(MkTime, MktimeTests64BitYear) {
143   if (sizeof(time_t) == 4)
144     return;
145   // Mon Jan 1 12:50:50 2170
146   struct tm tm_data;
147   EXPECT_EQ(call_mktime(&tm_data, 2170, 0, 1, 12, 50, 50),
148             static_cast<time_t>(6311479850));
149   EXPECT_EQ(1, tm_data.tm_wday);
150   EXPECT_EQ(0, tm_data.tm_yday);
151 
152   // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year.
153   EXPECT_EQ(call_mktime(&tm_data, 2147483647, 0, 1, 12, 50, 50),
154             static_cast<time_t>(67767976202043050));
155   EXPECT_EQ(2, tm_data.tm_wday);
156   EXPECT_EQ(0, tm_data.tm_yday);
157 }
158