root/maint/gnulib/tests/test-nstrftime.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. posixtm_test
  2. tzalloc_test
  3. quarter_test
  4. errno_test
  5. main

   1 /* Test that nstrftime works as required.
   2    Copyright (C) 2011-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3 of the License, or
   7    (at your option) any later version.
   8 
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Jim Meyering.  */
  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 /* Support for settings like TZ='<+00>0' was added in IEEE Std 1003.1-2001.  */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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   /* Input parameters.  */
 115   struct tzalloc_test *tza;
 116   time_t t;
 117 
 118   /* Expected result.  */
 119   char const *exp;
 120 
 121   /* Determines if an incorrectly unset tm_isdst
 122      results in failure or just a warning.  */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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, &LT[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           /* Don't fail for unhandled dst in ahistorical entries,
 207              as gnulib doesn't currently fix that issue, seen on Darwin 14.  */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222   int result = 0;
 223   size_t mon;
 224 
 225   /* Check %q.  */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 Local Variables:
 341 indent-tabs-mode: nil
 342 End:
 343 */

/* [previous][next][first][last][top][bottom][index][help] */