(root)/
glibc-2.38/
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"