From: Bruno Haible Date: Wed, 7 Feb 2024 11:38:44 +0000 (+0100) Subject: nstrftime tests: Allow reuse with another function. X-Git-Tag: v1.0~460 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=f0abcb6594f6ec1e5e479ea64ce844d521797332;p=gnulib.git nstrftime tests: Allow reuse with another function. * tests/test-nstrftime.h: New file, extracted from tests/test-nstrftime.c. (FUNC_NAME, STRINGIFY): New macros. (posixtm_test, tzalloc_test, quarter_test, errno_test): Use FUNC or FUNC_NAME instead of nstrftime. (quarter_test): Rename local variable 'result' to 'fail'. * tests/test-nstrftime.c: Remove code that moved to test-nstrftime.h. Include test-nstrftime.h. (STREQ): Remove redundant macro. * modules/nstrftime-tests (Files): Add tests/test-nstrftime.h. --- diff --git a/ChangeLog b/ChangeLog index 94a0090245..f2402e602c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2024-02-07 Bruno Haible + + nstrftime tests: Allow reuse with another function. + * tests/test-nstrftime.h: New file, extracted from + tests/test-nstrftime.c. + (FUNC_NAME, STRINGIFY): New macros. + (posixtm_test, tzalloc_test, quarter_test, errno_test): Use FUNC or + FUNC_NAME instead of nstrftime. + (quarter_test): Rename local variable 'result' to 'fail'. + * tests/test-nstrftime.c: Remove code that moved to test-nstrftime.h. + Include test-nstrftime.h. + (STREQ): Remove redundant macro. + * modules/nstrftime-tests (Files): Add tests/test-nstrftime.h. + 2024-02-07 Bruno Haible nstrftime: Document the nstrftime function. diff --git a/modules/nstrftime-tests b/modules/nstrftime-tests index ed2430accd..b30ebbbbae 100644 --- a/modules/nstrftime-tests +++ b/modules/nstrftime-tests @@ -1,5 +1,6 @@ Files: tests/test-nstrftime.c +tests/test-nstrftime.h tests/macros.h Depends-on: diff --git a/tests/test-nstrftime.c b/tests/test-nstrftime.c index 8b9c7797dc..3a76298f5e 100644 --- a/tests/test-nstrftime.c +++ b/tests/test-nstrftime.c @@ -30,300 +30,9 @@ #include #include "macros.h" -#define STREQ(a, b) (strcmp (a, b) == 0) -/* Support for settings like TZ='<+00>0' was added in IEEE Std 1003.1-2001. */ -#define TZ_ANGLE_BRACKETS_SHOULD_WORK (200112 <= _POSIX_VERSION) - -struct posixtm_test -{ - time_t in; - int in_ns; - char const *fmt; - char const *exp; -}; - -static struct posixtm_test const T[] = - { - { 1300000000, 0, "%F", "2011-03-13" }, - { 0, 10, "%T.%N", "00:00:00.000000010" }, - { 56, 123456789, "%T.%12N", "00:00:56.123456789000" }, - { 0, 0, NULL, NULL } - }; - -static int -posixtm_test (void) -{ - int fail = 0; - unsigned int i; - - for (i = 0; T[i].fmt; i++) - { - char buf[1000]; - time_t t = T[i].in; - struct tm *tm = gmtime (&t); - size_t n; - - ASSERT (tm); - - n = nstrftime (buf, sizeof buf, T[i].fmt, tm, 0, T[i].in_ns); - if (n == 0) - { - fail = 1; - printf ("nstrftime failed with format %s\n", T[i].fmt); - } - - if (! STREQ (buf, T[i].exp)) - { - fail = 1; - printf ("%s: result mismatch: got %s, expected %s\n", - T[i].fmt, buf, T[i].exp); - } - } - - return fail; -} - -struct tzalloc_test -{ - timezone_t tz; - char const *setting; -}; - -static struct tzalloc_test TZ[] = - { -#define Pacific 0 - { 0, "PST8PDT,M3.2.0,M11.1.0" }, -#define Arizona 1 - { 0, "MST7" }, -#define UTC 2 - { 0, 0 }, -#define CentEur 3 - { 0, "CET-1CEST,M3.5.0,M10.5.0/3" }, -#define Japan 4 - { 0, "JST-9" }, -#define NZ 5 - { 0, "NZST-12NZDT,M9.5.0,M4.1.0/3" }, -#define Unknown 6 - { 0, "<-00>0" }, - { 0 } - }; - -struct localtime_rz_test -{ - /* Input parameters. */ - struct tzalloc_test *tza; - time_t t; - - /* Expected result. */ - char const *exp; - - /* Determines if an incorrectly unset tm_isdst - results in failure or just a warning. */ - int ahistorical; -}; - -static struct localtime_rz_test LT[] = - { - { TZ+Pacific, 0, "1969-12-31 16:00:00 -0800 (PST)", 0 }, - { TZ+Arizona, 0, "1969-12-31 17:00:00 -0700 (MST)", 0 }, - { TZ+UTC , 0, "1970-01-01 00:00:00 +0000 (UTC)", 0 }, - { TZ+CentEur, 0, "1970-01-01 01:00:00 +0100 (CET)", 0 }, - { TZ+Japan , 0, "1970-01-01 09:00:00 +0900 (JST)", 0 }, - { TZ+NZ , 0, "1970-01-01 13:00:00 +1300 (NZDT)", 1 }, - { TZ+Pacific, 500000001, "1985-11-04 16:53:21 -0800 (PST)", 0 }, - { TZ+Arizona, 500000001, "1985-11-04 17:53:21 -0700 (MST)", 0 }, - { TZ+UTC , 500000001, "1985-11-05 00:53:21 +0000 (UTC)", 0 }, - { TZ+CentEur, 500000001, "1985-11-05 01:53:21 +0100 (CET)", 1 }, - { TZ+Japan , 500000001, "1985-11-05 09:53:21 +0900 (JST)", 0 }, - { TZ+NZ , 500000001, "1985-11-05 13:53:21 +1300 (NZDT)", 0 }, - { TZ+Pacific, 1000000002, "2001-09-08 18:46:42 -0700 (PDT)", 0 }, - { TZ+Arizona, 1000000002, "2001-09-08 18:46:42 -0700 (MST)", 0 }, - { TZ+UTC , 1000000002, "2001-09-09 01:46:42 +0000 (UTC)", 0 }, - { TZ+CentEur, 1000000002, "2001-09-09 03:46:42 +0200 (CEST)", 0 }, - { TZ+Japan , 1000000002, "2001-09-09 10:46:42 +0900 (JST)", 0 }, - { TZ+NZ , 1000000002, "2001-09-09 13:46:42 +1200 (NZST)", 0 }, -#if TZ_ANGLE_BRACKETS_SHOULD_WORK - { TZ+Unknown, 0, "1970-01-01 00:00:00 -0000 (-00)", 0 }, - { TZ+Unknown, 500000001, "1985-11-05 00:53:21 -0000 (-00)", 0 }, - { TZ+Unknown, 1000000002, "2001-09-09 01:46:42 -0000 (-00)", 0 }, -#endif - { 0 } - }; - -static int -tzalloc_test (void) -{ - int fail = 0; - int i; - - for (i = 0; LT[i].tza; i++) - { - struct tzalloc_test *tza = LT[i].tza; - long lt = LT[i].t; - timezone_t tz = tza->tz; - char const *setting; - static char const format[] = "%Y-%m-%d %H:%M:%S %z (%Z)"; - char buf[1000]; - struct tm tm; - size_t n; - - if (!tz && tza->setting) - { - tz = tzalloc (tza->setting); - if (!tz) - { - fail = 1; - printf ("%s: tzalloc: %s\n", TZ[i].setting, strerror (errno)); - continue; - } - tza->tz = tz; - } - - setting = tza->setting ? tza->setting : "UTC0"; - - if (!localtime_rz (tz, <[i].t, &tm)) - { - fail = 1; - printf ("%s: %ld: localtime_rz: %s\n", setting, lt, - strerror (errno)); - continue; - } - - n = nstrftime (buf, sizeof buf, format, &tm, tz, 0); - if (n == 0) - { - fail = 1; - printf ("%s: %ld: nstrftime failed\n", setting, lt); - continue; - } - - if (! (STREQ (buf, LT[i].exp) - || (!tz && n == strlen (LT[i].exp) - && memcmp (buf, LT[i].exp, n - sizeof "(GMT)" + 1) == 0 - && STREQ (buf + n - sizeof "(GMT)" + 1, "(GMT)")))) - { - /* Don't fail for unhandled dst in ahistorical entries, - as gnulib doesn't currently fix that issue, seen on Darwin 14. */ - if (!LT[i].ahistorical || tm.tm_isdst) - fail = 1; - printf ("%s: expected \"%s\", got \"%s\"\n", - setting, LT[i].exp, buf); - } - } - - return fail; -} - - -static int -quarter_test (void) -{ - int result = 0; - size_t mon; - - /* Check %q. */ - for (mon = 1; mon <= 12; mon++) - { - char out[2]; - char exp[2] = {0,}; - struct tm qtm = { .tm_mon = mon - 1 }; - char fmt[3] = {'%','q','\0'}; - - size_t r = nstrftime (out, sizeof (out), fmt, &qtm, 0, 0); - if (r == 0) - { - puts ("nstrftime(\"%q\") failed"); - result = 1; - break; - } - - exp[0] = mon < 4 ? '1' : mon < 7 ? '2' : mon < 10 ? '3' : '4'; - if (strcmp (out, exp) != 0) - { - printf ("nstrftime %%q: expected \"%s\", got \"%s\"\n", exp, out); - result = 1; - break; - } - } - - return result; -} - -static int -errno_test (void) -{ - int fail = 0; - struct tm tm = { .tm_year = 2020 - 1900, .tm_mday = 1 }; - char buf[INT_BUFSIZE_BOUND (time_t)]; - size_t n; - int bigyear = LLONG_MAX - 1900 < INT_MAX ? LLONG_MAX - 1900 : INT_MAX; - - errno = 0; - n = nstrftime (buf, 0, "%m", &tm, 0, 0); - if (! (n == 0 && errno == ERANGE)) - { - fail = 1; - printf ("nstrftime failed to set errno = ERANGE\n"); - } - - errno = 0; - n = nstrftime (buf, sizeof buf, "", &tm, 0, 0); - if (! (n == 0 && errno == 0)) - { - fail = 1; - printf ("nstrftime failed to leave errno alone\n"); - } - - - tm.tm_year = bigyear; - errno = 0; - n = nstrftime (buf, sizeof buf, "%s", &tm, 0, 0); - if (n == 0) - { - if (errno != EOVERFLOW) - { - fail = 1; - printf ("nstrftime failed to set errno = EOVERFLOW\n"); - } - - if (mktime_z (0, &tm) != (time_t) -1) - { - fail = 1; - printf ("nstrftime %%s failed but mktime_z worked for tm_year=%d\n", - bigyear); - } - } - else - { - long long int text_seconds = atoll (buf); - if (text_seconds <= (LLONG_MAX - 1 < TYPE_MAXIMUM (time_t) - ? LLONG_MAX - 1 : TYPE_MAXIMUM (time_t))) - { - time_t bigtime = text_seconds; - struct tm *tmp = gmtime (&bigtime); - if (!tmp) - { - fail = 1; - printf ("gmtime failed on nstrftime result\n"); - } - else - { - char buf1[sizeof buf]; - size_t n1 = nstrftime (buf1, sizeof buf1, "%s", tmp, 0, 0); - buf1[n1] = '\0'; - if (! STREQ (buf, buf1)) - { - fail = 1; - printf ("nstrftime %%s first returned '%s', then '%s'\n", - buf, buf1); - } - } - } - } - - return fail; -} +#define FUNC nstrftime +#include "test-nstrftime.h" int main (void) @@ -335,9 +44,3 @@ main (void) fail |= errno_test (); return fail; } - -/* -Local Variables: -indent-tabs-mode: nil -End: -*/ diff --git a/tests/test-nstrftime.h b/tests/test-nstrftime.h new file mode 100644 index 0000000000..7480ddf6d7 --- /dev/null +++ b/tests/test-nstrftime.h @@ -0,0 +1,328 @@ +/* Test of nstrftime-like functions in the "C" locale. + Copyright (C) 2011-2024 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Jim Meyering. */ + +#define FUNC_NAME STRINGIFY(FUNC) +#define STRINGIFY(x) #x + +/* Support for settings like TZ='<+00>0' was added in IEEE Std 1003.1-2001. */ +#define TZ_ANGLE_BRACKETS_SHOULD_WORK (200112 <= _POSIX_VERSION) + +/* -------------------------------------------------------------------------- */ + +struct posixtm_test +{ + time_t in; + int in_ns; + char const *fmt; + char const *exp; +}; + +static struct posixtm_test const T[] = + { + { 1300000000, 0, "%F", "2011-03-13" }, + { 0, 10, "%T.%N", "00:00:00.000000010" }, + { 56, 123456789, "%T.%12N", "00:00:56.123456789000" }, + { 0, 0, NULL, NULL } + }; + +static int +posixtm_test (void) +{ + int fail = 0; + unsigned int i; + + for (i = 0; T[i].fmt; i++) + { + char buf[1000]; + time_t t = T[i].in; + struct tm *tm = gmtime (&t); + size_t n; + + ASSERT (tm); + + n = FUNC (buf, sizeof buf, T[i].fmt, tm, 0, T[i].in_ns); + if (n == 0) + { + fail = 1; + printf ("%s failed with format %s\n", FUNC_NAME, T[i].fmt); + } + + if (! STREQ (buf, T[i].exp)) + { + fail = 1; + printf ("%s: result mismatch: got %s, expected %s\n", + T[i].fmt, buf, T[i].exp); + } + } + + return fail; +} + +/* -------------------------------------------------------------------------- */ + +struct tzalloc_test +{ + timezone_t tz; + char const *setting; +}; + +static struct tzalloc_test TZ[] = + { +#define Pacific 0 + { 0, "PST8PDT,M3.2.0,M11.1.0" }, +#define Arizona 1 + { 0, "MST7" }, +#define UTC 2 + { 0, 0 }, +#define CentEur 3 + { 0, "CET-1CEST,M3.5.0,M10.5.0/3" }, +#define Japan 4 + { 0, "JST-9" }, +#define NZ 5 + { 0, "NZST-12NZDT,M9.5.0,M4.1.0/3" }, +#define Unknown 6 + { 0, "<-00>0" }, + { 0 } + }; + +struct localtime_rz_test +{ + /* Input parameters. */ + struct tzalloc_test *tza; + time_t t; + + /* Expected result. */ + char const *exp; + + /* Determines if an incorrectly unset tm_isdst + results in failure or just a warning. */ + int ahistorical; +}; + +static struct localtime_rz_test LT[] = + { + { TZ+Pacific, 0, "1969-12-31 16:00:00 -0800 (PST)", 0 }, + { TZ+Arizona, 0, "1969-12-31 17:00:00 -0700 (MST)", 0 }, + { TZ+UTC , 0, "1970-01-01 00:00:00 +0000 (UTC)", 0 }, + { TZ+CentEur, 0, "1970-01-01 01:00:00 +0100 (CET)", 0 }, + { TZ+Japan , 0, "1970-01-01 09:00:00 +0900 (JST)", 0 }, + { TZ+NZ , 0, "1970-01-01 13:00:00 +1300 (NZDT)", 1 }, + { TZ+Pacific, 500000001, "1985-11-04 16:53:21 -0800 (PST)", 0 }, + { TZ+Arizona, 500000001, "1985-11-04 17:53:21 -0700 (MST)", 0 }, + { TZ+UTC , 500000001, "1985-11-05 00:53:21 +0000 (UTC)", 0 }, + { TZ+CentEur, 500000001, "1985-11-05 01:53:21 +0100 (CET)", 1 }, + { TZ+Japan , 500000001, "1985-11-05 09:53:21 +0900 (JST)", 0 }, + { TZ+NZ , 500000001, "1985-11-05 13:53:21 +1300 (NZDT)", 0 }, + { TZ+Pacific, 1000000002, "2001-09-08 18:46:42 -0700 (PDT)", 0 }, + { TZ+Arizona, 1000000002, "2001-09-08 18:46:42 -0700 (MST)", 0 }, + { TZ+UTC , 1000000002, "2001-09-09 01:46:42 +0000 (UTC)", 0 }, + { TZ+CentEur, 1000000002, "2001-09-09 03:46:42 +0200 (CEST)", 0 }, + { TZ+Japan , 1000000002, "2001-09-09 10:46:42 +0900 (JST)", 0 }, + { TZ+NZ , 1000000002, "2001-09-09 13:46:42 +1200 (NZST)", 0 }, +#if TZ_ANGLE_BRACKETS_SHOULD_WORK + { TZ+Unknown, 0, "1970-01-01 00:00:00 -0000 (-00)", 0 }, + { TZ+Unknown, 500000001, "1985-11-05 00:53:21 -0000 (-00)", 0 }, + { TZ+Unknown, 1000000002, "2001-09-09 01:46:42 -0000 (-00)", 0 }, +#endif + { 0 } + }; + +static int +tzalloc_test (void) +{ + int fail = 0; + int i; + + for (i = 0; LT[i].tza; i++) + { + struct tzalloc_test *tza = LT[i].tza; + long lt = LT[i].t; + timezone_t tz = tza->tz; + char const *setting; + static char const format[] = "%Y-%m-%d %H:%M:%S %z (%Z)"; + char buf[1000]; + struct tm tm; + size_t n; + + if (!tz && tza->setting) + { + tz = tzalloc (tza->setting); + if (!tz) + { + fail = 1; + printf ("%s: tzalloc: %s\n", TZ[i].setting, strerror (errno)); + continue; + } + tza->tz = tz; + } + + setting = tza->setting ? tza->setting : "UTC0"; + + if (!localtime_rz (tz, <[i].t, &tm)) + { + fail = 1; + printf ("%s: %ld: localtime_rz: %s\n", setting, lt, + strerror (errno)); + continue; + } + + n = FUNC (buf, sizeof buf, format, &tm, tz, 0); + if (n == 0) + { + fail = 1; + printf ("%s: %ld: %s failed\n", setting, lt, FUNC_NAME); + continue; + } + + if (! (STREQ (buf, LT[i].exp) + || (!tz && n == strlen (LT[i].exp) + && memcmp (buf, LT[i].exp, n - sizeof "(GMT)" + 1) == 0 + && STREQ (buf + n - sizeof "(GMT)" + 1, "(GMT)")))) + { + /* Don't fail for unhandled dst in ahistorical entries, + as gnulib doesn't currently fix that issue, seen on Darwin 14. */ + if (!LT[i].ahistorical || tm.tm_isdst) + fail = 1; + printf ("%s: expected \"%s\", got \"%s\"\n", + setting, LT[i].exp, buf); + } + } + + return fail; +} + +/* -------------------------------------------------------------------------- */ + +static int +quarter_test (void) +{ + int fail = 0; + size_t mon; + + /* Check %q. */ + for (mon = 1; mon <= 12; mon++) + { + char out[2]; + char exp[2] = {0,}; + struct tm qtm = { .tm_mon = mon - 1 }; + char fmt[3] = {'%','q','\0'}; + + size_t r = FUNC (out, sizeof (out), fmt, &qtm, 0, 0); + if (r == 0) + { + printf ("%s(\"%%q\") failed\n", FUNC_NAME); + fail = 1; + break; + } + + exp[0] = mon < 4 ? '1' : mon < 7 ? '2' : mon < 10 ? '3' : '4'; + if (strcmp (out, exp) != 0) + { + printf ("%s %%q: expected \"%s\", got \"%s\"\n", FUNC_NAME, exp, out); + fail = 1; + break; + } + } + + return fail; +} + +/* -------------------------------------------------------------------------- */ + +static int +errno_test (void) +{ + int fail = 0; + struct tm tm = { .tm_year = 2020 - 1900, .tm_mday = 1 }; + char buf[INT_BUFSIZE_BOUND (time_t)]; + size_t n; + int bigyear = LLONG_MAX - 1900 < INT_MAX ? LLONG_MAX - 1900 : INT_MAX; + + errno = 0; + n = FUNC (buf, 0, "%m", &tm, 0, 0); + if (! (n == 0 && errno == ERANGE)) + { + fail = 1; + printf ("%s failed to set errno = ERANGE\n", FUNC_NAME); + } + + errno = 0; + n = FUNC (buf, sizeof buf, "", &tm, 0, 0); + if (! (n == 0 && errno == 0)) + { + fail = 1; + printf ("%s failed to leave errno alone\n", FUNC_NAME); + } + + + tm.tm_year = bigyear; + errno = 0; + n = FUNC (buf, sizeof buf, "%s", &tm, 0, 0); + if (n == 0) + { + if (errno != EOVERFLOW) + { + fail = 1; + printf ("%s failed to set errno = EOVERFLOW\n", FUNC_NAME); + } + + if (mktime_z (0, &tm) != (time_t) -1) + { + fail = 1; + printf ("%s %%s failed but mktime_z worked for tm_year=%d\n", + FUNC_NAME, bigyear); + } + } + else + { + long long int text_seconds = atoll (buf); + if (text_seconds <= (LLONG_MAX - 1 < TYPE_MAXIMUM (time_t) + ? LLONG_MAX - 1 : TYPE_MAXIMUM (time_t))) + { + time_t bigtime = text_seconds; + struct tm *tmp = gmtime (&bigtime); + if (!tmp) + { + fail = 1; + printf ("gmtime failed on %s result\n", FUNC_NAME); + } + else + { + char buf1[sizeof buf]; + size_t n1 = FUNC (buf1, sizeof buf1, "%s", tmp, 0, 0); + buf1[n1] = '\0'; + if (! STREQ (buf, buf1)) + { + fail = 1; + printf ("%s %%s first returned '%s', then '%s'\n", + FUNC_NAME, buf, buf1); + } + } + } + } + + return fail; +} + +/* -------------------------------------------------------------------------- */ + +/* +Local Variables: +indent-tabs-mode: nil +End: +*/