Remove 'grp' and merge into 'nss' and 'posix'
[platform/upstream/glibc.git] / time / tst-strptime2.c
1 /* tst-strptime2 - Test strptime %z timezone offset specifier.  */
2
3 #include <limits.h>
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <time.h>
7 #include <libc-diag.h>
8
9 /* Dummy string is used to match strptime's %s specifier.  */
10
11 static const char dummy_string[] = "1113472456";
12
13 /* buffer_size contains the maximum test string length, including
14    trailing NUL.  */
15
16 enum
17 {
18   buffer_size = 20,
19 };
20
21 /* Verbose execution, set with --verbose command line option.  */
22
23 static bool verbose;
24
25
26 /* mkbuf - Write a test string for strptime with the specified time
27    value and number of digits into the supplied buffer, and return
28    the expected strptime test result.
29
30    The test string, buf, is written with the following content:
31      a dummy string matching strptime "%s" format specifier,
32      whitespace matching strptime " " format specifier, and
33      timezone string matching strptime "%z" format specifier.
34
35    Note that a valid timezone string is either "Z" or contains the
36    following fields:
37      Sign field consisting of a '+' or '-' sign,
38      Hours field in two decimal digits, and
39      optional Minutes field in two decimal digits. Optionally,
40      a ':' is used to separate hours and minutes.
41
42    This function may write test strings with minutes values outside
43    the valid range 00-59.  These are invalid strings and useful for
44    testing strptime's rejection of invalid strings.
45
46    The ndigits parameter is used to limit the number of timezone
47    string digits to be written and may range from 0 to 4.  Note that
48    only 2 and 4 digit strings are valid input to strptime; strings
49    with 0, 1 or 3 digits are invalid and useful for testing strptime's
50    rejection of invalid strings.
51
52    This function returns the behavior expected of strptime resulting
53    from parsing the the test string.  For valid strings, the function
54    returns the expected tm_gmtoff value.  For invalid strings,
55    LONG_MAX is returned.  LONG_MAX indicates the expectation that
56    strptime will return NULL; for example, if the number of digits
57    are not correct, or minutes part of the time is outside the valid
58    range of 00 to 59.  */
59
60 static long int
61 mkbuf (char *buf, bool neg, bool colon, unsigned int hhmm, size_t ndigits)
62 {
63   const int mm_max = 59;
64   char sign = neg ? '-' : '+';
65   int i;
66   unsigned int hh = hhmm / 100;
67   unsigned int mm = hhmm % 100;
68   long int expect = LONG_MAX;
69
70   i = sprintf (buf, "%s %c", dummy_string, sign);
71 #if __GNUC_PREREQ (7, 0)
72   /* GCC issues a warning when it thinks the snprintf buffer may be too short.
73      This test is explicitly using short buffers to force snprintf to truncate
74      the output so we ignore the warnings.  */
75   DIAG_PUSH_NEEDS_COMMENT;
76   DIAG_IGNORE_NEEDS_COMMENT (7.0, "-Wformat-truncation");
77 #endif
78   if (colon)
79     snprintf (buf + i, ndigits + 2, "%02u:%02u", hh, mm);
80   else
81     snprintf (buf + i, ndigits + 1, "%04u", hhmm);
82 #if __GNUC_PREREQ (7, 0)
83   DIAG_POP_NEEDS_COMMENT;
84 #endif
85
86   if (mm <= mm_max && (ndigits == 2 || ndigits == 4))
87     {
88       long int tm_gmtoff = hh * 3600 + mm * 60;
89
90       expect = neg ? -tm_gmtoff : tm_gmtoff;
91     }
92
93   return expect;
94 }
95
96
97 /* Write a description of expected or actual test result to stdout.  */
98
99 static void
100 describe (bool string_valid, long int tm_gmtoff)
101 {
102   if (string_valid)
103     printf ("valid, tm.tm_gmtoff %ld", tm_gmtoff);
104   else
105     printf ("invalid, return value NULL");
106 }
107
108
109 /* Using buffer buf, run strptime.  Compare results against expect,
110   the expected result.  Report failures and verbose results to stdout.
111   Update the result counts.  Return 1 if test failed, 0 if passed.  */
112
113 static int
114 compare (const char *buf, long int expect, unsigned int *nresult)
115 {
116   struct tm tm;
117   char *p;
118   bool test_string_valid;
119   long int test_result;
120   bool fail;
121   int result;
122
123   p = strptime (buf, "%s %z", &tm);
124   test_string_valid = p != NULL;
125   test_result = test_string_valid ? tm.tm_gmtoff : LONG_MAX;
126   fail = test_result != expect;
127
128   if (fail || verbose)
129     {
130       bool expect_string_valid = expect != LONG_MAX;
131
132       printf ("%s: input \"%s\", expected: ", fail ? "FAIL" : "PASS", buf);
133       describe (expect_string_valid, expect);
134
135       if (fail)
136         {
137           printf (", got: ");
138           describe (test_string_valid, test_result);
139         }
140
141       printf ("\n");
142     }
143
144   result = fail ? 1 : 0;
145   nresult[result]++;
146
147   return result;
148 }
149
150
151 static int
152 do_test (void)
153 {
154   char buf[buffer_size];
155   long int expect;
156   int result = 0;
157   /* Number of tests run with passing (index==0) and failing (index==1)
158      results.  */
159   unsigned int nresult[2];
160   unsigned int ndigits;
161   unsigned int step;
162   unsigned int hhmm;
163
164   nresult[0] = 0;
165   nresult[1] = 0;
166
167   /* Create and test input string with no sign and four digits input
168      (invalid format).  */
169
170   sprintf (buf, "%s  1030", dummy_string);
171   expect = LONG_MAX;
172   result |= compare (buf, expect, nresult);
173
174   /* Create and test input string with "Z" input (valid format).
175      Expect tm_gmtoff of 0.  */
176
177   sprintf (buf, "%s Z", dummy_string);
178   expect = 0;
179   result |= compare (buf, expect, nresult);
180
181   /* Create and test input strings with sign and digits:
182      0 digits (invalid format),
183      1 digit (invalid format),
184      2 digits (valid format),
185      3 digits (invalid format),
186      4 digits (valid format if and only if minutes is in range 00-59,
187                otherwise invalid).
188      If format is valid, the returned tm_gmtoff is checked.  */
189
190   for (ndigits = 0, step = 10000; ndigits <= 4; ndigits++, step /= 10)
191     for (hhmm = 0; hhmm <= 9999; hhmm += step)
192       {
193         /* Test both positive and negative signs.  */
194
195         expect = mkbuf (buf, false, false, hhmm, ndigits);
196         result |= compare (buf, expect, nresult);
197
198         expect = mkbuf (buf, true, false, hhmm, ndigits);
199         result |= compare (buf, expect, nresult);
200
201         /* Test with colon as well.  */
202
203         if (ndigits >= 3)
204           {
205             expect = mkbuf (buf, false, true, hhmm, ndigits);
206             result |= compare (buf, expect, nresult);
207
208             expect = mkbuf (buf, true, true, hhmm, ndigits);
209             result |= compare (buf, expect, nresult);
210           }
211       }
212
213   if (result > 0 || verbose)
214     printf ("%s: %u input strings: %u fail, %u pass\n",
215             result > 0 ? "FAIL" : "PASS",
216             nresult[1] + nresult[0], nresult[1], nresult[0]);
217
218   return result;
219 }
220
221
222 /* Add a "--verbose" command line option to test-skeleton.c.  */
223
224 #define OPT_VERBOSE 10000
225
226 #define CMDLINE_OPTIONS \
227   { "verbose", no_argument, NULL, OPT_VERBOSE, },
228
229 #define CMDLINE_PROCESS \
230   case OPT_VERBOSE: \
231     verbose = true; \
232     break;
233
234 #define TEST_FUNCTION do_test ()
235 #include "../test-skeleton.c"