Blame time/tst-strptime2.c

Packit 6c4009
/* tst-strptime2 - Test strptime %z timezone offset specifier.  */
Packit 6c4009
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <time.h>
Packit 6c4009
#include <libc-diag.h>
Packit 6c4009
Packit 6c4009
/* Dummy string is used to match strptime's %s specifier.  */
Packit 6c4009
Packit 6c4009
static const char dummy_string[] = "1113472456";
Packit 6c4009
Packit 6c4009
/* buffer_size contains the maximum test string length, including
Packit 6c4009
   trailing NUL.  */
Packit 6c4009
Packit 6c4009
enum
Packit 6c4009
{
Packit 6c4009
  buffer_size = 20,
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Verbose execution, set with --verbose command line option.  */
Packit 6c4009
Packit 6c4009
static bool verbose;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* mkbuf - Write a test string for strptime with the specified time
Packit 6c4009
   value and number of digits into the supplied buffer, and return
Packit 6c4009
   the expected strptime test result.
Packit 6c4009
Packit 6c4009
   The test string, buf, is written with the following content:
Packit 6c4009
     a dummy string matching strptime "%s" format specifier,
Packit 6c4009
     whitespace matching strptime " " format specifier, and
Packit 6c4009
     timezone string matching strptime "%z" format specifier.
Packit 6c4009
Packit 6c4009
   Note that a valid timezone string is either "Z" or contains the
Packit 6c4009
   following fields:
Packit 6c4009
     Sign field consisting of a '+' or '-' sign,
Packit 6c4009
     Hours field in two decimal digits, and
Packit 6c4009
     optional Minutes field in two decimal digits. Optionally,
Packit 6c4009
     a ':' is used to seperate hours and minutes.
Packit 6c4009
Packit 6c4009
   This function may write test strings with minutes values outside
Packit 6c4009
   the valid range 00-59.  These are invalid strings and useful for
Packit 6c4009
   testing strptime's rejection of invalid strings.
Packit 6c4009
Packit 6c4009
   The ndigits parameter is used to limit the number of timezone
Packit 6c4009
   string digits to be written and may range from 0 to 4.  Note that
Packit 6c4009
   only 2 and 4 digit strings are valid input to strptime; strings
Packit 6c4009
   with 0, 1 or 3 digits are invalid and useful for testing strptime's
Packit 6c4009
   rejection of invalid strings.
Packit 6c4009
Packit 6c4009
   This function returns the behavior expected of strptime resulting
Packit 6c4009
   from parsing the the test string.  For valid strings, the function
Packit 6c4009
   returns the expected tm_gmtoff value.  For invalid strings,
Packit 6c4009
   LONG_MAX is returned.  LONG_MAX indicates the expectation that
Packit 6c4009
   strptime will return NULL; for example, if the number of digits
Packit 6c4009
   are not correct, or minutes part of the time is outside the valid
Packit 6c4009
   range of 00 to 59.  */
Packit 6c4009
Packit 6c4009
static long int
Packit 6c4009
mkbuf (char *buf, bool neg, bool colon, unsigned int hhmm, size_t ndigits)
Packit 6c4009
{
Packit 6c4009
  const int mm_max = 59;
Packit 6c4009
  char sign = neg ? '-' : '+';
Packit 6c4009
  int i;
Packit 6c4009
  unsigned int hh = hhmm / 100;
Packit 6c4009
  unsigned int mm = hhmm % 100;
Packit 6c4009
  long int expect = LONG_MAX;
Packit 6c4009
Packit 6c4009
  i = sprintf (buf, "%s %c", dummy_string, sign);
Packit 6c4009
#if __GNUC_PREREQ (7, 0)
Packit 6c4009
  /* GCC issues a warning when it thinks the snprintf buffer may be too short.
Packit 6c4009
     This test is explicitly using short buffers to force snprintf to truncate
Packit 6c4009
     the output so we ignore the warnings.  */
Packit 6c4009
  DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
  DIAG_IGNORE_NEEDS_COMMENT (7.0, "-Wformat-truncation");
Packit 6c4009
#endif
Packit 6c4009
  if (colon)
Packit 6c4009
    snprintf (buf + i, ndigits + 2, "%02u:%02u", hh, mm);
Packit 6c4009
  else
Packit 6c4009
    snprintf (buf + i, ndigits + 1, "%04u", hhmm);
Packit 6c4009
#if __GNUC_PREREQ (7, 0)
Packit 6c4009
  DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  if (mm <= mm_max && (ndigits == 2 || ndigits == 4))
Packit 6c4009
    {
Packit 6c4009
      long int tm_gmtoff = hh * 3600 + mm * 60;
Packit 6c4009
Packit 6c4009
      expect = neg ? -tm_gmtoff : tm_gmtoff;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return expect;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Write a description of expected or actual test result to stdout.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
describe (bool string_valid, long int tm_gmtoff)
Packit 6c4009
{
Packit 6c4009
  if (string_valid)
Packit 6c4009
    printf ("valid, tm.tm_gmtoff %ld", tm_gmtoff);
Packit 6c4009
  else
Packit 6c4009
    printf ("invalid, return value NULL");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Using buffer buf, run strptime.  Compare results against expect,
Packit 6c4009
  the expected result.  Report failures and verbose results to stdout.
Packit 6c4009
  Update the result counts.  Return 1 if test failed, 0 if passed.  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
compare (const char *buf, long int expect, unsigned int *nresult)
Packit 6c4009
{
Packit 6c4009
  struct tm tm;
Packit 6c4009
  char *p;
Packit 6c4009
  bool test_string_valid;
Packit 6c4009
  long int test_result;
Packit 6c4009
  bool fail;
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
  p = strptime (buf, "%s %z", &tm;;
Packit 6c4009
  test_string_valid = p != NULL;
Packit 6c4009
  test_result = test_string_valid ? tm.tm_gmtoff : LONG_MAX;
Packit 6c4009
  fail = test_result != expect;
Packit 6c4009
Packit 6c4009
  if (fail || verbose)
Packit 6c4009
    {
Packit 6c4009
      bool expect_string_valid = expect != LONG_MAX;
Packit 6c4009
Packit 6c4009
      printf ("%s: input \"%s\", expected: ", fail ? "FAIL" : "PASS", buf);
Packit 6c4009
      describe (expect_string_valid, expect);
Packit 6c4009
Packit 6c4009
      if (fail)
Packit 6c4009
	{
Packit 6c4009
	  printf (", got: ");
Packit 6c4009
	  describe (test_string_valid, test_result);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      printf ("\n");
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  result = fail ? 1 : 0;
Packit 6c4009
  nresult[result]++;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  char buf[buffer_size];
Packit 6c4009
  long int expect;
Packit 6c4009
  int result = 0;
Packit 6c4009
  /* Number of tests run with passing (index==0) and failing (index==1)
Packit 6c4009
     results.  */
Packit 6c4009
  unsigned int nresult[2];
Packit 6c4009
  unsigned int ndigits;
Packit 6c4009
  unsigned int step;
Packit 6c4009
  unsigned int hhmm;
Packit 6c4009
Packit 6c4009
  nresult[0] = 0;
Packit 6c4009
  nresult[1] = 0;
Packit 6c4009
Packit 6c4009
  /* Create and test input string with no sign and four digits input
Packit 6c4009
     (invalid format).  */
Packit 6c4009
Packit 6c4009
  sprintf (buf, "%s  1030", dummy_string);
Packit 6c4009
  expect = LONG_MAX;
Packit 6c4009
  result |= compare (buf, expect, nresult);
Packit 6c4009
Packit 6c4009
  /* Create and test input string with "Z" input (valid format).
Packit 6c4009
     Expect tm_gmtoff of 0.  */
Packit 6c4009
Packit 6c4009
  sprintf (buf, "%s Z", dummy_string);
Packit 6c4009
  expect = 0;
Packit 6c4009
  result |= compare (buf, expect, nresult);
Packit 6c4009
Packit 6c4009
  /* Create and test input strings with sign and digits:
Packit 6c4009
     0 digits (invalid format),
Packit 6c4009
     1 digit (invalid format),
Packit 6c4009
     2 digits (valid format),
Packit 6c4009
     3 digits (invalid format),
Packit 6c4009
     4 digits (valid format if and only if minutes is in range 00-59,
Packit 6c4009
	       otherwise invalid).
Packit 6c4009
     If format is valid, the returned tm_gmtoff is checked.  */
Packit 6c4009
Packit 6c4009
  for (ndigits = 0, step = 10000; ndigits <= 4; ndigits++, step /= 10)
Packit 6c4009
    for (hhmm = 0; hhmm <= 9999; hhmm += step)
Packit 6c4009
      {
Packit 6c4009
	/* Test both positive and negative signs.  */
Packit 6c4009
Packit 6c4009
	expect = mkbuf (buf, false, false, hhmm, ndigits);
Packit 6c4009
	result |= compare (buf, expect, nresult);
Packit 6c4009
Packit 6c4009
	expect = mkbuf (buf, true, false, hhmm, ndigits);
Packit 6c4009
	result |= compare (buf, expect, nresult);
Packit 6c4009
Packit 6c4009
	/* Test with colon as well.  */
Packit 6c4009
Packit 6c4009
	if (ndigits >= 3)
Packit 6c4009
	  {
Packit 6c4009
	    expect = mkbuf (buf, false, true, hhmm, ndigits);
Packit 6c4009
	    result |= compare (buf, expect, nresult);
Packit 6c4009
Packit 6c4009
	    expect = mkbuf (buf, true, true, hhmm, ndigits);
Packit 6c4009
	    result |= compare (buf, expect, nresult);
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  if (result > 0 || verbose)
Packit 6c4009
    printf ("%s: %u input strings: %u fail, %u pass\n",
Packit 6c4009
	    result > 0 ? "FAIL" : "PASS",
Packit 6c4009
	    nresult[1] + nresult[0], nresult[1], nresult[0]);
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Add a "--verbose" command line option to test-skeleton.c.  */
Packit 6c4009
Packit 6c4009
#define OPT_VERBOSE 10000
Packit 6c4009
Packit 6c4009
#define CMDLINE_OPTIONS \
Packit 6c4009
  { "verbose", no_argument, NULL, OPT_VERBOSE, },
Packit 6c4009
Packit 6c4009
#define CMDLINE_PROCESS \
Packit 6c4009
  case OPT_VERBOSE: \
Packit 6c4009
    verbose = true; \
Packit 6c4009
    break;
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"