1/* $NetBSD: t_strptime.c,v 1.17 2024/03/26 21:52:23 rillig Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by David Laight. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__COPYRIGHT("@(#) Copyright (c) 2008\ 34 The NetBSD Foundation, inc. All rights reserved."); 35__RCSID("$NetBSD: t_strptime.c,v 1.17 2024/03/26 21:52:23 rillig Exp $"); 36 37#include <errno.h> 38#include <inttypes.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <time.h> 42 43#include <atf-c.h> 44 45static void 46h_pass(const char *buf, const char *fmt, int len, 47 int tm_sec, int tm_min, int tm_hour, int tm_mday, 48 int tm_mon, int tm_year, int tm_wday, int tm_yday) 49{ 50 struct tm tm = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL }; 51 const char *ret, *exp; 52 53 exp = buf + len; 54 ret = strptime(buf, fmt, &tm); 55 56 ATF_CHECK_MSG(ret == exp, 57 "strptime(\"%s\", \"%s\", tm): incorrect return code: " 58 "expected: %p, got: %p", buf, fmt, exp, ret); 59 60#define H_REQUIRE_FIELD(field) \ 61 ATF_CHECK_MSG(tm.field == field, \ 62 "strptime(\"%s\", \"%s\", tm): incorrect %s: " \ 63 "expected: %d, but got: %d", buf, fmt, \ 64 ___STRING(field), field, tm.field) 65 66 H_REQUIRE_FIELD(tm_sec); 67 H_REQUIRE_FIELD(tm_min); 68 H_REQUIRE_FIELD(tm_hour); 69 H_REQUIRE_FIELD(tm_mday); 70 H_REQUIRE_FIELD(tm_mon); 71 H_REQUIRE_FIELD(tm_year); 72 H_REQUIRE_FIELD(tm_wday); 73 H_REQUIRE_FIELD(tm_yday); 74 75#undef H_REQUIRE_FIELD 76} 77 78static void 79h_fail(const char *buf, const char *fmt) 80{ 81 struct tm tm = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL }; 82 83 ATF_CHECK_MSG(strptime(buf, fmt, &tm) == NULL, "strptime(\"%s\", " 84 "\"%s\", &tm) should fail, but it didn't", buf, fmt); 85} 86 87static struct { 88 const char *name; 89 long offs; 90} zt[] = { 91 { "Z", 0 }, 92 { "UT", 0 }, 93 { "UTC", 0 }, 94 { "GMT", 0 }, 95 { "EST", -18000 }, 96 { "EDT", -14400 }, 97 { "CST", -21600 }, 98 { "CDT", -18000 }, 99 { "MST", -25200 }, 100 { "MDT", -21600 }, 101 { "PST", -28800 }, 102 { "PDT", -25200 }, 103 104 { "VST", -1 }, 105 { "VDT", -1 }, 106 107 { "+03", 10800 }, 108 { "-03", -10800 }, 109 { "+0403", 14580 }, 110 { "-0403", -14580 }, 111 { "+04:03", 14580 }, 112 { "-04:03", -14580 }, 113 { "+14:00", 50400 }, 114 { "-14:00", -50400 }, 115 { "+23:59", 86340 }, 116 { "-23:59", -86340 }, 117 118 { "1", -1 }, 119 { "03", -1 }, 120 { "0304", -1 }, 121 { "+1", -1 }, 122 { "-203", -1 }, 123 { "+12345", -1 }, 124 { "+12:345", -1 }, 125 { "+123:45", -1 }, 126 { "+2400", -1 }, 127 { "-2400", -1 }, 128 { "+1060", -1 }, 129 { "-1060", -1 }, 130 131 { "A", 3600 }, 132 { "B", 7200 }, 133 { "C", 10800 }, 134 { "D", 14400 }, 135 { "E", 18000 }, 136 { "F", 21600 }, 137 { "G", 25200 }, 138 { "H", 28800 }, 139 { "I", 32400 }, 140 { "L", 39600 }, 141 { "M", 43200 }, 142 { "N", -3600 }, 143 { "O", -7200 }, 144 { "P", -10800 }, 145 { "Q", -14400 }, 146 { "R", -18000 }, 147 { "T", -25200 }, 148 { "U", -28800 }, 149 { "V", -32400 }, 150 { "W", -36000 }, 151 { "X", -39600 }, 152 { "Y", -43200 }, 153 154 { "J", -2 }, 155 156 { "America/Los_Angeles", -28800 }, 157 { "America/New_York", -18000 }, 158 { "EST4EDT", -14400 }, 159 160 { "Bogus", -1 }, 161}; 162 163static void 164ztest1(const char *name, const char *fmt, long value) 165{ 166 struct tm tm; 167 char *rv; 168 169 memset(&tm, 0, sizeof(tm)); 170 if ((rv = strptime(name, fmt, &tm)) == NULL) 171 tm.tm_gmtoff = -1; 172 else if (rv == name && fmt[1] == 'Z') 173 value = 0; 174 175 switch (value) { 176 case -2: 177 value = -timezone; 178 break; 179 case -1: 180 if (fmt[1] == 'Z') 181 value = 0; 182 break; 183 default: 184 break; 185 } 186 187 ATF_CHECK_MSG(tm.tm_gmtoff == value, 188 "strptime(\"%s\", \"%s\", &tm): " 189 "expected: tm.tm_gmtoff=%ld, got: tm.tm_gmtoff=%ld", 190 name, fmt, value, tm.tm_gmtoff); 191 printf("%s %s %ld\n", name, fmt, tm.tm_gmtoff); 192} 193 194static void 195ztest(const char *fmt) 196{ 197 setenv("TZ", "US/Eastern", 1); 198 ztest1("GMT", fmt, 0); 199 ztest1("UTC", fmt, 0); 200 ztest1("US/Eastern", fmt, -18000); 201 for (size_t i = 0; i < __arraycount(zt); i++) 202 ztest1(zt[i].name, fmt, zt[i].offs); 203} 204 205ATF_TC(common); 206 207ATF_TC_HEAD(common, tc) 208{ 209 210 atf_tc_set_md_var(tc, "descr", "Checks strptime(3): various checks"); 211} 212 213ATF_TC_BODY(common, tc) 214{ 215 216 h_pass("Tue Jan 20 23:27:46 1998", "%a %b %d %T %Y", 217 24, 46, 27, 23, 20, 0, 98, 2, 19); 218 h_pass("Tue Jan 20 23:27:46 1998", "%a %b %d %H:%M:%S %Y", 219 24, 46, 27, 23, 20, 0, 98, 2, 19); 220 h_pass("Tue Jan 20 23:27:46 1998", "%c", 221 24, 46, 27, 23, 20, 0, 98, 2, 19); 222 h_pass("Fri Mar 4 20:05:34 2005", "%a %b %e %H:%M:%S %Y", 223 24, 34, 5, 20, 4, 2, 105, 5, 62); 224 h_pass("5\t3 4 8pm:05:34 2005", "%w%n%m%t%d%n%k%p:%M:%S %Y", 225 21, 34, 5, 20, 4, 2, 105, 5, 62); 226 h_pass("Fri Mar 4 20:05:34 2005", "%c", 227 24, 34, 5, 20, 4, 2, 105, 5, 62); 228} 229 230ATF_TC(day); 231 232ATF_TC_HEAD(day, tc) 233{ 234 235 atf_tc_set_md_var(tc, "descr", 236 "Checks strptime(3) day name conversions [aA]"); 237} 238 239ATF_TC_BODY(day, tc) 240{ 241 242 h_pass("Sun", "%a", 3, -1, -1, -1, -1, -1, -1, 0, -1); 243 h_pass("Sunday", "%a", 6, -1, -1, -1, -1, -1, -1, 0, -1); 244 h_pass("Mon", "%a", 3, -1, -1, -1, -1, -1, -1, 1, -1); 245 h_pass("Monday", "%a", 6, -1, -1, -1, -1, -1, -1, 1, -1); 246 h_pass("Tue", "%a", 3, -1, -1, -1, -1, -1, -1, 2, -1); 247 h_pass("Tuesday", "%a", 7, -1, -1, -1, -1, -1, -1, 2, -1); 248 h_pass("Wed", "%a", 3, -1, -1, -1, -1, -1, -1, 3, -1); 249 h_pass("Wednesday", "%a", 9, -1, -1, -1, -1, -1, -1, 3, -1); 250 h_pass("Thu", "%a", 3, -1, -1, -1, -1, -1, -1, 4, -1); 251 h_pass("Thursday", "%a", 8, -1, -1, -1, -1, -1, -1, 4, -1); 252 h_pass("Fri", "%a", 3, -1, -1, -1, -1, -1, -1, 5, -1); 253 h_pass("Friday", "%a", 6, -1, -1, -1, -1, -1, -1, 5, -1); 254 h_pass("Sat", "%a", 3, -1, -1, -1, -1, -1, -1, 6, -1); 255 h_pass("Saturday", "%a", 8, -1, -1, -1, -1, -1, -1, 6, -1); 256 h_pass("Saturn", "%a", 3, -1, -1, -1, -1, -1, -1, 6, -1); 257 h_fail("Moon", "%a"); 258 h_pass("Sun", "%A", 3, -1, -1, -1, -1, -1, -1, 0, -1); 259 h_pass("Sunday", "%A", 6, -1, -1, -1, -1, -1, -1, 0, -1); 260 h_pass("Mon", "%A", 3, -1, -1, -1, -1, -1, -1, 1, -1); 261 h_pass("Monday", "%A", 6, -1, -1, -1, -1, -1, -1, 1, -1); 262 h_pass("Tue", "%A", 3, -1, -1, -1, -1, -1, -1, 2, -1); 263 h_pass("Tuesday", "%A", 7, -1, -1, -1, -1, -1, -1, 2, -1); 264 h_pass("Wed", "%A", 3, -1, -1, -1, -1, -1, -1, 3, -1); 265 h_pass("Wednesday", "%A", 9, -1, -1, -1, -1, -1, -1, 3, -1); 266 h_pass("Thu", "%A", 3, -1, -1, -1, -1, -1, -1, 4, -1); 267 h_pass("Thursday", "%A", 8, -1, -1, -1, -1, -1, -1, 4, -1); 268 h_pass("Fri", "%A", 3, -1, -1, -1, -1, -1, -1, 5, -1); 269 h_pass("Friday", "%A", 6, -1, -1, -1, -1, -1, -1, 5, -1); 270 h_pass("Sat", "%A", 3, -1, -1, -1, -1, -1, -1, 6, -1); 271 h_pass("Saturday", "%A", 8, -1, -1, -1, -1, -1, -1, 6, -1); 272 h_pass("Saturn", "%A", 3, -1, -1, -1, -1, -1, -1, 6, -1); 273 h_fail("Moon", "%A"); 274 275 h_pass("mon", "%a", 3, -1, -1, -1, -1, -1, -1, 1, -1); 276 h_pass("tueSDay", "%A", 7, -1, -1, -1, -1, -1, -1, 2, -1); 277 h_pass("sunday", "%A", 6, -1, -1, -1, -1, -1, -1, 0, -1); 278 h_fail("sunday", "%EA"); 279 h_pass("SaturDay", "%A", 8, -1, -1, -1, -1, -1, -1, 6, -1); 280 h_fail("SaturDay", "%OA"); 281} 282 283ATF_TC(hour); 284 285ATF_TC_HEAD(hour, tc) 286{ 287 288 atf_tc_set_md_var(tc, "descr", 289 "Checks strptime(3) hour conversions [IH]"); 290} 291 292ATF_TC_BODY(hour, tc) 293{ 294 295 h_fail("00", "%I"); 296 h_fail("13", "%I"); 297 298 h_pass("00", "%H", 2, -1, -1, 0, -1, -1, -1, -1, -1); 299 h_pass("12", "%H", 2, -1, -1, 12, -1, -1, -1, -1, -1); 300 h_pass("23", "%H", 2, -1, -1, 23, -1, -1, -1, -1, -1); 301 h_fail("24", "%H"); 302} 303 304 305ATF_TC(month); 306 307ATF_TC_HEAD(month, tc) 308{ 309 310 atf_tc_set_md_var(tc, "descr", 311 "Checks strptime(3) month name conversions [bB]"); 312} 313 314ATF_TC_BODY(month, tc) 315{ 316 317 h_pass("Jan", "%b", 3, -1, -1, -1, -1, 0, -1, -1, -1); 318 h_pass("January", "%b", 7, -1, -1, -1, -1, 0, -1, -1, -1); 319 h_pass("Feb", "%b", 3, -1, -1, -1, -1, 1, -1, -1, -1); 320 h_pass("February", "%b", 8, -1, -1, -1, -1, 1, -1, -1, -1); 321 h_pass("Mar", "%b", 3, -1, -1, -1, -1, 2, -1, -1, -1); 322 h_pass("March", "%b", 5, -1, -1, -1, -1, 2, -1, -1, -1); 323 h_pass("Apr", "%b", 3, -1, -1, -1, -1, 3, -1, -1, -1); 324 h_pass("April", "%b", 5, -1, -1, -1, -1, 3, -1, -1, -1); 325 h_pass("May", "%b", 3, -1, -1, -1, -1, 4, -1, -1, -1); 326 h_pass("Jun", "%b", 3, -1, -1, -1, -1, 5, -1, -1, -1); 327 h_pass("June", "%b", 4, -1, -1, -1, -1, 5, -1, -1, -1); 328 h_pass("Jul", "%b", 3, -1, -1, -1, -1, 6, -1, -1, -1); 329 h_pass("July", "%b", 4, -1, -1, -1, -1, 6, -1, -1, -1); 330 h_pass("Aug", "%b", 3, -1, -1, -1, -1, 7, -1, -1, -1); 331 h_pass("August", "%b", 6, -1, -1, -1, -1, 7, -1, -1, -1); 332 h_pass("Sep", "%b", 3, -1, -1, -1, -1, 8, -1, -1, -1); 333 h_pass("September", "%b", 9, -1, -1, -1, -1, 8, -1, -1, -1); 334 h_pass("Oct", "%b", 3, -1, -1, -1, -1, 9, -1, -1, -1); 335 h_pass("October", "%b", 7, -1, -1, -1, -1, 9, -1, -1, -1); 336 h_pass("Nov", "%b", 3, -1, -1, -1, -1, 10, -1, -1, -1); 337 h_pass("November", "%b", 8, -1, -1, -1, -1, 10, -1, -1, -1); 338 h_pass("Dec", "%b", 3, -1, -1, -1, -1, 11, -1, -1, -1); 339 h_pass("December", "%b", 8, -1, -1, -1, -1, 11, -1, -1, -1); 340 h_pass("Mayor", "%b", 3, -1, -1, -1, -1, 4, -1, -1, -1); 341 h_pass("Mars", "%b", 3, -1, -1, -1, -1, 2, -1, -1, -1); 342 h_fail("Rover", "%b"); 343 h_pass("Jan", "%B", 3, -1, -1, -1, -1, 0, -1, -1, -1); 344 h_pass("January", "%B", 7, -1, -1, -1, -1, 0, -1, -1, -1); 345 h_pass("Feb", "%B", 3, -1, -1, -1, -1, 1, -1, -1, -1); 346 h_pass("February", "%B", 8, -1, -1, -1, -1, 1, -1, -1, -1); 347 h_pass("Mar", "%B", 3, -1, -1, -1, -1, 2, -1, -1, -1); 348 h_pass("March", "%B", 5, -1, -1, -1, -1, 2, -1, -1, -1); 349 h_pass("Apr", "%B", 3, -1, -1, -1, -1, 3, -1, -1, -1); 350 h_pass("April", "%B", 5, -1, -1, -1, -1, 3, -1, -1, -1); 351 h_pass("May", "%B", 3, -1, -1, -1, -1, 4, -1, -1, -1); 352 h_pass("Jun", "%B", 3, -1, -1, -1, -1, 5, -1, -1, -1); 353 h_pass("June", "%B", 4, -1, -1, -1, -1, 5, -1, -1, -1); 354 h_pass("Jul", "%B", 3, -1, -1, -1, -1, 6, -1, -1, -1); 355 h_pass("July", "%B", 4, -1, -1, -1, -1, 6, -1, -1, -1); 356 h_pass("Aug", "%B", 3, -1, -1, -1, -1, 7, -1, -1, -1); 357 h_pass("August", "%B", 6, -1, -1, -1, -1, 7, -1, -1, -1); 358 h_pass("Sep", "%B", 3, -1, -1, -1, -1, 8, -1, -1, -1); 359 h_pass("September", "%B", 9, -1, -1, -1, -1, 8, -1, -1, -1); 360 h_pass("Oct", "%B", 3, -1, -1, -1, -1, 9, -1, -1, -1); 361 h_pass("October", "%B", 7, -1, -1, -1, -1, 9, -1, -1, -1); 362 h_pass("Nov", "%B", 3, -1, -1, -1, -1, 10, -1, -1, -1); 363 h_pass("November", "%B", 8, -1, -1, -1, -1, 10, -1, -1, -1); 364 h_pass("Dec", "%B", 3, -1, -1, -1, -1, 11, -1, -1, -1); 365 h_pass("December", "%B", 8, -1, -1, -1, -1, 11, -1, -1, -1); 366 h_pass("Mayor", "%B", 3, -1, -1, -1, -1, 4, -1, -1, -1); 367 h_pass("Mars", "%B", 3, -1, -1, -1, -1, 2, -1, -1, -1); 368 h_fail("Rover", "%B"); 369 370 h_pass("september", "%b", 9, -1, -1, -1, -1, 8, -1, -1, -1); 371 h_pass("septembe", "%B", 3, -1, -1, -1, -1, 8, -1, -1, -1); 372} 373 374ATF_TC(seconds); 375 376ATF_TC_HEAD(seconds, tc) 377{ 378 379 atf_tc_set_md_var(tc, "descr", 380 "Checks strptime(3) seconds conversions [S]"); 381} 382 383ATF_TC_BODY(seconds, tc) 384{ 385 386 h_pass("0", "%S", 1, 0, -1, -1, -1, -1, -1, -1, -1); 387 h_pass("59", "%S", 2, 59, -1, -1, -1, -1, -1, -1, -1); 388 h_pass("60", "%S", 2, 60, -1, -1, -1, -1, -1, -1, -1); 389 h_pass("61", "%S", 2, 61, -1, -1, -1, -1, -1, -1, -1); 390 h_fail("62", "%S"); 391} 392 393ATF_TC(year); 394 395ATF_TC_HEAD(year, tc) 396{ 397 398 atf_tc_set_md_var(tc, "descr", 399 "Checks strptime(3) century/year conversions [CyY]"); 400} 401 402ATF_TC_BODY(year, tc) 403{ 404 405 h_pass("x20y", "x%Cy", 4, -1, -1, -1, -1, -1, 100, -1, -1); 406 h_pass("x84y", "x%yy", 4, -1, -1, -1, -1, -1, 84, -1, -1); 407 h_pass("x2084y", "x%C%yy", 6, -1, -1, -1, -1, -1, 184, -1, -1); 408 h_pass("x8420y", "x%y%Cy", 6, -1, -1, -1, -1, -1, 184, -1, -1); 409 h_pass("%20845", "%%%C%y5", 6, -1, -1, -1, -1, -1, 184, -1, -1); 410 h_fail("%", "%E%"); 411 412 h_pass("1980", "%Y", 4, -1, -1, -1, -1, -1, 80, -1, -1); 413 h_pass("1980", "%EY", 4, -1, -1, -1, -1, -1, 80, -1, -1); 414} 415 416ATF_TC(zone); 417 418ATF_TC_HEAD(zone, tc) 419{ 420 421 atf_tc_set_md_var(tc, "descr", 422 "Checks strptime(3) timezone conversion [z]"); 423} 424 425 426ATF_TC_BODY(zone, tc) 427{ 428 ztest("%z"); 429} 430 431ATF_TC(Zone); 432 433ATF_TC_HEAD(Zone, tc) 434{ 435 436 atf_tc_set_md_var(tc, "descr", 437 "Checks strptime(3) timezone conversion [Z]"); 438} 439 440 441ATF_TC_BODY(Zone, tc) 442{ 443 ztest("%Z"); 444} 445 446ATF_TC(posixtime_overflow); 447 448ATF_TC_HEAD(posixtime_overflow, tc) 449{ 450 451 atf_tc_set_md_var(tc, "descr", 452 "Checks strptime(3) safely rejects POSIX time overflow"); 453} 454 455ATF_TC_BODY(posixtime_overflow, tc) 456{ 457 static const uint64_t P[] = { /* cases that should pass round-trip */ 458 [0] = 0, 459 [1] = 1, 460 [2] = 2, 461 [3] = 0x7ffffffe, 462 [4] = 0x7fffffff, 463 [5] = 0x80000000, 464 [6] = 0x80000001, 465 [7] = 0xfffffffe, 466 [8] = 0xffffffff, 467 [9] = 0x100000000, 468 [10] = 0x100000001, 469 [11] = 67767976233532799, /* 2147483647-12-31T23:59:59 */ 470 /* 471 * Beyond this point, the year (.tm_year + 1900) 472 * overflows the signed 32-bit range, so we won't be 473 * able to test round-trips: 474 */ 475 [12] = 67767976233532800, 476 [13] = 67767976233532801, 477 [14] = 67768036191676799, 478 /* 479 * Beyond this point, .tm_year itself overflows the 480 * signed 32-bit range, so strptime won't work at all; 481 * the output can't be represented in struct tm. 482 */ 483#if 0 484 [15] = 67768036191676800, 485 [16] = 67768036191676801, 486 [17] = 0x7ffffffffffffffe, 487 [18] = 0x7fffffffffffffff, 488#endif 489 }; 490 static const uint64_t F[] = { /* cases strptime should reject */ 491 [0] = 67768036191676800, 492 [1] = 67768036191676801, 493 [2] = 0x7ffffffffffffffe, 494 [3] = 0x7fffffffffffffff, 495 [4] = 0x8000000000000000, 496 [5] = 0x8000000000000001, 497 [6] = 0xfffffffffffffffe, 498 [7] = 0xffffffffffffffff, 499 }; 500 size_t i; 501 502 /* 503 * Verify time_t fits in uint64_t, with space to spare since 504 * it's signed. 505 */ 506 __CTASSERT(__type_max(time_t) < __type_max(uint64_t)); 507 508 /* 509 * Make sure we work in UTC so this test doesn't depend on 510 * which time zone your machine is configured for. 511 */ 512 setenv("TZ", "UTC", 1); 513 514 /* 515 * Check the should-pass cases. 516 */ 517 for (i = 0; i < __arraycount(P); i++) { 518 char buf[sizeof("18446744073709551616")]; 519 int n; 520 struct tm tm; 521 time_t t; 522 int error; 523 524 /* 525 * Format the integer in decimal. 526 */ 527 n = snprintf(buf, sizeof(buf), "%"PRIu64, P[i]); 528 ATF_CHECK_MSG(n >= 0 && (unsigned)n < sizeof(buf), 529 "P[%zu]: 64-bit requires %d digits", i, n); 530 531 /* 532 * Parse the time into components. 533 */ 534 fprintf(stderr, "# P[%zu]: %"PRId64"\n", i, P[i]); 535 if (strptime(buf, "%s", &tm) == NULL) { 536 atf_tc_fail_nonfatal("P[%zu]: strptime failed", i); 537 continue; 538 } 539 fprintf(stderr, "tm_sec=%d\n", tm.tm_sec); 540 fprintf(stderr, "tm_min=%d\n", tm.tm_min); 541 fprintf(stderr, "tm_hour=%d\n", tm.tm_hour); 542 fprintf(stderr, "tm_mday=%d\n", tm.tm_mday); 543 fprintf(stderr, "tm_mon=%d\n", tm.tm_mon); 544 fprintf(stderr, "tm_year=%d\n", tm.tm_year); 545 fprintf(stderr, "tm_wday=%d\n", tm.tm_wday); 546 fprintf(stderr, "tm_yday=%d\n", tm.tm_yday); 547 fprintf(stderr, "tm_isdst=%d\n", tm.tm_isdst); 548 fprintf(stderr, "tm_gmtoff=%ld\n", tm.tm_gmtoff); 549 fprintf(stderr, "tm_zone=%s\n", tm.tm_zone); 550 551 /* 552 * Convert back to POSIX seconds since epoch -- unless 553 * the year number overflows signed 32-bit, in which 554 * case stop here because we can't test further. 555 */ 556 if (tm.tm_year > 0x7fffffff - 1900) 557 continue; 558 t = mktime(&tm); 559 error = errno; 560 ATF_CHECK_MSG(t != -1, "P[%zu]: mktime failed: %d, %s", 561 i, error, strerror(error)); 562 563 /* 564 * Verify the round-trip. 565 */ 566 ATF_CHECK_EQ_MSG(P[i], (uint64_t)t, 567 "P[%zu]: %"PRId64" -> %"PRId64, i, P[i], (int64_t)t); 568 } 569 570 /* 571 * Check the should-fail cases. 572 */ 573 for (i = 0; i < __arraycount(F); i++) { 574 char buf[sizeof("18446744073709551616")]; 575 int n; 576 577 /* 578 * Format the integer in decimal. 579 */ 580 n = snprintf(buf, sizeof(buf), "%"PRIu64, F[i]); 581 ATF_CHECK_MSG(n >= 0 && (unsigned)n < sizeof(buf), 582 "F[%zu]: 64-bit requires %d digits", i, n); 583 584 /* 585 * Verify strptime rejects this. 586 */ 587 h_fail(buf, "%s"); 588 } 589} 590 591ATF_TP_ADD_TCS(tp) 592{ 593 594 ATF_TP_ADD_TC(tp, common); 595 ATF_TP_ADD_TC(tp, day); 596 ATF_TP_ADD_TC(tp, hour); 597 ATF_TP_ADD_TC(tp, month); 598 ATF_TP_ADD_TC(tp, seconds); 599 ATF_TP_ADD_TC(tp, year); 600 ATF_TP_ADD_TC(tp, zone); 601 ATF_TP_ADD_TC(tp, Zone); 602 ATF_TP_ADD_TC(tp, posixtime_overflow); 603 604 return atf_no_error(); 605} 606