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