This source file includes following definitions.
- posixtm_test
- tzalloc_test
- quarter_test
- errno_test
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21 #include "strftime.h"
22
23 #include "intprops.h"
24
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <time.h>
30 #include <unistd.h>
31
32 #include "macros.h"
33 #define STREQ(a, b) (strcmp (a, b) == 0)
34
35
36 #define TZ_ANGLE_BRACKETS_SHOULD_WORK (200112 <= _POSIX_VERSION)
37
38 struct posixtm_test
39 {
40 time_t in;
41 int in_ns;
42 char const *fmt;
43 char const *exp;
44 };
45
46 static struct posixtm_test const T[] =
47 {
48 { 1300000000, 0, "%F", "2011-03-13" },
49 { 0, 10, "%T.%N", "00:00:00.000000010" },
50 { 56, 123456789, "%T.%12N", "00:00:56.123456789000" },
51 { 0, 0, NULL, NULL }
52 };
53
54 static int
55 posixtm_test (void)
56 {
57 int fail = 0;
58 unsigned int i;
59
60 for (i = 0; T[i].fmt; i++)
61 {
62 char buf[1000];
63 time_t t = T[i].in;
64 struct tm *tm = gmtime (&t);
65 size_t n;
66
67 ASSERT (tm);
68
69 n = nstrftime (buf, sizeof buf, T[i].fmt, tm, 0, T[i].in_ns);
70 if (n == 0)
71 {
72 fail = 1;
73 printf ("nstrftime failed with format %s\n", T[i].fmt);
74 }
75
76 if (! STREQ (buf, T[i].exp))
77 {
78 fail = 1;
79 printf ("%s: result mismatch: got %s, expected %s\n",
80 T[i].fmt, buf, T[i].exp);
81 }
82 }
83
84 return fail;
85 }
86
87 struct tzalloc_test
88 {
89 timezone_t tz;
90 char const *setting;
91 };
92
93 static struct tzalloc_test TZ[] =
94 {
95 #define Pacific 0
96 { 0, "PST8PDT,M3.2.0,M11.1.0" },
97 #define Arizona 1
98 { 0, "MST7" },
99 #define UTC 2
100 { 0, 0 },
101 #define CentEur 3
102 { 0, "CET-1CEST,M3.5.0,M10.5.0/3" },
103 #define Japan 4
104 { 0, "JST-9" },
105 #define NZ 5
106 { 0, "NZST-12NZDT,M9.5.0,M4.1.0/3" },
107 #define Unknown 6
108 { 0, "<-00>0" },
109 { 0 }
110 };
111
112 struct localtime_rz_test
113 {
114
115 struct tzalloc_test *tza;
116 time_t t;
117
118
119 char const *exp;
120
121
122
123 int ahistorical;
124 };
125
126 static struct localtime_rz_test LT[] =
127 {
128 { TZ+Pacific, 0, "1969-12-31 16:00:00 -0800 (PST)", 0 },
129 { TZ+Arizona, 0, "1969-12-31 17:00:00 -0700 (MST)", 0 },
130 { TZ+UTC , 0, "1970-01-01 00:00:00 +0000 (UTC)", 0 },
131 { TZ+CentEur, 0, "1970-01-01 01:00:00 +0100 (CET)", 0 },
132 { TZ+Japan , 0, "1970-01-01 09:00:00 +0900 (JST)", 0 },
133 { TZ+NZ , 0, "1970-01-01 13:00:00 +1300 (NZDT)", 1 },
134 { TZ+Pacific, 500000001, "1985-11-04 16:53:21 -0800 (PST)", 0 },
135 { TZ+Arizona, 500000001, "1985-11-04 17:53:21 -0700 (MST)", 0 },
136 { TZ+UTC , 500000001, "1985-11-05 00:53:21 +0000 (UTC)", 0 },
137 { TZ+CentEur, 500000001, "1985-11-05 01:53:21 +0100 (CET)", 1 },
138 { TZ+Japan , 500000001, "1985-11-05 09:53:21 +0900 (JST)", 0 },
139 { TZ+NZ , 500000001, "1985-11-05 13:53:21 +1300 (NZDT)", 0 },
140 { TZ+Pacific, 1000000002, "2001-09-08 18:46:42 -0700 (PDT)", 0 },
141 { TZ+Arizona, 1000000002, "2001-09-08 18:46:42 -0700 (MST)", 0 },
142 { TZ+UTC , 1000000002, "2001-09-09 01:46:42 +0000 (UTC)", 0 },
143 { TZ+CentEur, 1000000002, "2001-09-09 03:46:42 +0200 (CEST)", 0 },
144 { TZ+Japan , 1000000002, "2001-09-09 10:46:42 +0900 (JST)", 0 },
145 { TZ+NZ , 1000000002, "2001-09-09 13:46:42 +1200 (NZST)", 0 },
146 #if TZ_ANGLE_BRACKETS_SHOULD_WORK
147 { TZ+Unknown, 0, "1970-01-01 00:00:00 -0000 (-00)", 0 },
148 { TZ+Unknown, 500000001, "1985-11-05 00:53:21 -0000 (-00)", 0 },
149 { TZ+Unknown, 1000000002, "2001-09-09 01:46:42 -0000 (-00)", 0 },
150 #endif
151 { 0 }
152 };
153
154 static int
155 tzalloc_test (void)
156 {
157 int fail = 0;
158 int i;
159
160 for (i = 0; LT[i].tza; i++)
161 {
162 struct tzalloc_test *tza = LT[i].tza;
163 long lt = LT[i].t;
164 timezone_t tz = tza->tz;
165 char const *setting;
166 static char const format[] = "%Y-%m-%d %H:%M:%S %z (%Z)";
167 char buf[1000];
168 struct tm tm;
169 size_t n;
170
171 if (!tz && tza->setting)
172 {
173 tz = tzalloc (tza->setting);
174 if (!tz)
175 {
176 fail = 1;
177 printf ("%s: tzalloc: %s\n", TZ[i].setting, strerror (errno));
178 continue;
179 }
180 tza->tz = tz;
181 }
182
183 setting = tza->setting ? tza->setting : "UTC0";
184
185 if (!localtime_rz (tz, <[i].t, &tm))
186 {
187 fail = 1;
188 printf ("%s: %ld: localtime_rz: %s\n", setting, lt,
189 strerror (errno));
190 continue;
191 }
192
193 n = nstrftime (buf, sizeof buf, format, &tm, tz, 0);
194 if (n == 0)
195 {
196 fail = 1;
197 printf ("%s: %ld: nstrftime failed\n", setting, lt);
198 continue;
199 }
200
201 if (! (STREQ (buf, LT[i].exp)
202 || (!tz && n == strlen (LT[i].exp)
203 && memcmp (buf, LT[i].exp, n - sizeof "(GMT)" + 1) == 0
204 && STREQ (buf + n - sizeof "(GMT)" + 1, "(GMT)"))))
205 {
206
207
208 if (!LT[i].ahistorical || tm.tm_isdst)
209 fail = 1;
210 printf ("%s: expected \"%s\", got \"%s\"\n",
211 setting, LT[i].exp, buf);
212 }
213 }
214
215 return fail;
216 }
217
218
219 static int
220 quarter_test (void)
221 {
222 int result = 0;
223 size_t mon;
224
225
226 for (mon = 1; mon <= 12; mon++)
227 {
228 char out[2];
229 char exp[2] = {0,};
230 struct tm qtm = { .tm_mon = mon - 1 };
231 char fmt[3] = {'%','q','\0'};
232
233 size_t r = nstrftime (out, sizeof (out), fmt, &qtm, 0, 0);
234 if (r == 0)
235 {
236 puts ("nstrftime(\"%q\") failed");
237 result = 1;
238 break;
239 }
240
241 exp[0] = mon < 4 ? '1' : mon < 7 ? '2' : mon < 10 ? '3' : '4';
242 if (strcmp (out, exp) != 0)
243 {
244 printf ("nstrftime %%q: expected \"%s\", got \"%s\"\n", exp, out);
245 result = 1;
246 break;
247 }
248 }
249
250 return result;
251 }
252
253 static int
254 errno_test (void)
255 {
256 int fail = 0;
257 struct tm tm = { .tm_year = 2020 - 1900, .tm_mday = 1 };
258 char buf[INT_BUFSIZE_BOUND (time_t)];
259 size_t n;
260 int bigyear = LLONG_MAX - 1900 < INT_MAX ? LLONG_MAX - 1900 : INT_MAX;
261
262 errno = 0;
263 n = nstrftime (buf, 0, "%m", &tm, 0, 0);
264 if (! (n == 0 && errno == ERANGE))
265 {
266 fail = 1;
267 printf ("nstrftime failed to set errno = ERANGE\n");
268 }
269
270 errno = 0;
271 n = nstrftime (buf, sizeof buf, "", &tm, 0, 0);
272 if (! (n == 0 && errno == 0))
273 {
274 fail = 1;
275 printf ("nstrftime failed to leave errno alone\n");
276 }
277
278
279 tm.tm_year = bigyear;
280 errno = 0;
281 n = nstrftime (buf, sizeof buf, "%s", &tm, 0, 0);
282 if (n == 0)
283 {
284 if (errno != EOVERFLOW)
285 {
286 fail = 1;
287 printf ("nstrftime failed to set errno = EOVERFLOW\n");
288 }
289
290 if (mktime_z (0, &tm) != (time_t) -1)
291 {
292 fail = 1;
293 printf ("nstrftime %%s failed but mktime_z worked for tm_year=%d\n",
294 bigyear);
295 }
296 }
297 else
298 {
299 long long int text_seconds = atoll (buf);
300 if (text_seconds <= (LLONG_MAX - 1 < TYPE_MAXIMUM (time_t)
301 ? LLONG_MAX - 1 : TYPE_MAXIMUM (time_t)))
302 {
303 time_t bigtime = text_seconds;
304 struct tm *tmp = gmtime (&bigtime);
305 if (!tmp)
306 {
307 fail = 1;
308 printf ("gmtime failed on nstrftime result\n");
309 }
310 else
311 {
312 char buf1[sizeof buf];
313 size_t n1 = nstrftime (buf1, sizeof buf1, "%s", tmp, 0, 0);
314 buf1[n1] = '\0';
315 if (! STREQ (buf, buf1))
316 {
317 fail = 1;
318 printf ("nstrftime %%s first returned '%s', then '%s'\n",
319 buf, buf1);
320 }
321 }
322 }
323 }
324
325 return fail;
326 }
327
328 int
329 main (void)
330 {
331 int fail = 0;
332 fail |= posixtm_test ();
333 fail |= tzalloc_test ();
334 fail |= quarter_test ();
335 fail |= errno_test ();
336 return fail;
337 }
338
339
340
341
342
343