1 /* $NetBSD: t_parsedate.c,v 1.16 2015/12/08 12:41:28 christos Exp $ */ 2 /*- 3 * Copyright (c) 2010, 2015 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: t_parsedate.c,v 1.16 2015/12/08 12:41:28 christos Exp $"); 33 34 #include <atf-c.h> 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <time.h> 39 #include <util.h> 40 41 /* 42 * ANY is used as a placeholder for values that do not need to be 43 * checked. The actual value is arbitrary. We don't use -1 44 * because some tests might want to use -1 as a literal value. 45 */ 46 #define ANY -30215 47 48 /* parsecheck -- 49 * call parsedate(), then call time_to_tm() on the result, 50 * and check that year/month/day/hour/minute/second are as expected. 51 * 52 * time_to_tm should usually be localtime_r or gmtime_r. 53 * 54 * Don't check values specified as ANY. 55 */ 56 static void 57 parsecheck(const char *datestr, const time_t *reftime, const int *zoff, 58 struct tm * time_to_tm(const time_t *, struct tm *), 59 int year, int month, int day, int hour, int minute, int second) 60 { 61 time_t t; 62 struct tm tm; 63 char argstr[128]; 64 65 /* 66 * printable version of the args. 67 * 68 * Note that printf("%.*d", 0, 0)) prints nothing at all, 69 * while printf("%.*d", 1, val) prints the value as usual. 70 */ 71 snprintf(argstr, sizeof(argstr), "%s%s%s, %s%.*jd, %s%.*d", 72 /* NULL or \"<datestr>\" */ 73 (datestr ? "\"" : ""), 74 (datestr ? datestr : "NULL"), 75 (datestr ? "\"" : ""), 76 /* NULL or *reftime */ 77 (reftime ? "" : "NULL"), 78 (reftime ? 1 : 0), 79 (reftime ? (intmax_t)*reftime : (intmax_t)0), 80 /* NULL or *zoff */ 81 (zoff ? "" : "NULL"), 82 (zoff ? 1 : 0), 83 (zoff ? *zoff : 0)); 84 85 ATF_CHECK_MSG((t = parsedate(datestr, reftime, zoff)) != -1, 86 "parsedate(%s) returned -1\n", argstr); 87 ATF_CHECK(time_to_tm(&t, &tm) != NULL); 88 if (year != ANY) 89 ATF_CHECK_MSG(tm.tm_year + 1900 == year, 90 "parsedate(%s) expected year %d got %d (+1900)\n", 91 argstr, year, (int)tm.tm_year); 92 if (month != ANY) 93 ATF_CHECK_MSG(tm.tm_mon + 1 == month, 94 "parsedate(%s) expected month %d got %d (+1)\n", 95 argstr, month, (int)tm.tm_mon); 96 if (day != ANY) 97 ATF_CHECK_MSG(tm.tm_mday == day, 98 "parsedate(%s) expected day %d got %d\n", 99 argstr, day, (int)tm.tm_mday); 100 if (hour != ANY) 101 ATF_CHECK_MSG(tm.tm_hour == hour, 102 "parsedate(%s) expected hour %d got %d\n", 103 argstr, hour, (int)tm.tm_hour); 104 if (minute != ANY) 105 ATF_CHECK_MSG(tm.tm_min == minute, 106 "parsedate(%s) expected minute %d got %d\n", 107 argstr, minute, (int)tm.tm_min); 108 if (second != ANY) 109 ATF_CHECK_MSG(tm.tm_sec == second, 110 "parsedate(%s) expected second %d got %d\n", 111 argstr, second, (int)tm.tm_sec); 112 } 113 114 ATF_TC(dates); 115 116 ATF_TC_HEAD(dates, tc) 117 { 118 atf_tc_set_md_var(tc, "descr", "Test unambiguous dates" 119 " (PR lib/44255)"); 120 } 121 122 ATF_TC_BODY(dates, tc) 123 { 124 125 parsecheck("9/10/69", NULL, NULL, localtime_r, 126 2069, 9, 10, 0, 0, 0); /* year < 70: add 2000 */ 127 parsecheck("9/10/70", NULL, NULL, localtime_r, 128 1970, 9, 10, 0, 0, 0); /* 70 <= year < 100: add 1900 */ 129 parsecheck("69-09-10", NULL, NULL, localtime_r, 130 69, 9, 10, 0, 0, 0); /* ISO8601 year remains unchanged */ 131 parsecheck("70-09-10", NULL, NULL, localtime_r, 132 70, 9, 10, 0, 0, 0); /* ISO8601 year remains unchanged */ 133 parsecheck("2006-11-17", NULL, NULL, localtime_r, 134 2006, 11, 17, 0, 0, 0); 135 parsecheck("10/1/2000", NULL, NULL, localtime_r, 136 2000, 10, 1, 0, 0, 0); /* month/day/year */ 137 parsecheck("20 Jun 1994", NULL, NULL, localtime_r, 138 1994, 6, 20, 0, 0, 0); 139 parsecheck("97 September 2", NULL, NULL, localtime_r, 140 1997, 9, 2, 0, 0, 0); 141 parsecheck("23jun2001", NULL, NULL, localtime_r, 142 2001, 6, 23, 0, 0, 0); 143 parsecheck("1-sep-06", NULL, NULL, localtime_r, 144 2006, 9, 1, 0, 0, 0); 145 parsecheck("1/11", NULL, NULL, localtime_r, 146 ANY, 1, 11, 0, 0, 0); /* month/day */ 147 parsecheck("1500-01-02", NULL, NULL, localtime_r, 148 1500, 1, 2, 0, 0, 0); 149 parsecheck("9999-12-21", NULL, NULL, localtime_r, 150 9999, 12, 21, 0, 0, 0); 151 parsecheck("2015.12.07.08.07.35", NULL, NULL, localtime_r, 152 2015, 12, 7, 8, 7, 35); 153 } 154 155 ATF_TC(times); 156 157 ATF_TC_HEAD(times, tc) 158 { 159 atf_tc_set_md_var(tc, "descr", "Test times" 160 " (PR lib/44255)"); 161 } 162 163 ATF_TC_BODY(times, tc) 164 { 165 166 parsecheck("10:01", NULL, NULL, localtime_r, 167 ANY, ANY, ANY, 10, 1, 0); 168 parsecheck("10:12pm", NULL, NULL, localtime_r, 169 ANY, ANY, ANY, 22, 12, 0); 170 parsecheck("12:11:01.000012", NULL, NULL, localtime_r, 171 ANY, ANY, ANY, 12, 11, 1); 172 parsecheck("12:21-0500", NULL, NULL, gmtime_r, 173 ANY, ANY, ANY, 12+5, 21, 0); 174 /* numeric zones not permitted with am/pm ... */ 175 parsecheck("7 a.m. ICT", NULL, NULL, gmtime_r, 176 ANY, ANY, ANY, 7-7, 0, 0); 177 parsecheck("midnight", NULL, NULL, localtime_r, 178 ANY, ANY, ANY, 0, 0, 0); 179 parsecheck("mn", NULL, NULL, localtime_r, 180 ANY, ANY, ANY, 0, 0, 0); 181 parsecheck("noon", NULL, NULL, localtime_r, 182 ANY, ANY, ANY, 12, 0, 0); 183 parsecheck("dawn", NULL, NULL, localtime_r, 184 ANY, ANY, ANY, 6, 0, 0); 185 parsecheck("sunset", NULL, NULL, localtime_r, 186 ANY, ANY, ANY, 18, 0, 0); 187 } 188 189 ATF_TC(dsttimes); 190 191 ATF_TC_HEAD(dsttimes, tc) 192 { 193 atf_tc_set_md_var(tc, "descr", "Test DST transition times" 194 " (PR lib/47916)"); 195 } 196 197 ATF_TC_BODY(dsttimes, tc) 198 { 199 struct tm tm; 200 time_t t; 201 int tzoff; 202 203 putenv(__UNCONST("TZ=EST")); 204 tzset(); 205 parsecheck("12:0", NULL, NULL, localtime_r, 206 ANY, ANY, ANY, 12, 0, 0); 207 208 putenv(__UNCONST("TZ=Asia/Tokyo")); 209 tzset(); 210 parsecheck("12:0", NULL, NULL, localtime_r, 211 ANY, ANY, ANY, 12, 0, 0); 212 213 /* 214 * When the effective local time is Tue Jul 9 13:21:53 BST 2013, 215 * check mktime("14:00") 216 */ 217 putenv(__UNCONST("TZ=Europe/London")); 218 tzset(); 219 tm = (struct tm){ 220 .tm_year = 2013-1900, .tm_mon = 7-1, .tm_mday = 9, 221 .tm_hour = 13, .tm_min = 21, .tm_sec = 53, 222 .tm_isdst = 0 }; 223 t = mktime(&tm); 224 ATF_CHECK(t != (time_t)-1); 225 parsecheck("14:00", &t, NULL, localtime_r, 226 2013, 7, 9, 14, 0, 0); 227 tzoff = -60; /* British Summer Time */ 228 parsecheck("14:00", &t, &tzoff, localtime_r, 229 2013, 7, 9, 14, 0, 0); 230 } 231 232 ATF_TC(relative); 233 234 ATF_TC_HEAD(relative, tc) 235 { 236 atf_tc_set_md_var(tc, "descr", "Test relative items" 237 " (PR lib/44255)"); 238 } 239 240 ATF_TC_BODY(relative, tc) 241 { 242 struct tm tm; 243 time_t now; 244 245 #define REL_CHECK(s, now, tm) do { \ 246 time_t p, q; \ 247 char pb[30], qb[30]; \ 248 ATF_CHECK_EQ_MSG((p = parsedate(s, &now, NULL)), \ 249 (q = mktime(&tm)), \ 250 "From %s Expected %jd: %24.24s Obtained %jd: %24.24s", s, \ 251 (uintmax_t)p, ctime_r(&p, pb), (uintmax_t)q, \ 252 ctime_r(&q, qb)); \ 253 } while (/*CONSTCOND*/0) 254 255 ATF_CHECK(parsedate("-1 month", NULL, NULL) != -1); 256 ATF_CHECK(parsedate("last friday", NULL, NULL) != -1); 257 ATF_CHECK(parsedate("one week ago", NULL, NULL) != -1); 258 ATF_CHECK(parsedate("this thursday", NULL, NULL) != -1); 259 ATF_CHECK(parsedate("next sunday", NULL, NULL) != -1); 260 ATF_CHECK(parsedate("+2 years", NULL, NULL) != -1); 261 262 (void)time(&now); 263 264 ATF_CHECK(localtime_r(&now, &tm) != NULL); 265 tm.tm_mday--; 266 /* "yesterday" leaves time untouched */ 267 tm.tm_isdst = -1; 268 REL_CHECK("yesterday", now, tm); 269 270 ATF_CHECK(localtime_r(&now, &tm) != NULL); 271 tm.tm_mday++; 272 /* as does "tomorrow" */ 273 tm.tm_isdst = -1; 274 REL_CHECK("tomorrow", now, tm); 275 276 ATF_CHECK(localtime_r(&now, &tm) != NULL); 277 if (tm.tm_wday > 4) 278 tm.tm_mday += 7; 279 tm.tm_mday += 4 - tm.tm_wday; 280 /* if a day name is mentioned, it means midnight (by default) */ 281 tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 282 tm.tm_isdst = -1; 283 REL_CHECK("this thursday", now, tm); 284 285 ATF_CHECK(localtime_r(&now, &tm) != NULL); 286 tm.tm_mday += 14 - tm.tm_wday; 287 tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 288 tm.tm_isdst = -1; 289 REL_CHECK("next sunday", now, tm); 290 291 ATF_CHECK(localtime_r(&now, &tm) != NULL); 292 if (tm.tm_wday <= 5) 293 tm.tm_mday -= 7; 294 tm.tm_mday += 5 - tm.tm_wday; 295 tm.tm_sec = tm.tm_min = 0; 296 tm.tm_hour = 16; 297 tm.tm_isdst = -1; 298 REL_CHECK("last friday 4 p.m.", now, tm); 299 300 ATF_CHECK(localtime_r(&now, &tm) != NULL); 301 tm.tm_mday += 14; 302 if (tm.tm_wday > 3) 303 tm.tm_mday += 7; 304 tm.tm_mday += 3 - tm.tm_wday; 305 tm.tm_sec = tm.tm_min = 0; 306 tm.tm_hour = 3; 307 tm.tm_isdst = -1; 308 REL_CHECK("we fortnight 3 a.m.", now, tm); 309 310 ATF_CHECK(localtime_r(&now, &tm) != NULL); 311 tm.tm_min -= 5; 312 tm.tm_isdst = -1; 313 REL_CHECK("5 minutes ago", now, tm); 314 315 ATF_CHECK(localtime_r(&now, &tm) != NULL); 316 tm.tm_hour++; 317 tm.tm_min += 37; 318 tm.tm_isdst = -1; 319 REL_CHECK("97 minutes", now, tm); 320 321 ATF_CHECK(localtime_r(&now, &tm) != NULL); 322 tm.tm_mon++; 323 tm.tm_isdst = -1; 324 REL_CHECK("month", now, tm); 325 326 ATF_CHECK(localtime_r(&now, &tm) != NULL); 327 tm.tm_mon += 2; /* "next" means add 2 ... */ 328 tm.tm_isdst = -1; 329 REL_CHECK("next month", now, tm); 330 331 ATF_CHECK(localtime_r(&now, &tm) != NULL); 332 tm.tm_mon--; 333 tm.tm_isdst = -1; 334 REL_CHECK("last month", now, tm); 335 336 ATF_CHECK(localtime_r(&now, &tm) != NULL); 337 tm.tm_mon += 6; 338 tm.tm_mday += 2; 339 tm.tm_isdst = -1; 340 REL_CHECK("+6 months 2 days", now, tm); 341 342 ATF_CHECK(localtime_r(&now, &tm) != NULL); 343 tm.tm_mon -= 9; 344 tm.tm_isdst = -1; 345 REL_CHECK("9 months ago", now, tm); 346 347 ATF_CHECK(localtime_r(&now, &tm) != NULL); 348 if (tm.tm_wday <= 2) 349 tm.tm_mday -= 7; 350 tm.tm_mday += 2 - tm.tm_wday; 351 tm.tm_isdst = -1; 352 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 353 REL_CHECK("1 week ago Tu", now, tm); 354 355 ATF_CHECK(localtime_r(&now, &tm) != NULL); 356 tm.tm_isdst = -1; 357 tm.tm_mday++; 358 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 359 REL_CHECK("midnight tomorrow", now, tm); 360 361 ATF_CHECK(localtime_r(&now, &tm) != NULL); 362 tm.tm_isdst = -1; 363 tm.tm_mday++; 364 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 365 REL_CHECK("tomorrow midnight", now, tm); 366 367 ATF_CHECK(localtime_r(&now, &tm) != NULL); 368 tm.tm_isdst = -1; 369 tm.tm_mday++; 370 tm.tm_hour = 12; 371 tm.tm_min = tm.tm_sec = 0; 372 REL_CHECK("noon tomorrow", now, tm); 373 374 ATF_CHECK(localtime_r(&now, &tm) != NULL); 375 if (tm.tm_wday > 2) 376 tm.tm_mday += 7; 377 tm.tm_mday += 2 - tm.tm_wday; 378 tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 379 tm.tm_isdst = -1; 380 REL_CHECK("midnight Tuesday", now, tm); 381 382 ATF_CHECK(localtime_r(&now, &tm) != NULL); 383 if (tm.tm_wday > 2) 384 tm.tm_mday += 7; 385 tm.tm_mday += 2 - tm.tm_wday; 386 tm.tm_mday++; /* xxx midnight --> the next day */ 387 tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 388 tm.tm_isdst = -1; 389 REL_CHECK("Tuesday midnight", now, tm); 390 } 391 392 ATF_TC(atsecs); 393 394 ATF_TC_HEAD(atsecs, tc) 395 { 396 atf_tc_set_md_var(tc, "descr", "Test seconds past the epoch"); 397 } 398 399 ATF_TC_BODY(atsecs, tc) 400 { 401 int tzoff; 402 403 /* "@0" -> (time_t)0, regardless of timezone */ 404 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 405 putenv(__UNCONST("TZ=Europe/Berlin")); 406 tzset(); 407 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 408 putenv(__UNCONST("TZ=America/New_York")); 409 tzset(); 410 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 411 tzoff = 0; 412 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 413 tzoff = 3600; 414 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 415 tzoff = -3600; 416 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 417 418 /* -1 or other negative numbers are not errors */ 419 errno = 0; 420 ATF_CHECK(parsedate("@-1", NULL, &tzoff) == (time_t)-1 && errno == 0); 421 ATF_CHECK(parsedate("@-2", NULL, &tzoff) == (time_t)-2 && errno == 0); 422 423 /* junk is an error */ 424 errno = 0; 425 ATF_CHECK(parsedate("@junk", NULL, NULL) == (time_t)-1 && errno != 0); 426 } 427 428 ATF_TC(zones); 429 430 ATF_TC_HEAD(zones, tc) 431 { 432 atf_tc_set_md_var(tc, "descr", "Test parsing dates with zones"); 433 } 434 435 ATF_TC_BODY(zones, tc) 436 { 437 parsecheck("2015-12-06 16:11:48 UTC", NULL, NULL, gmtime_r, 438 2015, 12, 6, 16, 11, 48); 439 parsecheck("2015-12-06 16:11:48 UT", NULL, NULL, gmtime_r, 440 2015, 12, 6, 16, 11, 48); 441 parsecheck("2015-12-06 16:11:48 GMT", NULL, NULL, gmtime_r, 442 2015, 12, 6, 16, 11, 48); 443 parsecheck("2015-12-06 16:11:48 +0000", NULL, NULL, gmtime_r, 444 2015, 12, 6, 16, 11, 48); 445 446 parsecheck("2015-12-06 16:11:48 -0500", NULL, NULL, gmtime_r, 447 2015, 12, 6, 21, 11, 48); 448 parsecheck("2015-12-06 16:11:48 EST", NULL, NULL, gmtime_r, 449 2015, 12, 6, 21, 11, 48); 450 parsecheck("2015-12-06 16:11:48 EDT", NULL, NULL, gmtime_r, 451 2015, 12, 6, 20, 11, 48); 452 parsecheck("2015-12-06 16:11:48 +0500", NULL, NULL, gmtime_r, 453 2015, 12, 6, 11, 11, 48); 454 455 parsecheck("2015-12-06 16:11:48 +1000", NULL, NULL, gmtime_r, 456 2015, 12, 6, 6, 11, 48); 457 parsecheck("2015-12-06 16:11:48 AEST", NULL, NULL, gmtime_r, 458 2015, 12, 6, 6, 11, 48); 459 parsecheck("2015-12-06 16:11:48 -1000", NULL, NULL, gmtime_r, 460 2015, 12, 7, 2, 11, 48); 461 parsecheck("2015-12-06 16:11:48 HST", NULL, NULL, gmtime_r, 462 2015, 12, 7, 2, 11, 48); 463 464 parsecheck("2015-12-06 16:11:48 AWST", NULL, NULL, gmtime_r, 465 2015, 12, 6, 8, 11, 48); 466 parsecheck("2015-12-06 16:11:48 NZDT", NULL, NULL, gmtime_r, 467 2015, 12, 6, 3, 11, 48); 468 469 parsecheck("Sun, 6 Dec 2015 09:43:16 -0500", NULL, NULL, gmtime_r, 470 2015, 12, 6, 14, 43, 16); 471 parsecheck("Mon Dec 7 03:13:31 ICT 2015", NULL, NULL, gmtime_r, 472 2015, 12, 6, 20, 13, 31); 473 /* the day name is ignored when a day of month (etc) is given... */ 474 parsecheck("Sat Dec 7 03:13:31 ICT 2015", NULL, NULL, gmtime_r, 475 2015, 12, 6, 20, 13, 31); 476 477 478 parsecheck("2015-12-06 12:00:00 IDLW", NULL, NULL, gmtime_r, 479 2015, 12, 7, 0, 0, 0); 480 parsecheck("2015-12-06 12:00:00 IDLE", NULL, NULL, gmtime_r, 481 2015, 12, 6, 0, 0, 0); 482 483 parsecheck("2015-12-06 21:17:33 NFT", NULL, NULL, gmtime_r, 484 2015, 12, 7, 0, 47, 33); 485 parsecheck("2015-12-06 21:17:33 ACST", NULL, NULL, gmtime_r, 486 2015, 12, 6, 11, 47, 33); 487 parsecheck("2015-12-06 21:17:33 +0717", NULL, NULL, gmtime_r, 488 2015, 12, 6, 14, 0, 33); 489 490 parsecheck("2015-12-06 21:21:21 Z", NULL, NULL, gmtime_r, 491 2015, 12, 6, 21, 21, 21); 492 parsecheck("2015-12-06 21:21:21 A", NULL, NULL, gmtime_r, 493 2015, 12, 6, 22, 21, 21); 494 parsecheck("2015-12-06 21:21:21 G", NULL, NULL, gmtime_r, 495 2015, 12, 7, 4, 21, 21); 496 parsecheck("2015-12-06 21:21:21 M", NULL, NULL, gmtime_r, 497 2015, 12, 7, 9, 21, 21); 498 parsecheck("2015-12-06 21:21:21 N", NULL, NULL, gmtime_r, 499 2015, 12, 6, 20, 21, 21); 500 parsecheck("2015-12-06 21:21:21 T", NULL, NULL, gmtime_r, 501 2015, 12, 6, 14, 21, 21); 502 parsecheck("2015-12-06 21:21:21 Y", NULL, NULL, gmtime_r, 503 2015, 12, 6, 9, 21, 21); 504 505 } 506 507 ATF_TC(gibberish); 508 509 ATF_TC_HEAD(gibberish, tc) 510 { 511 atf_tc_set_md_var(tc, "descr", "Test (not) parsing nonsense"); 512 } 513 514 ATF_TC_BODY(gibberish, tc) 515 { 516 errno = 0; 517 ATF_CHECK(parsedate("invalid nonsense", NULL, NULL) == (time_t)-1 518 && errno != 0); 519 errno = 0; 520 ATF_CHECK(parsedate("12th day of Christmas", NULL, NULL) == (time_t)-1 521 && errno != 0); 522 errno = 0; 523 ATF_CHECK(parsedate("2015-31-07 15:00", NULL, NULL) == (time_t)-1 524 && errno != 0); 525 errno = 0; 526 ATF_CHECK(parsedate("2015-02-29 10:01", NULL, NULL) == (time_t)-1 527 && errno != 0); 528 errno = 0; 529 ATF_CHECK(parsedate("2015-12-06 24:01", NULL, NULL) == (time_t)-1 530 && errno != 0); 531 errno = 0; 532 ATF_CHECK(parsedate("2015-12-06 14:61", NULL, NULL) == (time_t)-1 533 && errno != 0); 534 } 535 536 ATF_TP_ADD_TCS(tp) 537 { 538 ATF_TP_ADD_TC(tp, dates); 539 ATF_TP_ADD_TC(tp, times); 540 ATF_TP_ADD_TC(tp, dsttimes); 541 ATF_TP_ADD_TC(tp, relative); 542 ATF_TP_ADD_TC(tp, atsecs); 543 ATF_TP_ADD_TC(tp, zones); 544 ATF_TP_ADD_TC(tp, gibberish); 545 546 return atf_no_error(); 547 } 548 549