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 <limits.h> 17 18 using __llvm_libc::testing::ErrnoSetterMatcher::Fails; 19 using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; 20 using __llvm_libc::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(__llvm_libc::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(__llvm_libc::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(__llvm_libc::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(__llvm_libc::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(__llvm_libc::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(__llvm_libc::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(__llvm_libc::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(__llvm_libc::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(size_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(__llvm_libc::mktime(&tm_data), 191 Succeeds(TimeConstants::OUT_OF_RANGE_RETURN_VALUE)); 192 } 193 194 { 195 // 2038-01-19 03:15:07 tests overflow of the minute in 2038. 196 struct tm tm_data { 197 .tm_sec = 7, .tm_min = 15, .tm_hour = 3, .tm_mday = 19, 198 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 199 .tm_yday = 0 200 }; 201 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 202 Succeeds(TimeConstants::OUT_OF_RANGE_RETURN_VALUE)); 203 } 204 205 { 206 // 2038-01-19 04:14:07 tests overflow of the hour in 2038. 207 struct tm tm_data { 208 .tm_sec = 7, .tm_min = 14, .tm_hour = 4, .tm_mday = 19, 209 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 210 .tm_yday = 0 211 }; 212 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 213 Succeeds(TimeConstants::OUT_OF_RANGE_RETURN_VALUE)); 214 } 215 216 { 217 // 2038-01-20 03:14:07 tests overflow of the day in 2038. 218 struct tm tm_data { 219 .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 20, 220 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 221 .tm_yday = 0 222 }; 223 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 224 Succeeds(TimeConstants::OUT_OF_RANGE_RETURN_VALUE)); 225 } 226 227 { 228 // 2038-02-19 03:14:07 tests overflow of the month in 2038. 229 struct tm tm_data { 230 .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, 231 .tm_mon = Month::FEBRUARY, .tm_year = tm_year(2038), .tm_wday = 0, 232 .tm_yday = 0 233 }; 234 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 235 Succeeds(TimeConstants::OUT_OF_RANGE_RETURN_VALUE)); 236 } 237 238 { 239 // 2039-01-19 03:14:07 tests overflow of the year. 240 struct tm tm_data { 241 .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, 242 .tm_mon = Month::JANUARY, .tm_year = tm_year(2039), .tm_wday = 0, 243 .tm_yday = 0 244 }; 245 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 246 Succeeds(TimeConstants::OUT_OF_RANGE_RETURN_VALUE)); 247 } 248 } 249 250 TEST(LlvmLibcMkTime, InvalidMonths) { 251 { 252 // -1 month from 1970-01-01 00:00:00 returns 1969-12-01 00:00:00. 253 struct tm tm_data { 254 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 0, .tm_mon = -1, 255 .tm_year = tm_year(1970), .tm_wday = 0, .tm_yday = 0 256 }; 257 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 258 Succeeds(-32 * TimeConstants::SECONDS_PER_DAY)); 259 EXPECT_TM_EQ((tm{.tm_sec = 0, 260 .tm_min = 0, 261 .tm_hour = 0, 262 .tm_mday = 1, 263 .tm_mon = Month::DECEMBER, 264 .tm_year = tm_year(1969), 265 .tm_wday = 1, 266 .tm_yday = 0}), 267 tm_data); 268 } 269 270 { 271 // 1970-13-01 00:00:00 returns 1971-01-01 00:00:00. 272 struct tm tm_data { 273 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, .tm_mon = 12, 274 .tm_year = tm_year(1970), .tm_wday = 0, .tm_yday = 0 275 }; 276 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 277 Succeeds(TimeConstants::DAYS_PER_NON_LEAP_YEAR * 278 TimeConstants::SECONDS_PER_DAY)); 279 EXPECT_TM_EQ((tm{.tm_sec = 0, 280 .tm_min = 0, 281 .tm_hour = 0, 282 .tm_mday = 1, 283 .tm_mon = Month::JANUARY, 284 .tm_year = tm_year(1971), 285 .tm_wday = 5, 286 .tm_yday = 0}), 287 tm_data); 288 } 289 } 290 291 TEST(LlvmLibcMkTime, InvalidDays) { 292 { 293 // -1 day from 1970-01-01 00:00:00 returns 1969-12-31 00:00:00. 294 struct tm tm_data { 295 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = (1 - 1), 296 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 297 .tm_yday = 0 298 }; 299 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 300 Succeeds(-1 * TimeConstants::SECONDS_PER_DAY)); 301 EXPECT_TM_EQ((tm{.tm_sec = 0, 302 .tm_min = 0, 303 .tm_hour = 0, 304 .tm_mday = 31, 305 .tm_mon = Month::DECEMBER, 306 .tm_year = tm_year(1969), 307 .tm_wday = 3, 308 .tm_yday = 0}), 309 tm_data); 310 } 311 312 { 313 // 1970-01-32 00:00:00 returns 1970-02-01 00:00:00. 314 struct tm tm_data { 315 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 32, 316 .tm_mon = Month::JANUARY, .tm_year = tm_year(1970), .tm_wday = 0, 317 .tm_yday = 0 318 }; 319 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 320 Succeeds(31 * TimeConstants::SECONDS_PER_DAY)); 321 EXPECT_TM_EQ((tm{.tm_sec = 0, 322 .tm_min = 0, 323 .tm_hour = 0, 324 .tm_mday = 1, 325 .tm_mon = Month::FEBRUARY, 326 .tm_year = tm_year(1970), 327 .tm_wday = 0, 328 .tm_yday = 0}), 329 tm_data); 330 } 331 332 { 333 // 1970-02-29 00:00:00 returns 1970-03-01 00:00:00. 334 struct tm tm_data { 335 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 29, 336 .tm_mon = Month::FEBRUARY, .tm_year = tm_year(1970), .tm_wday = 0, 337 .tm_yday = 0 338 }; 339 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 340 Succeeds(59 * TimeConstants::SECONDS_PER_DAY)); 341 EXPECT_TM_EQ((tm{.tm_sec = 0, 342 .tm_min = 0, 343 .tm_hour = 0, 344 .tm_mday = 1, 345 .tm_mon = Month::MARCH, 346 .tm_year = tm_year(1970), 347 .tm_wday = 0, 348 .tm_yday = 0}), 349 tm_data); 350 } 351 352 { 353 // 1972-02-30 00:00:00 returns 1972-03-01 00:00:00. 354 struct tm tm_data { 355 .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 30, 356 .tm_mon = Month::FEBRUARY, .tm_year = tm_year(1972), .tm_wday = 0, 357 .tm_yday = 0 358 }; 359 EXPECT_THAT(__llvm_libc::mktime(&tm_data), 360 Succeeds(((2 * TimeConstants::DAYS_PER_NON_LEAP_YEAR) + 60) * 361 TimeConstants::SECONDS_PER_DAY)); 362 EXPECT_TM_EQ((tm{.tm_sec = 0, 363 .tm_min = 0, 364 .tm_hour = 0, 365 .tm_mday = 1, 366 .tm_mon = Month::MARCH, 367 .tm_year = tm_year(1972), 368 .tm_wday = 3, 369 .tm_yday = 0}), 370 tm_data); 371 } 372 } 373 374 TEST(LlvmLibcMkTime, EndOf32BitEpochYear) { 375 // Test for maximum value of a signed 32-bit integer. 376 // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC. 377 struct tm tm_data { 378 .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, 379 .tm_mon = Month::JANUARY, .tm_year = tm_year(2038), .tm_wday = 0, 380 .tm_yday = 0 381 }; 382 EXPECT_THAT(__llvm_libc::mktime(&tm_data), Succeeds(0x7FFFFFFF)); 383 EXPECT_TM_EQ((tm{.tm_sec = 7, 384 .tm_min = 14, 385 .tm_hour = 3, 386 .tm_mday = 19, 387 .tm_mon = Month::JANUARY, 388 .tm_year = tm_year(2038), 389 .tm_wday = 2, 390 .tm_yday = 7}), 391 tm_data); 392 } 393 394 TEST(LlvmLibcMkTime, Max64BitYear) { 395 if (sizeof(time_t) == 4) 396 return; 397 { 398 // Mon Jan 1 12:50:50 2170 (200 years from 1970), 399 struct tm tm_data { 400 .tm_sec = 50, .tm_min = 50, .tm_hour = 12, .tm_mday = 1, 401 .tm_mon = Month::JANUARY, .tm_year = tm_year(2170), .tm_wday = 0, 402 .tm_yday = 0 403 }; 404 EXPECT_THAT(__llvm_libc::mktime(&tm_data), Succeeds(6311479850)); 405 EXPECT_TM_EQ((tm{.tm_sec = 50, 406 .tm_min = 50, 407 .tm_hour = 12, 408 .tm_mday = 1, 409 .tm_mon = Month::JANUARY, 410 .tm_year = tm_year(2170), 411 .tm_wday = 1, 412 .tm_yday = 50}), 413 tm_data); 414 } 415 416 { 417 // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year. 418 struct tm tm_data { 419 .tm_sec = 50, .tm_min = 50, .tm_hour = 12, .tm_mday = 1, 420 .tm_mon = Month::JANUARY, .tm_year = tm_year(2147483647), .tm_wday = 0, 421 .tm_yday = 0 422 }; 423 EXPECT_THAT(__llvm_libc::mktime(&tm_data), Succeeds(67767976202043050)); 424 EXPECT_TM_EQ((tm{.tm_sec = 50, 425 .tm_min = 50, 426 .tm_hour = 12, 427 .tm_mday = 1, 428 .tm_mon = Month::JANUARY, 429 .tm_year = tm_year(2147483647), 430 .tm_wday = 2, 431 .tm_yday = 50}), 432 tm_data); 433 } 434 } 435