1 /* $NetBSD: t_parsedate.c,v 1.13 2014/10/08 17:23:03 apb Exp $ */ 2 /*- 3 * Copyright (c) 2010 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.13 2014/10/08 17:23:03 apb 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("23jun2001", NULL, NULL, localtime_r, 140 2001, 6, 23, 0, 0, 0); 141 parsecheck("1-sep-06", NULL, NULL, localtime_r, 142 2006, 9, 1, 0, 0, 0); 143 parsecheck("1/11", NULL, NULL, localtime_r, 144 ANY, 1, 11, 0, 0, 0); /* month/day */ 145 parsecheck("1500-01-02", NULL, NULL, localtime_r, 146 1500, 1, 2, 0, 0, 0); 147 parsecheck("9999-12-21", NULL, NULL, localtime_r, 148 9999, 12, 21, 0, 0, 0); 149 } 150 151 ATF_TC(times); 152 153 ATF_TC_HEAD(times, tc) 154 { 155 atf_tc_set_md_var(tc, "descr", "Test times" 156 " (PR lib/44255)"); 157 } 158 159 ATF_TC_BODY(times, tc) 160 { 161 162 parsecheck("10:01", NULL, NULL, localtime_r, 163 ANY, ANY, ANY, 10, 1, 0); 164 parsecheck("10:12pm", NULL, NULL, localtime_r, 165 ANY, ANY, ANY, 22, 12, 0); 166 parsecheck("12:11:01.000012", NULL, NULL, localtime_r, 167 ANY, ANY, ANY, 12, 11, 1); 168 parsecheck("12:21-0500", NULL, NULL, gmtime_r, 169 ANY, ANY, ANY, 12+5, 21, 0); 170 } 171 172 ATF_TC(dsttimes); 173 174 ATF_TC_HEAD(dsttimes, tc) 175 { 176 atf_tc_set_md_var(tc, "descr", "Test DST transition times" 177 " (PR lib/47916)"); 178 } 179 180 ATF_TC_BODY(dsttimes, tc) 181 { 182 struct tm tm; 183 time_t t; 184 int tzoff; 185 186 putenv(__UNCONST("TZ=EST")); 187 tzset(); 188 parsecheck("12:0", NULL, NULL, localtime_r, 189 ANY, ANY, ANY, 12, 0, 0); 190 191 putenv(__UNCONST("TZ=Japan")); 192 tzset(); 193 parsecheck("12:0", NULL, NULL, localtime_r, 194 ANY, ANY, ANY, 12, 0, 0); 195 196 /* 197 * When the effective local time is Tue Jul 9 13:21:53 BST 2013, 198 * check mktime("14:00") 199 */ 200 putenv(__UNCONST("TZ=Europe/London")); 201 tzset(); 202 tm = (struct tm){ 203 .tm_year = 2013-1900, .tm_mon = 7-1, .tm_mday = 9, 204 .tm_hour = 13, .tm_min = 21, .tm_sec = 53, 205 .tm_isdst = 0 }; 206 t = mktime(&tm); 207 ATF_CHECK(t != (time_t)-1); 208 parsecheck("14:00", &t, NULL, localtime_r, 209 2013, 7, 9, 14, 0, 0); 210 tzoff = -60; /* British Summer Time */ 211 parsecheck("14:00", &t, &tzoff, localtime_r, 212 2013, 7, 9, 14, 0, 0); 213 } 214 215 ATF_TC(relative); 216 217 ATF_TC_HEAD(relative, tc) 218 { 219 atf_tc_set_md_var(tc, "descr", "Test relative items" 220 " (PR lib/44255)"); 221 } 222 223 ATF_TC_BODY(relative, tc) 224 { 225 226 ATF_CHECK(parsedate("-1 month", NULL, NULL) != -1); 227 ATF_CHECK(parsedate("last friday", NULL, NULL) != -1); 228 ATF_CHECK(parsedate("one week ago", NULL, NULL) != -1); 229 ATF_CHECK(parsedate("this thursday", NULL, NULL) != -1); 230 ATF_CHECK(parsedate("next sunday", NULL, NULL) != -1); 231 ATF_CHECK(parsedate("+2 years", NULL, NULL) != -1); 232 } 233 234 ATF_TC(atsecs); 235 236 ATF_TC_HEAD(atsecs, tc) 237 { 238 atf_tc_set_md_var(tc, "descr", "Test seconds past the epoch"); 239 } 240 241 ATF_TC_BODY(atsecs, tc) 242 { 243 int tzoff; 244 245 /* "@0" -> (time_t)0, regardless of timezone */ 246 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 247 putenv(__UNCONST("TZ=Europe/Berlin")); 248 tzset(); 249 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 250 putenv(__UNCONST("TZ=America/New_York")); 251 tzset(); 252 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 253 tzoff = 0; 254 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 255 tzoff = 3600; 256 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 257 tzoff = -3600; 258 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 259 260 /* -1 or other negative numbers are not errors */ 261 errno = 0; 262 ATF_CHECK(parsedate("@-1", NULL, &tzoff) == (time_t)-1 && errno == 0); 263 ATF_CHECK(parsedate("@-2", NULL, &tzoff) == (time_t)-2 && errno == 0); 264 265 /* junk is an error */ 266 errno = 0; 267 ATF_CHECK(parsedate("@junk", NULL, NULL) == (time_t)-1 && errno != 0); 268 } 269 270 ATF_TP_ADD_TCS(tp) 271 { 272 ATF_TP_ADD_TC(tp, dates); 273 ATF_TP_ADD_TC(tp, times); 274 ATF_TP_ADD_TC(tp, dsttimes); 275 ATF_TP_ADD_TC(tp, relative); 276 ATF_TP_ADD_TC(tp, atsecs); 277 278 return atf_no_error(); 279 } 280