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 "src/time/time_utils.h" 11 #include "test/UnitTest/ErrnoSetterMatcher.h" 12 #include "test/UnitTest/Test.h" 13 #include "test/src/time/TmHelper.h" 14 #include "test/src/time/TmMatcher.h" 15 16 #include <limits.h> 17 18 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; 19 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; 20 using LIBC_NAMESPACE::time_utils::Month; 21 22 static inline constexpr int tm_year(int year) { 23 return year - TimeConstants::TIME_YEAR_BASE; 24 } 25 26 TEST(LlvmLibcMkTime, FailureSetsErrno) { 27 struct tm tm_data { 28 .tm_sec = INT_MAX, .tm_min = INT_MAX, .tm_hour = INT_MAX, 29 .tm_mday = INT_MAX, .tm_mon = INT_MAX - 1, .tm_year = tm_year(INT_MAX), 30 .tm_wday = 0, .tm_yday = 0 31 }; 32 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); 33 } 34 35 TEST(LlvmLibcMkTime, InvalidSeconds) { 36 { 37 // -1 second from 1970-01-01 00:00:00 returns 1969-12-31 23:59:59. 38 struct tm tm_data { 39 .tm_sec = -1, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, 40 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 41 .tm_yday = 0 42 }; 43 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(-1)); 44 EXPECT_TM_EQ((tm{.tm_sec = 59, 45 .tm_min = 59, 46 .tm_hour = 23, 47 .tm_mday = 31, 48 .tm_mon = Month::DECEMBER, 49 .tm_year = tm_year(1969), 50 .tm_wday = 3, 51 .tm_yday = 364}), 52 tm_data); 53 } 54 55 { 56 // 60 seconds from 1970-01-01 00:00:00 returns 1970-01-01 00:01:00. 57 struct tm tm_data { 58 .tm_sec = 60, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, 59 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 60 .tm_yday = 0 61 }; 62 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(60)); 63 EXPECT_TM_EQ((tm{.tm_sec = 0, 64 .tm_min = 1, 65 .tm_hour = 0, 66 .tm_mday = 1, 67 .tm_mon = Month::JANUARY, 68 .tm_year = tm_year(1970), 69 .tm_wday = 4, 70 .tm_yday = 0}), 71 tm_data); 72 } 73 } 74 75 TEST(LlvmLibcMkTime, InvalidMinutes) { 76 { 77 // -1 minute from 1970-01-01 00:00:00 returns 1969-12-31 23:59:00. 78 struct tm tm_data { 79 .tm_sec = 0, .tm_min = -1, .tm_hour = 0, .tm_mday = 1, 80 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 81 .tm_yday = 0 82 }; 83 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 84 Succeeds(-TimeConstants::SECONDS_PER_MIN)); 85 EXPECT_TM_EQ((tm{.tm_sec = 0, 86 .tm_min = 59, 87 .tm_hour = 23, 88 .tm_mday = 31, 89 .tm_mon = Month::DECEMBER, 90 .tm_year = tm_year(1969), 91 .tm_wday = 3, 92 .tm_yday = 0}), 93 tm_data); 94 } 95 96 { 97 // 60 minutes from 1970-01-01 00:00:00 returns 1970-01-01 01:00:00. 98 struct tm tm_data { 99 .tm_sec = 0, .tm_min = 60, .tm_hour = 0, .tm_mday = 1, 100 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 101 .tm_yday = 0 102 }; 103 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 104 Succeeds(60 * TimeConstants::SECONDS_PER_MIN)); 105 EXPECT_TM_EQ((tm{.tm_sec = 0, 106 .tm_min = 0, 107 .tm_hour = 1, 108 .tm_mday = 1, 109 .tm_mon = Month::JANUARY, 110 .tm_year = tm_year(1970), 111 .tm_wday = 4, 112 .tm_yday = 0}), 113 tm_data); 114 } 115 } 116 117 TEST(LlvmLibcMkTime, InvalidHours) { 118 { 119 // -1 hour from 1970-01-01 00:00:00 returns 1969-12-31 23:00:00. 120 struct tm tm_data { 121 .tm_sec = 0, .tm_min = 0, .tm_hour = -1, .tm_mday = 1, 122 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 123 .tm_yday = 0 124 }; 125 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 126 Succeeds(-TimeConstants::SECONDS_PER_HOUR)); 127 EXPECT_TM_EQ((tm{.tm_sec = 0, 128 .tm_min = 0, 129 .tm_hour = 23, 130 .tm_mday = 31, 131 .tm_mon = Month::DECEMBER, 132 .tm_year = tm_year(1969), 133 .tm_wday = 3, 134 .tm_yday = 0}), 135 tm_data); 136 } 137 138 { 139 // 24 hours from 1970-01-01 00:00:00 returns 1970-01-02 00:00:00. 140 struct tm tm_data { 141 .tm_sec = 0, .tm_min = 0, .tm_hour = 24, .tm_mday = 1, 142 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 143 .tm_yday = 0 144 }; 145 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 146 Succeeds(24 * TimeConstants::SECONDS_PER_HOUR)); 147 EXPECT_TM_EQ((tm{.tm_sec = 0, 148 .tm_min = 0, 149 .tm_hour = 0, 150 .tm_mday = 2, 151 .tm_mon = Month::JANUARY, 152 .tm_year = tm_year(1970), 153 .tm_wday = 5, 154 .tm_yday = 0}), 155 tm_data); 156 } 157 } 158 159 TEST(LlvmLibcMkTime, InvalidYear) { 160 // -1 year from 1970-01-01 00:00:00 returns 1969-01-01 00:00:00. 161 struct tm tm_data { 162 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, 163 .tm_mon = Month::JANUARY, .tm_year = tm_year(1969), .tm_wday = 0, 164 .tm_yday = 0 165 }; 166 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 167 Succeeds(-TimeConstants::DAYS_PER_NON_LEAP_YEAR * 168 TimeConstants::SECONDS_PER_DAY)); 169 EXPECT_TM_EQ((tm{.tm_sec = 0, 170 .tm_min = 0, 171 .tm_hour = 0, 172 .tm_mday = 1, 173 .tm_mon = Month::JANUARY, 174 .tm_year = tm_year(1969), 175 .tm_wday = 3, 176 .tm_yday = 0}), 177 tm_data); 178 } 179 180 TEST(LlvmLibcMkTime, InvalidEndOf32BitEpochYear) { 181 if (sizeof(time_t) != 4) 182 return; 183 { 184 // 2038-01-19 03:14:08 tests overflow of the second in 2038. 185 struct tm tm_data { 186 .tm_sec = 8, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, 187 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 188 .tm_yday = 0 189 }; 190 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); 191 } 192 193 { 194 // 2038-01-19 03:15:07 tests overflow of the minute in 2038. 195 struct tm tm_data { 196 .tm_sec = 7, .tm_min = 15, .tm_hour = 3, .tm_mday = 19, 197 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 198 .tm_yday = 0 199 }; 200 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); 201 } 202 203 { 204 // 2038-01-19 04:14:07 tests overflow of the hour in 2038. 205 struct tm tm_data { 206 .tm_sec = 7, .tm_min = 14, .tm_hour = 4, .tm_mday = 19, 207 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 208 .tm_yday = 0 209 }; 210 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); 211 } 212 213 { 214 // 2038-01-20 03:14:07 tests overflow of the day in 2038. 215 struct tm tm_data { 216 .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 20, 217 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 218 .tm_yday = 0 219 }; 220 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); 221 } 222 223 { 224 // 2038-02-19 03:14:07 tests overflow of the month in 2038. 225 struct tm tm_data { 226 .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, 227 .tm_mon = Month::FEBRUARY, .tm_year = tm_year(2038), .tm_wday = 0, 228 .tm_yday = 0 229 }; 230 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); 231 } 232 233 { 234 // 2039-01-19 03:14:07 tests overflow of the year. 235 struct tm tm_data { 236 .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, 237 .tm_mon = Month::JANUARY, .tm_year = tm_year(2039), .tm_wday = 0, 238 .tm_yday = 0 239 }; 240 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); 241 } 242 } 243 244 TEST(LlvmLibcMkTime, InvalidMonths) { 245 { 246 // -1 month from 1970-01-01 00:00:00 returns 1969-12-01 00:00:00. 247 struct tm tm_data { 248 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 0, .tm_mon = -1, 249 .tm_year = tm_year(1970), .tm_wday = 0, .tm_yday = 0 250 }; 251 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 252 Succeeds(-32 * TimeConstants::SECONDS_PER_DAY)); 253 EXPECT_TM_EQ((tm{.tm_sec = 0, 254 .tm_min = 0, 255 .tm_hour = 0, 256 .tm_mday = 1, 257 .tm_mon = Month::DECEMBER, 258 .tm_year = tm_year(1969), 259 .tm_wday = 1, 260 .tm_yday = 0}), 261 tm_data); 262 } 263 264 { 265 // 1970-13-01 00:00:00 returns 1971-01-01 00:00:00. 266 struct tm tm_data { 267 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, .tm_mon = 12, 268 .tm_year = tm_year(1970), .tm_wday = 0, .tm_yday = 0 269 }; 270 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 271 Succeeds(TimeConstants::DAYS_PER_NON_LEAP_YEAR * 272 TimeConstants::SECONDS_PER_DAY)); 273 EXPECT_TM_EQ((tm{.tm_sec = 0, 274 .tm_min = 0, 275 .tm_hour = 0, 276 .tm_mday = 1, 277 .tm_mon = Month::JANUARY, 278 .tm_year = tm_year(1971), 279 .tm_wday = 5, 280 .tm_yday = 0}), 281 tm_data); 282 } 283 } 284 285 TEST(LlvmLibcMkTime, InvalidDays) { 286 { 287 // -1 day from 1970-01-01 00:00:00 returns 1969-12-31 00:00:00. 288 struct tm tm_data { 289 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = (1 - 1), 290 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 291 .tm_yday = 0 292 }; 293 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 294 Succeeds(-1 * TimeConstants::SECONDS_PER_DAY)); 295 EXPECT_TM_EQ((tm{.tm_sec = 0, 296 .tm_min = 0, 297 .tm_hour = 0, 298 .tm_mday = 31, 299 .tm_mon = Month::DECEMBER, 300 .tm_year = tm_year(1969), 301 .tm_wday = 3, 302 .tm_yday = 0}), 303 tm_data); 304 } 305 306 { 307 // 1970-01-32 00:00:00 returns 1970-02-01 00:00:00. 308 struct tm tm_data { 309 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 32, 310 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 311 .tm_yday = 0 312 }; 313 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 314 Succeeds(31 * TimeConstants::SECONDS_PER_DAY)); 315 EXPECT_TM_EQ((tm{.tm_sec = 0, 316 .tm_min = 0, 317 .tm_hour = 0, 318 .tm_mday = 1, 319 .tm_mon = Month::FEBRUARY, 320 .tm_year = tm_year(1970), 321 .tm_wday = 0, 322 .tm_yday = 0}), 323 tm_data); 324 } 325 326 { 327 // 1970-02-29 00:00:00 returns 1970-03-01 00:00:00. 328 struct tm tm_data { 329 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 29, 330 .tm_mon = Month::FEBRUARY, .tm_year = tm_year(1970), .tm_wday = 0, 331 .tm_yday = 0 332 }; 333 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 334 Succeeds(59 * TimeConstants::SECONDS_PER_DAY)); 335 EXPECT_TM_EQ((tm{.tm_sec = 0, 336 .tm_min = 0, 337 .tm_hour = 0, 338 .tm_mday = 1, 339 .tm_mon = Month::MARCH, 340 .tm_year = tm_year(1970), 341 .tm_wday = 0, 342 .tm_yday = 0}), 343 tm_data); 344 } 345 346 { 347 // 1972-02-30 00:00:00 returns 1972-03-01 00:00:00. 348 struct tm tm_data { 349 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 30, 350 .tm_mon = Month::FEBRUARY, .tm_year = tm_year(1972), .tm_wday = 0, 351 .tm_yday = 0 352 }; 353 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), 354 Succeeds(((2 * TimeConstants::DAYS_PER_NON_LEAP_YEAR) + 60) * 355 TimeConstants::SECONDS_PER_DAY)); 356 EXPECT_TM_EQ((tm{.tm_sec = 0, 357 .tm_min = 0, 358 .tm_hour = 0, 359 .tm_mday = 1, 360 .tm_mon = Month::MARCH, 361 .tm_year = tm_year(1972), 362 .tm_wday = 3, 363 .tm_yday = 0}), 364 tm_data); 365 } 366 } 367 368 TEST(LlvmLibcMkTime, EndOf32BitEpochYear) { 369 // Test for maximum value of a signed 32-bit integer. 370 // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC. 371 struct tm tm_data { 372 .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, 373 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 374 .tm_yday = 0 375 }; 376 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(0x7FFFFFFF)); 377 EXPECT_TM_EQ((tm{.tm_sec = 7, 378 .tm_min = 14, 379 .tm_hour = 3, 380 .tm_mday = 19, 381 .tm_mon = Month::JANUARY, 382 .tm_year = tm_year(2038), 383 .tm_wday = 2, 384 .tm_yday = 7}), 385 tm_data); 386 } 387 388 TEST(LlvmLibcMkTime, Max64BitYear) { 389 if (sizeof(time_t) == 4) 390 return; 391 { 392 // Mon Jan 1 12:50:50 2170 (200 years from 1970), 393 struct tm tm_data { 394 .tm_sec = 50, .tm_min = 50, .tm_hour = 12, .tm_mday = 1, 395 .tm_mon = Month::JANUARY, .tm_year = tm_year(2170), .tm_wday = 0, 396 .tm_yday = 0 397 }; 398 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(6311479850)); 399 EXPECT_TM_EQ((tm{.tm_sec = 50, 400 .tm_min = 50, 401 .tm_hour = 12, 402 .tm_mday = 1, 403 .tm_mon = Month::JANUARY, 404 .tm_year = tm_year(2170), 405 .tm_wday = 1, 406 .tm_yday = 50}), 407 tm_data); 408 } 409 410 { 411 // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year. 412 struct tm tm_data { 413 .tm_sec = 50, .tm_min = 50, .tm_hour = 12, .tm_mday = 1, 414 .tm_mon = Month::JANUARY, .tm_year = tm_year(2147483647), .tm_wday = 0, 415 .tm_yday = 0 416 }; 417 EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(67767976202043050)); 418 EXPECT_TM_EQ((tm{.tm_sec = 50, 419 .tm_min = 50, 420 .tm_hour = 12, 421 .tm_mday = 1, 422 .tm_mon = Month::JANUARY, 423 .tm_year = tm_year(2147483647), 424 .tm_wday = 2, 425 .tm_yday = 50}), 426 tm_data); 427 } 428 } 429