1*e6155eabSrillig /* $NetBSD: t_strptime.c,v 1.17 2024/03/26 21:52:23 rillig Exp $ */
2004608e4Spgoyette
3004608e4Spgoyette /*-
4004608e4Spgoyette * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
5004608e4Spgoyette * All rights reserved.
6004608e4Spgoyette *
7004608e4Spgoyette * This code is derived from software contributed to The NetBSD Foundation
8004608e4Spgoyette * by David Laight.
9004608e4Spgoyette *
10004608e4Spgoyette * Redistribution and use in source and binary forms, with or without
11004608e4Spgoyette * modification, are permitted provided that the following conditions
12004608e4Spgoyette * are met:
13004608e4Spgoyette * 1. Redistributions of source code must retain the above copyright
14004608e4Spgoyette * notice, this list of conditions and the following disclaimer.
15004608e4Spgoyette * 2. Redistributions in binary form must reproduce the above copyright
16004608e4Spgoyette * notice, this list of conditions and the following disclaimer in the
17004608e4Spgoyette * documentation and/or other materials provided with the distribution.
18004608e4Spgoyette *
19004608e4Spgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20004608e4Spgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21004608e4Spgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22004608e4Spgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23004608e4Spgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24004608e4Spgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25004608e4Spgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26004608e4Spgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27004608e4Spgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28004608e4Spgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29004608e4Spgoyette * POSSIBILITY OF SUCH DAMAGE.
30004608e4Spgoyette */
31004608e4Spgoyette
32004608e4Spgoyette #include <sys/cdefs.h>
33004608e4Spgoyette __COPYRIGHT("@(#) Copyright (c) 2008\
34004608e4Spgoyette The NetBSD Foundation, inc. All rights reserved.");
35*e6155eabSrillig __RCSID("$NetBSD: t_strptime.c,v 1.17 2024/03/26 21:52:23 rillig Exp $");
36004608e4Spgoyette
37086a7f84Sriastradh #include <errno.h>
38086a7f84Sriastradh #include <inttypes.h>
393112bb3eSchristos #include <stdio.h>
40086a7f84Sriastradh #include <stdlib.h>
41086a7f84Sriastradh #include <time.h>
42004608e4Spgoyette
43004608e4Spgoyette #include <atf-c.h>
44004608e4Spgoyette
45004608e4Spgoyette static void
h_pass(const char * buf,const char * fmt,int len,int tm_sec,int tm_min,int tm_hour,int tm_mday,int tm_mon,int tm_year,int tm_wday,int tm_yday)46004608e4Spgoyette h_pass(const char *buf, const char *fmt, int len,
47004608e4Spgoyette int tm_sec, int tm_min, int tm_hour, int tm_mday,
48004608e4Spgoyette int tm_mon, int tm_year, int tm_wday, int tm_yday)
49004608e4Spgoyette {
50004608e4Spgoyette struct tm tm = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL };
51004608e4Spgoyette const char *ret, *exp;
52004608e4Spgoyette
53004608e4Spgoyette exp = buf + len;
54004608e4Spgoyette ret = strptime(buf, fmt, &tm);
55004608e4Spgoyette
560161d869Smaya ATF_CHECK_MSG(ret == exp,
57004608e4Spgoyette "strptime(\"%s\", \"%s\", tm): incorrect return code: "
58004608e4Spgoyette "expected: %p, got: %p", buf, fmt, exp, ret);
59004608e4Spgoyette
60004608e4Spgoyette #define H_REQUIRE_FIELD(field) \
610161d869Smaya ATF_CHECK_MSG(tm.field == field, \
62004608e4Spgoyette "strptime(\"%s\", \"%s\", tm): incorrect %s: " \
63004608e4Spgoyette "expected: %d, but got: %d", buf, fmt, \
64004608e4Spgoyette ___STRING(field), field, tm.field)
65004608e4Spgoyette
66004608e4Spgoyette H_REQUIRE_FIELD(tm_sec);
67004608e4Spgoyette H_REQUIRE_FIELD(tm_min);
68004608e4Spgoyette H_REQUIRE_FIELD(tm_hour);
69004608e4Spgoyette H_REQUIRE_FIELD(tm_mday);
70004608e4Spgoyette H_REQUIRE_FIELD(tm_mon);
71004608e4Spgoyette H_REQUIRE_FIELD(tm_year);
72004608e4Spgoyette H_REQUIRE_FIELD(tm_wday);
73004608e4Spgoyette H_REQUIRE_FIELD(tm_yday);
74004608e4Spgoyette
75004608e4Spgoyette #undef H_REQUIRE_FIELD
76004608e4Spgoyette }
77004608e4Spgoyette
78004608e4Spgoyette static void
h_fail(const char * buf,const char * fmt)79004608e4Spgoyette h_fail(const char *buf, const char *fmt)
80004608e4Spgoyette {
81004608e4Spgoyette struct tm tm = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL };
82004608e4Spgoyette
830161d869Smaya ATF_CHECK_MSG(strptime(buf, fmt, &tm) == NULL, "strptime(\"%s\", "
84004608e4Spgoyette "\"%s\", &tm) should fail, but it didn't", buf, fmt);
85004608e4Spgoyette }
86004608e4Spgoyette
87a45df959Schristos static struct {
88a45df959Schristos const char *name;
89a45df959Schristos long offs;
90a45df959Schristos } zt[] = {
91a45df959Schristos { "Z", 0 },
92a45df959Schristos { "UT", 0 },
93a45df959Schristos { "UTC", 0 },
94a45df959Schristos { "GMT", 0 },
95a45df959Schristos { "EST", -18000 },
96a45df959Schristos { "EDT", -14400 },
97a45df959Schristos { "CST", -21600 },
98a45df959Schristos { "CDT", -18000 },
99a45df959Schristos { "MST", -25200 },
100a45df959Schristos { "MDT", -21600 },
101a45df959Schristos { "PST", -28800 },
102a45df959Schristos { "PDT", -25200 },
103a45df959Schristos
104a45df959Schristos { "VST", -1 },
105a45df959Schristos { "VDT", -1 },
106a45df959Schristos
107a45df959Schristos { "+03", 10800 },
108a45df959Schristos { "-03", -10800 },
109a45df959Schristos { "+0403", 14580 },
110a45df959Schristos { "-0403", -14580 },
111a45df959Schristos { "+04:03", 14580 },
112a45df959Schristos { "-04:03", -14580 },
113a45df959Schristos { "+14:00", 50400 },
114a45df959Schristos { "-14:00", -50400 },
115a45df959Schristos { "+23:59", 86340 },
116a45df959Schristos { "-23:59", -86340 },
117a45df959Schristos
118a45df959Schristos { "1", -1 },
119a45df959Schristos { "03", -1 },
120a45df959Schristos { "0304", -1 },
121a45df959Schristos { "+1", -1 },
122a45df959Schristos { "-203", -1 },
123a45df959Schristos { "+12345", -1 },
124a45df959Schristos { "+12:345", -1 },
125a45df959Schristos { "+123:45", -1 },
126a45df959Schristos { "+2400", -1 },
127a45df959Schristos { "-2400", -1 },
128a45df959Schristos { "+1060", -1 },
129a45df959Schristos { "-1060", -1 },
130a45df959Schristos
1318f3f249eSginsbach { "A", 3600 },
1328f3f249eSginsbach { "B", 7200 },
1338f3f249eSginsbach { "C", 10800 },
1348f3f249eSginsbach { "D", 14400 },
1358f3f249eSginsbach { "E", 18000 },
1368f3f249eSginsbach { "F", 21600 },
1378f3f249eSginsbach { "G", 25200 },
1388f3f249eSginsbach { "H", 28800 },
1398f3f249eSginsbach { "I", 32400 },
1408f3f249eSginsbach { "L", 39600 },
1418f3f249eSginsbach { "M", 43200 },
1428f3f249eSginsbach { "N", -3600 },
1438f3f249eSginsbach { "O", -7200 },
1448f3f249eSginsbach { "P", -10800 },
1458f3f249eSginsbach { "Q", -14400 },
1468f3f249eSginsbach { "R", -18000 },
1478f3f249eSginsbach { "T", -25200 },
1488f3f249eSginsbach { "U", -28800 },
1498f3f249eSginsbach { "V", -32400 },
1508f3f249eSginsbach { "W", -36000 },
1518f3f249eSginsbach { "X", -39600 },
1528f3f249eSginsbach { "Y", -43200 },
153a45df959Schristos
1543112bb3eSchristos { "J", -2 },
155a45df959Schristos
156a45df959Schristos { "America/Los_Angeles", -28800 },
157a45df959Schristos { "America/New_York", -18000 },
158a45df959Schristos { "EST4EDT", -14400 },
159a45df959Schristos
160a45df959Schristos { "Bogus", -1 },
161a45df959Schristos };
162a45df959Schristos
163a45df959Schristos static void
ztest1(const char * name,const char * fmt,long value)1644e4836ffSchristos ztest1(const char *name, const char *fmt, long value)
165a45df959Schristos {
166a45df959Schristos struct tm tm;
1673112bb3eSchristos char *rv;
168a45df959Schristos
169a45df959Schristos memset(&tm, 0, sizeof(tm));
1703112bb3eSchristos if ((rv = strptime(name, fmt, &tm)) == NULL)
171a45df959Schristos tm.tm_gmtoff = -1;
1723112bb3eSchristos else if (rv == name && fmt[1] == 'Z')
1733112bb3eSchristos value = 0;
1743112bb3eSchristos
1753112bb3eSchristos switch (value) {
1763112bb3eSchristos case -2:
1773112bb3eSchristos value = -timezone;
1783112bb3eSchristos break;
1793112bb3eSchristos case -1:
1803112bb3eSchristos if (fmt[1] == 'Z')
1813112bb3eSchristos value = 0;
1823112bb3eSchristos break;
1833112bb3eSchristos default:
1843112bb3eSchristos break;
1853112bb3eSchristos }
1863112bb3eSchristos
1870161d869Smaya ATF_CHECK_MSG(tm.tm_gmtoff == value,
188a45df959Schristos "strptime(\"%s\", \"%s\", &tm): "
189a45df959Schristos "expected: tm.tm_gmtoff=%ld, got: tm.tm_gmtoff=%ld",
190a45df959Schristos name, fmt, value, tm.tm_gmtoff);
1913112bb3eSchristos printf("%s %s %ld\n", name, fmt, tm.tm_gmtoff);
192a45df959Schristos }
193a45df959Schristos
1944e4836ffSchristos static void
ztest(const char * fmt)1954e4836ffSchristos ztest(const char *fmt)
1964e4836ffSchristos {
1974e4836ffSchristos setenv("TZ", "US/Eastern", 1);
1984e4836ffSchristos ztest1("GMT", fmt, 0);
1994e4836ffSchristos ztest1("UTC", fmt, 0);
2004e4836ffSchristos ztest1("US/Eastern", fmt, -18000);
2014e4836ffSchristos for (size_t i = 0; i < __arraycount(zt); i++)
2024e4836ffSchristos ztest1(zt[i].name, fmt, zt[i].offs);
2034e4836ffSchristos }
2044e4836ffSchristos
205004608e4Spgoyette ATF_TC(common);
206004608e4Spgoyette
ATF_TC_HEAD(common,tc)207004608e4Spgoyette ATF_TC_HEAD(common, tc)
208004608e4Spgoyette {
209004608e4Spgoyette
210004608e4Spgoyette atf_tc_set_md_var(tc, "descr", "Checks strptime(3): various checks");
211004608e4Spgoyette }
212004608e4Spgoyette
ATF_TC_BODY(common,tc)213004608e4Spgoyette ATF_TC_BODY(common, tc)
214004608e4Spgoyette {
215004608e4Spgoyette
216004608e4Spgoyette h_pass("Tue Jan 20 23:27:46 1998", "%a %b %d %T %Y",
217ca074ef6Schristos 24, 46, 27, 23, 20, 0, 98, 2, 19);
218004608e4Spgoyette h_pass("Tue Jan 20 23:27:46 1998", "%a %b %d %H:%M:%S %Y",
219ca074ef6Schristos 24, 46, 27, 23, 20, 0, 98, 2, 19);
220004608e4Spgoyette h_pass("Tue Jan 20 23:27:46 1998", "%c",
221ca074ef6Schristos 24, 46, 27, 23, 20, 0, 98, 2, 19);
222004608e4Spgoyette h_pass("Fri Mar 4 20:05:34 2005", "%a %b %e %H:%M:%S %Y",
223ca074ef6Schristos 24, 34, 5, 20, 4, 2, 105, 5, 62);
224004608e4Spgoyette h_pass("5\t3 4 8pm:05:34 2005", "%w%n%m%t%d%n%k%p:%M:%S %Y",
225ca074ef6Schristos 21, 34, 5, 20, 4, 2, 105, 5, 62);
226004608e4Spgoyette h_pass("Fri Mar 4 20:05:34 2005", "%c",
227ca074ef6Schristos 24, 34, 5, 20, 4, 2, 105, 5, 62);
228004608e4Spgoyette }
229004608e4Spgoyette
230004608e4Spgoyette ATF_TC(day);
231004608e4Spgoyette
ATF_TC_HEAD(day,tc)232004608e4Spgoyette ATF_TC_HEAD(day, tc)
233004608e4Spgoyette {
234004608e4Spgoyette
235a5f68193Sginsbach atf_tc_set_md_var(tc, "descr",
236a5f68193Sginsbach "Checks strptime(3) day name conversions [aA]");
237004608e4Spgoyette }
238004608e4Spgoyette
ATF_TC_BODY(day,tc)239004608e4Spgoyette ATF_TC_BODY(day, tc)
240004608e4Spgoyette {
241004608e4Spgoyette
242004608e4Spgoyette h_pass("Sun", "%a", 3, -1, -1, -1, -1, -1, -1, 0, -1);
243004608e4Spgoyette h_pass("Sunday", "%a", 6, -1, -1, -1, -1, -1, -1, 0, -1);
244004608e4Spgoyette h_pass("Mon", "%a", 3, -1, -1, -1, -1, -1, -1, 1, -1);
245004608e4Spgoyette h_pass("Monday", "%a", 6, -1, -1, -1, -1, -1, -1, 1, -1);
246004608e4Spgoyette h_pass("Tue", "%a", 3, -1, -1, -1, -1, -1, -1, 2, -1);
247004608e4Spgoyette h_pass("Tuesday", "%a", 7, -1, -1, -1, -1, -1, -1, 2, -1);
248004608e4Spgoyette h_pass("Wed", "%a", 3, -1, -1, -1, -1, -1, -1, 3, -1);
249004608e4Spgoyette h_pass("Wednesday", "%a", 9, -1, -1, -1, -1, -1, -1, 3, -1);
250004608e4Spgoyette h_pass("Thu", "%a", 3, -1, -1, -1, -1, -1, -1, 4, -1);
251004608e4Spgoyette h_pass("Thursday", "%a", 8, -1, -1, -1, -1, -1, -1, 4, -1);
252004608e4Spgoyette h_pass("Fri", "%a", 3, -1, -1, -1, -1, -1, -1, 5, -1);
253004608e4Spgoyette h_pass("Friday", "%a", 6, -1, -1, -1, -1, -1, -1, 5, -1);
254004608e4Spgoyette h_pass("Sat", "%a", 3, -1, -1, -1, -1, -1, -1, 6, -1);
255004608e4Spgoyette h_pass("Saturday", "%a", 8, -1, -1, -1, -1, -1, -1, 6, -1);
256004608e4Spgoyette h_pass("Saturn", "%a", 3, -1, -1, -1, -1, -1, -1, 6, -1);
257004608e4Spgoyette h_fail("Moon", "%a");
258004608e4Spgoyette h_pass("Sun", "%A", 3, -1, -1, -1, -1, -1, -1, 0, -1);
259004608e4Spgoyette h_pass("Sunday", "%A", 6, -1, -1, -1, -1, -1, -1, 0, -1);
260004608e4Spgoyette h_pass("Mon", "%A", 3, -1, -1, -1, -1, -1, -1, 1, -1);
261004608e4Spgoyette h_pass("Monday", "%A", 6, -1, -1, -1, -1, -1, -1, 1, -1);
262004608e4Spgoyette h_pass("Tue", "%A", 3, -1, -1, -1, -1, -1, -1, 2, -1);
263004608e4Spgoyette h_pass("Tuesday", "%A", 7, -1, -1, -1, -1, -1, -1, 2, -1);
264004608e4Spgoyette h_pass("Wed", "%A", 3, -1, -1, -1, -1, -1, -1, 3, -1);
265004608e4Spgoyette h_pass("Wednesday", "%A", 9, -1, -1, -1, -1, -1, -1, 3, -1);
266004608e4Spgoyette h_pass("Thu", "%A", 3, -1, -1, -1, -1, -1, -1, 4, -1);
267004608e4Spgoyette h_pass("Thursday", "%A", 8, -1, -1, -1, -1, -1, -1, 4, -1);
268004608e4Spgoyette h_pass("Fri", "%A", 3, -1, -1, -1, -1, -1, -1, 5, -1);
269004608e4Spgoyette h_pass("Friday", "%A", 6, -1, -1, -1, -1, -1, -1, 5, -1);
270004608e4Spgoyette h_pass("Sat", "%A", 3, -1, -1, -1, -1, -1, -1, 6, -1);
271004608e4Spgoyette h_pass("Saturday", "%A", 8, -1, -1, -1, -1, -1, -1, 6, -1);
272004608e4Spgoyette h_pass("Saturn", "%A", 3, -1, -1, -1, -1, -1, -1, 6, -1);
273004608e4Spgoyette h_fail("Moon", "%A");
274004608e4Spgoyette
275004608e4Spgoyette h_pass("mon", "%a", 3, -1, -1, -1, -1, -1, -1, 1, -1);
276004608e4Spgoyette h_pass("tueSDay", "%A", 7, -1, -1, -1, -1, -1, -1, 2, -1);
277004608e4Spgoyette h_pass("sunday", "%A", 6, -1, -1, -1, -1, -1, -1, 0, -1);
278004608e4Spgoyette h_fail("sunday", "%EA");
279004608e4Spgoyette h_pass("SaturDay", "%A", 8, -1, -1, -1, -1, -1, -1, 6, -1);
280004608e4Spgoyette h_fail("SaturDay", "%OA");
281004608e4Spgoyette }
282004608e4Spgoyette
2837b940a5bSginsbach ATF_TC(hour);
2847b940a5bSginsbach
ATF_TC_HEAD(hour,tc)2857b940a5bSginsbach ATF_TC_HEAD(hour, tc)
2867b940a5bSginsbach {
2877b940a5bSginsbach
2887b940a5bSginsbach atf_tc_set_md_var(tc, "descr",
2897b940a5bSginsbach "Checks strptime(3) hour conversions [IH]");
2907b940a5bSginsbach }
2917b940a5bSginsbach
ATF_TC_BODY(hour,tc)2927b940a5bSginsbach ATF_TC_BODY(hour, tc)
2937b940a5bSginsbach {
2947b940a5bSginsbach
2957b940a5bSginsbach h_fail("00", "%I");
2967b940a5bSginsbach h_fail("13", "%I");
2977b940a5bSginsbach
2987b940a5bSginsbach h_pass("00", "%H", 2, -1, -1, 0, -1, -1, -1, -1, -1);
2997b940a5bSginsbach h_pass("12", "%H", 2, -1, -1, 12, -1, -1, -1, -1, -1);
3007b940a5bSginsbach h_pass("23", "%H", 2, -1, -1, 23, -1, -1, -1, -1, -1);
3017b940a5bSginsbach h_fail("24", "%H");
3027b940a5bSginsbach }
3037b940a5bSginsbach
3047b940a5bSginsbach
305004608e4Spgoyette ATF_TC(month);
306004608e4Spgoyette
ATF_TC_HEAD(month,tc)307004608e4Spgoyette ATF_TC_HEAD(month, tc)
308004608e4Spgoyette {
309004608e4Spgoyette
310a5f68193Sginsbach atf_tc_set_md_var(tc, "descr",
311a5f68193Sginsbach "Checks strptime(3) month name conversions [bB]");
312004608e4Spgoyette }
313004608e4Spgoyette
ATF_TC_BODY(month,tc)314004608e4Spgoyette ATF_TC_BODY(month, tc)
315004608e4Spgoyette {
316004608e4Spgoyette
317004608e4Spgoyette h_pass("Jan", "%b", 3, -1, -1, -1, -1, 0, -1, -1, -1);
318004608e4Spgoyette h_pass("January", "%b", 7, -1, -1, -1, -1, 0, -1, -1, -1);
319004608e4Spgoyette h_pass("Feb", "%b", 3, -1, -1, -1, -1, 1, -1, -1, -1);
320004608e4Spgoyette h_pass("February", "%b", 8, -1, -1, -1, -1, 1, -1, -1, -1);
321004608e4Spgoyette h_pass("Mar", "%b", 3, -1, -1, -1, -1, 2, -1, -1, -1);
322004608e4Spgoyette h_pass("March", "%b", 5, -1, -1, -1, -1, 2, -1, -1, -1);
323004608e4Spgoyette h_pass("Apr", "%b", 3, -1, -1, -1, -1, 3, -1, -1, -1);
324004608e4Spgoyette h_pass("April", "%b", 5, -1, -1, -1, -1, 3, -1, -1, -1);
325004608e4Spgoyette h_pass("May", "%b", 3, -1, -1, -1, -1, 4, -1, -1, -1);
326004608e4Spgoyette h_pass("Jun", "%b", 3, -1, -1, -1, -1, 5, -1, -1, -1);
327004608e4Spgoyette h_pass("June", "%b", 4, -1, -1, -1, -1, 5, -1, -1, -1);
328004608e4Spgoyette h_pass("Jul", "%b", 3, -1, -1, -1, -1, 6, -1, -1, -1);
329004608e4Spgoyette h_pass("July", "%b", 4, -1, -1, -1, -1, 6, -1, -1, -1);
330004608e4Spgoyette h_pass("Aug", "%b", 3, -1, -1, -1, -1, 7, -1, -1, -1);
331004608e4Spgoyette h_pass("August", "%b", 6, -1, -1, -1, -1, 7, -1, -1, -1);
332004608e4Spgoyette h_pass("Sep", "%b", 3, -1, -1, -1, -1, 8, -1, -1, -1);
333004608e4Spgoyette h_pass("September", "%b", 9, -1, -1, -1, -1, 8, -1, -1, -1);
334004608e4Spgoyette h_pass("Oct", "%b", 3, -1, -1, -1, -1, 9, -1, -1, -1);
335004608e4Spgoyette h_pass("October", "%b", 7, -1, -1, -1, -1, 9, -1, -1, -1);
336004608e4Spgoyette h_pass("Nov", "%b", 3, -1, -1, -1, -1, 10, -1, -1, -1);
337004608e4Spgoyette h_pass("November", "%b", 8, -1, -1, -1, -1, 10, -1, -1, -1);
338004608e4Spgoyette h_pass("Dec", "%b", 3, -1, -1, -1, -1, 11, -1, -1, -1);
339004608e4Spgoyette h_pass("December", "%b", 8, -1, -1, -1, -1, 11, -1, -1, -1);
340004608e4Spgoyette h_pass("Mayor", "%b", 3, -1, -1, -1, -1, 4, -1, -1, -1);
341004608e4Spgoyette h_pass("Mars", "%b", 3, -1, -1, -1, -1, 2, -1, -1, -1);
342004608e4Spgoyette h_fail("Rover", "%b");
343004608e4Spgoyette h_pass("Jan", "%B", 3, -1, -1, -1, -1, 0, -1, -1, -1);
344004608e4Spgoyette h_pass("January", "%B", 7, -1, -1, -1, -1, 0, -1, -1, -1);
345004608e4Spgoyette h_pass("Feb", "%B", 3, -1, -1, -1, -1, 1, -1, -1, -1);
346004608e4Spgoyette h_pass("February", "%B", 8, -1, -1, -1, -1, 1, -1, -1, -1);
347004608e4Spgoyette h_pass("Mar", "%B", 3, -1, -1, -1, -1, 2, -1, -1, -1);
348004608e4Spgoyette h_pass("March", "%B", 5, -1, -1, -1, -1, 2, -1, -1, -1);
349004608e4Spgoyette h_pass("Apr", "%B", 3, -1, -1, -1, -1, 3, -1, -1, -1);
350004608e4Spgoyette h_pass("April", "%B", 5, -1, -1, -1, -1, 3, -1, -1, -1);
351004608e4Spgoyette h_pass("May", "%B", 3, -1, -1, -1, -1, 4, -1, -1, -1);
352004608e4Spgoyette h_pass("Jun", "%B", 3, -1, -1, -1, -1, 5, -1, -1, -1);
353004608e4Spgoyette h_pass("June", "%B", 4, -1, -1, -1, -1, 5, -1, -1, -1);
354004608e4Spgoyette h_pass("Jul", "%B", 3, -1, -1, -1, -1, 6, -1, -1, -1);
355004608e4Spgoyette h_pass("July", "%B", 4, -1, -1, -1, -1, 6, -1, -1, -1);
356004608e4Spgoyette h_pass("Aug", "%B", 3, -1, -1, -1, -1, 7, -1, -1, -1);
357004608e4Spgoyette h_pass("August", "%B", 6, -1, -1, -1, -1, 7, -1, -1, -1);
358004608e4Spgoyette h_pass("Sep", "%B", 3, -1, -1, -1, -1, 8, -1, -1, -1);
359004608e4Spgoyette h_pass("September", "%B", 9, -1, -1, -1, -1, 8, -1, -1, -1);
360004608e4Spgoyette h_pass("Oct", "%B", 3, -1, -1, -1, -1, 9, -1, -1, -1);
361004608e4Spgoyette h_pass("October", "%B", 7, -1, -1, -1, -1, 9, -1, -1, -1);
362004608e4Spgoyette h_pass("Nov", "%B", 3, -1, -1, -1, -1, 10, -1, -1, -1);
363004608e4Spgoyette h_pass("November", "%B", 8, -1, -1, -1, -1, 10, -1, -1, -1);
364004608e4Spgoyette h_pass("Dec", "%B", 3, -1, -1, -1, -1, 11, -1, -1, -1);
365004608e4Spgoyette h_pass("December", "%B", 8, -1, -1, -1, -1, 11, -1, -1, -1);
366004608e4Spgoyette h_pass("Mayor", "%B", 3, -1, -1, -1, -1, 4, -1, -1, -1);
367004608e4Spgoyette h_pass("Mars", "%B", 3, -1, -1, -1, -1, 2, -1, -1, -1);
368004608e4Spgoyette h_fail("Rover", "%B");
369004608e4Spgoyette
370004608e4Spgoyette h_pass("september", "%b", 9, -1, -1, -1, -1, 8, -1, -1, -1);
371004608e4Spgoyette h_pass("septembe", "%B", 3, -1, -1, -1, -1, 8, -1, -1, -1);
372004608e4Spgoyette }
373004608e4Spgoyette
374fb89bad2Sginsbach ATF_TC(seconds);
375fb89bad2Sginsbach
ATF_TC_HEAD(seconds,tc)376fb89bad2Sginsbach ATF_TC_HEAD(seconds, tc)
377fb89bad2Sginsbach {
378fb89bad2Sginsbach
379fb89bad2Sginsbach atf_tc_set_md_var(tc, "descr",
380fb89bad2Sginsbach "Checks strptime(3) seconds conversions [S]");
381fb89bad2Sginsbach }
382fb89bad2Sginsbach
ATF_TC_BODY(seconds,tc)383fb89bad2Sginsbach ATF_TC_BODY(seconds, tc)
384fb89bad2Sginsbach {
385fb89bad2Sginsbach
386fb89bad2Sginsbach h_pass("0", "%S", 1, 0, -1, -1, -1, -1, -1, -1, -1);
387fb89bad2Sginsbach h_pass("59", "%S", 2, 59, -1, -1, -1, -1, -1, -1, -1);
388fb89bad2Sginsbach h_pass("60", "%S", 2, 60, -1, -1, -1, -1, -1, -1, -1);
389fb89bad2Sginsbach h_pass("61", "%S", 2, 61, -1, -1, -1, -1, -1, -1, -1);
390fb89bad2Sginsbach h_fail("62", "%S");
391fb89bad2Sginsbach }
392fb89bad2Sginsbach
3930b61b786Sginsbach ATF_TC(year);
3940b61b786Sginsbach
ATF_TC_HEAD(year,tc)3950b61b786Sginsbach ATF_TC_HEAD(year, tc)
3960b61b786Sginsbach {
3970b61b786Sginsbach
3980b61b786Sginsbach atf_tc_set_md_var(tc, "descr",
3990b61b786Sginsbach "Checks strptime(3) century/year conversions [CyY]");
4000b61b786Sginsbach }
4010b61b786Sginsbach
ATF_TC_BODY(year,tc)4020b61b786Sginsbach ATF_TC_BODY(year, tc)
4030b61b786Sginsbach {
4040b61b786Sginsbach
4050b61b786Sginsbach h_pass("x20y", "x%Cy", 4, -1, -1, -1, -1, -1, 100, -1, -1);
4060b61b786Sginsbach h_pass("x84y", "x%yy", 4, -1, -1, -1, -1, -1, 84, -1, -1);
4070b61b786Sginsbach h_pass("x2084y", "x%C%yy", 6, -1, -1, -1, -1, -1, 184, -1, -1);
4080b61b786Sginsbach h_pass("x8420y", "x%y%Cy", 6, -1, -1, -1, -1, -1, 184, -1, -1);
4090b61b786Sginsbach h_pass("%20845", "%%%C%y5", 6, -1, -1, -1, -1, -1, 184, -1, -1);
4100b61b786Sginsbach h_fail("%", "%E%");
4110b61b786Sginsbach
4120b61b786Sginsbach h_pass("1980", "%Y", 4, -1, -1, -1, -1, -1, 80, -1, -1);
4130b61b786Sginsbach h_pass("1980", "%EY", 4, -1, -1, -1, -1, -1, 80, -1, -1);
4140b61b786Sginsbach }
4150b61b786Sginsbach
41605ea9f0eSchristos ATF_TC(zone);
41705ea9f0eSchristos
ATF_TC_HEAD(zone,tc)41805ea9f0eSchristos ATF_TC_HEAD(zone, tc)
41905ea9f0eSchristos {
42005ea9f0eSchristos
42105ea9f0eSchristos atf_tc_set_md_var(tc, "descr",
42205ea9f0eSchristos "Checks strptime(3) timezone conversion [z]");
42305ea9f0eSchristos }
42405ea9f0eSchristos
42505ea9f0eSchristos
ATF_TC_BODY(zone,tc)42605ea9f0eSchristos ATF_TC_BODY(zone, tc)
42705ea9f0eSchristos {
4284e4836ffSchristos ztest("%z");
42905ea9f0eSchristos }
430a45df959Schristos
431a45df959Schristos ATF_TC(Zone);
432a45df959Schristos
ATF_TC_HEAD(Zone,tc)433a45df959Schristos ATF_TC_HEAD(Zone, tc)
434a45df959Schristos {
435a45df959Schristos
436a45df959Schristos atf_tc_set_md_var(tc, "descr",
437a45df959Schristos "Checks strptime(3) timezone conversion [Z]");
438a45df959Schristos }
439a45df959Schristos
440a45df959Schristos
ATF_TC_BODY(Zone,tc)441a45df959Schristos ATF_TC_BODY(Zone, tc)
442a45df959Schristos {
443001379fbSkre ztest("%Z");
44405ea9f0eSchristos }
44505ea9f0eSchristos
446086a7f84Sriastradh ATF_TC(posixtime_overflow);
447086a7f84Sriastradh
ATF_TC_HEAD(posixtime_overflow,tc)448086a7f84Sriastradh ATF_TC_HEAD(posixtime_overflow, tc)
449086a7f84Sriastradh {
450086a7f84Sriastradh
451086a7f84Sriastradh atf_tc_set_md_var(tc, "descr",
452*e6155eabSrillig "Checks strptime(3) safely rejects POSIX time overflow");
453086a7f84Sriastradh }
454086a7f84Sriastradh
ATF_TC_BODY(posixtime_overflow,tc)455086a7f84Sriastradh ATF_TC_BODY(posixtime_overflow, tc)
456086a7f84Sriastradh {
457086a7f84Sriastradh static const uint64_t P[] = { /* cases that should pass round-trip */
458086a7f84Sriastradh [0] = 0,
459086a7f84Sriastradh [1] = 1,
460086a7f84Sriastradh [2] = 2,
461086a7f84Sriastradh [3] = 0x7ffffffe,
462086a7f84Sriastradh [4] = 0x7fffffff,
463086a7f84Sriastradh [5] = 0x80000000,
464086a7f84Sriastradh [6] = 0x80000001,
465086a7f84Sriastradh [7] = 0xfffffffe,
466086a7f84Sriastradh [8] = 0xffffffff,
467086a7f84Sriastradh [9] = 0x100000000,
468086a7f84Sriastradh [10] = 0x100000001,
469086a7f84Sriastradh [11] = 67767976233532799, /* 2147483647-12-31T23:59:59 */
470086a7f84Sriastradh /*
471086a7f84Sriastradh * Beyond this point, the year (.tm_year + 1900)
472086a7f84Sriastradh * overflows the signed 32-bit range, so we won't be
473086a7f84Sriastradh * able to test round-trips:
474086a7f84Sriastradh */
475086a7f84Sriastradh [12] = 67767976233532800,
476086a7f84Sriastradh [13] = 67767976233532801,
477086a7f84Sriastradh [14] = 67768036191676799,
478086a7f84Sriastradh /*
479086a7f84Sriastradh * Beyond this point, .tm_year itself overflows the
480086a7f84Sriastradh * signed 32-bit range, so strptime won't work at all;
481086a7f84Sriastradh * the output can't be represented in struct tm.
482086a7f84Sriastradh */
483086a7f84Sriastradh #if 0
484086a7f84Sriastradh [15] = 67768036191676800,
485086a7f84Sriastradh [16] = 67768036191676801,
486086a7f84Sriastradh [17] = 0x7ffffffffffffffe,
487086a7f84Sriastradh [18] = 0x7fffffffffffffff,
488086a7f84Sriastradh #endif
489086a7f84Sriastradh };
490086a7f84Sriastradh static const uint64_t F[] = { /* cases strptime should reject */
491086a7f84Sriastradh [0] = 67768036191676800,
492086a7f84Sriastradh [1] = 67768036191676801,
493086a7f84Sriastradh [2] = 0x7ffffffffffffffe,
494086a7f84Sriastradh [3] = 0x7fffffffffffffff,
495086a7f84Sriastradh [4] = 0x8000000000000000,
496086a7f84Sriastradh [5] = 0x8000000000000001,
497086a7f84Sriastradh [6] = 0xfffffffffffffffe,
498086a7f84Sriastradh [7] = 0xffffffffffffffff,
499086a7f84Sriastradh };
500086a7f84Sriastradh size_t i;
501086a7f84Sriastradh
502086a7f84Sriastradh /*
503086a7f84Sriastradh * Verify time_t fits in uint64_t, with space to spare since
504086a7f84Sriastradh * it's signed.
505086a7f84Sriastradh */
506086a7f84Sriastradh __CTASSERT(__type_max(time_t) < __type_max(uint64_t));
507086a7f84Sriastradh
508086a7f84Sriastradh /*
509086a7f84Sriastradh * Make sure we work in UTC so this test doesn't depend on
510086a7f84Sriastradh * which time zone your machine is configured for.
511086a7f84Sriastradh */
512086a7f84Sriastradh setenv("TZ", "UTC", 1);
513086a7f84Sriastradh
514086a7f84Sriastradh /*
515086a7f84Sriastradh * Check the should-pass cases.
516086a7f84Sriastradh */
517086a7f84Sriastradh for (i = 0; i < __arraycount(P); i++) {
518086a7f84Sriastradh char buf[sizeof("18446744073709551616")];
519086a7f84Sriastradh int n;
520086a7f84Sriastradh struct tm tm;
521086a7f84Sriastradh time_t t;
522086a7f84Sriastradh int error;
523086a7f84Sriastradh
524086a7f84Sriastradh /*
525086a7f84Sriastradh * Format the integer in decimal.
526086a7f84Sriastradh */
527086a7f84Sriastradh n = snprintf(buf, sizeof(buf), "%"PRIu64, P[i]);
528086a7f84Sriastradh ATF_CHECK_MSG(n >= 0 && (unsigned)n < sizeof(buf),
529086a7f84Sriastradh "P[%zu]: 64-bit requires %d digits", i, n);
530086a7f84Sriastradh
531086a7f84Sriastradh /*
532086a7f84Sriastradh * Parse the time into components.
533086a7f84Sriastradh */
534086a7f84Sriastradh fprintf(stderr, "# P[%zu]: %"PRId64"\n", i, P[i]);
535086a7f84Sriastradh if (strptime(buf, "%s", &tm) == NULL) {
536086a7f84Sriastradh atf_tc_fail_nonfatal("P[%zu]: strptime failed", i);
537086a7f84Sriastradh continue;
538086a7f84Sriastradh }
539086a7f84Sriastradh fprintf(stderr, "tm_sec=%d\n", tm.tm_sec);
540086a7f84Sriastradh fprintf(stderr, "tm_min=%d\n", tm.tm_min);
541086a7f84Sriastradh fprintf(stderr, "tm_hour=%d\n", tm.tm_hour);
542086a7f84Sriastradh fprintf(stderr, "tm_mday=%d\n", tm.tm_mday);
543086a7f84Sriastradh fprintf(stderr, "tm_mon=%d\n", tm.tm_mon);
544086a7f84Sriastradh fprintf(stderr, "tm_year=%d\n", tm.tm_year);
545086a7f84Sriastradh fprintf(stderr, "tm_wday=%d\n", tm.tm_wday);
546086a7f84Sriastradh fprintf(stderr, "tm_yday=%d\n", tm.tm_yday);
547086a7f84Sriastradh fprintf(stderr, "tm_isdst=%d\n", tm.tm_isdst);
548086a7f84Sriastradh fprintf(stderr, "tm_gmtoff=%ld\n", tm.tm_gmtoff);
549086a7f84Sriastradh fprintf(stderr, "tm_zone=%s\n", tm.tm_zone);
550086a7f84Sriastradh
551086a7f84Sriastradh /*
552086a7f84Sriastradh * Convert back to POSIX seconds since epoch -- unless
553086a7f84Sriastradh * the year number overflows signed 32-bit, in which
554086a7f84Sriastradh * case stop here because we can't test further.
555086a7f84Sriastradh */
556086a7f84Sriastradh if (tm.tm_year > 0x7fffffff - 1900)
557086a7f84Sriastradh continue;
558086a7f84Sriastradh t = mktime(&tm);
559086a7f84Sriastradh error = errno;
560086a7f84Sriastradh ATF_CHECK_MSG(t != -1, "P[%zu]: mktime failed: %d, %s",
561086a7f84Sriastradh i, error, strerror(error));
562086a7f84Sriastradh
563086a7f84Sriastradh /*
564086a7f84Sriastradh * Verify the round-trip.
565086a7f84Sriastradh */
566086a7f84Sriastradh ATF_CHECK_EQ_MSG(P[i], (uint64_t)t,
567086a7f84Sriastradh "P[%zu]: %"PRId64" -> %"PRId64, i, P[i], (int64_t)t);
568086a7f84Sriastradh }
569086a7f84Sriastradh
570086a7f84Sriastradh /*
571086a7f84Sriastradh * Check the should-fail cases.
572086a7f84Sriastradh */
573086a7f84Sriastradh for (i = 0; i < __arraycount(F); i++) {
574086a7f84Sriastradh char buf[sizeof("18446744073709551616")];
575086a7f84Sriastradh int n;
576086a7f84Sriastradh
577086a7f84Sriastradh /*
578086a7f84Sriastradh * Format the integer in decimal.
579086a7f84Sriastradh */
580086a7f84Sriastradh n = snprintf(buf, sizeof(buf), "%"PRIu64, F[i]);
581086a7f84Sriastradh ATF_CHECK_MSG(n >= 0 && (unsigned)n < sizeof(buf),
582086a7f84Sriastradh "F[%zu]: 64-bit requires %d digits", i, n);
583086a7f84Sriastradh
584086a7f84Sriastradh /*
585086a7f84Sriastradh * Verify strptime rejects this.
586086a7f84Sriastradh */
587086a7f84Sriastradh h_fail(buf, "%s");
588086a7f84Sriastradh }
589086a7f84Sriastradh }
590086a7f84Sriastradh
ATF_TP_ADD_TCS(tp)591004608e4Spgoyette ATF_TP_ADD_TCS(tp)
592004608e4Spgoyette {
593004608e4Spgoyette
594004608e4Spgoyette ATF_TP_ADD_TC(tp, common);
595004608e4Spgoyette ATF_TP_ADD_TC(tp, day);
5967b940a5bSginsbach ATF_TP_ADD_TC(tp, hour);
597004608e4Spgoyette ATF_TP_ADD_TC(tp, month);
598fb89bad2Sginsbach ATF_TP_ADD_TC(tp, seconds);
5990b61b786Sginsbach ATF_TP_ADD_TC(tp, year);
60005ea9f0eSchristos ATF_TP_ADD_TC(tp, zone);
601a45df959Schristos ATF_TP_ADD_TC(tp, Zone);
602086a7f84Sriastradh ATF_TP_ADD_TC(tp, posixtime_overflow);
603004608e4Spgoyette
604004608e4Spgoyette return atf_no_error();
605004608e4Spgoyette }
606