Paul Eggert wrote:
> * tests/test-linkat.c (main): Don’t lose the failure results of
> earlier tests.  Problem found by Coverity.

The same problem exists on a few more tests. Fixed by the first
patch below.

The second patch is a simple refactoring.


2024-05-25  Bruno Haible  <br...@clisp.org>

        tests: Refactor.
        * tests/test-inttostr.c (main): Report SKIP in the 'if' branch.
        * tests/test-quotearg.c (main): Likewise.

2024-05-25  Bruno Haible  <br...@clisp.org>

        tests: Before declaring a SKIP, test if there were ASSERT failures.
        * HACKING: Document idiom to use with test_exit_status.
        * tests/test-c32isalnum.c (main): If there were ASSERT failures, report
        them instead of declaring SKIP.
        * tests/test-c32isalpha.c (main): Likewise.
        * tests/test-c32isblank.c (main): Likewise.
        * tests/test-c32iscntrl.c (main): Likewise.
        * tests/test-c32isdigit.c (main): Likewise.
        * tests/test-c32isgraph.c (main): Likewise.
        * tests/test-c32islower.c (main): Likewise.
        * tests/test-c32isprint.c (main): Likewise.
        * tests/test-c32ispunct.c (main): Likewise.
        * tests/test-c32isspace.c (main): Likewise.
        * tests/test-c32isupper.c (main): Likewise.
        * tests/test-c32isxdigit.c (main): Likewise.
        * tests/test-c32rtomb.c (main): Likewise.
        * tests/test-c32rtomb-w32.c (main): Likewise.
        * tests/test-c32snrtombs.c (main): Likewise.
        * tests/test-c32srtombs.c (main): Likewise.
        * tests/test-c32stombs.c (main): Likewise.
        * tests/test-c32tolower.c (main): Likewise.
        * tests/test-c32toupper.c (main): Likewise.
        * tests/test-canonicalize.c (main): Likewise.
        * tests/test-canonicalize-lgpl.c (main): Likewise.
        * tests/test-duplocale.c (main): Likewise.
        * tests/test-fbufmode.c (main): Likewise.
        * tests/test-fenv-except-state-3.c (main): Likewise.
        * tests/test-fenv-except-trapping-1.c (main): Likewise.
        * tests/test-fenv-except-trapping-2.c (main): Likewise.
        * tests/test-fnmatch.c (main): Likewise.
        * tests/test-fnmatch-w32.c (main): Likewise.
        * tests/test-fpurge.c (main): Likewise.
        * tests/test-freadable.c (main): Likewise.
        * tests/test-fseek.c (main): Likewise.
        * tests/test-fseeko.c (main): Likewise.
        * tests/test-ftell.c (main): Likewise.
        * tests/test-ftell3.c (main): Likewise.
        * tests/test-ftello.c (main): Likewise.
        * tests/test-ftello3.c (main): Likewise.
        * tests/test-fwritable.c (main): Likewise.
        * tests/test-fwriting.c (main): Likewise.
        * tests/test-getrandom.c (main): Likewise.
        * tests/test-mbrlen-w32.c (main): Likewise.
        * tests/test-mbrtoc16.c (main): Likewise.
        * tests/test-mbrtoc16-w32.c (main): Likewise.
        * tests/test-mbrtoc32.c (main): Likewise.
        * tests/test-mbrtoc32-w32.c (main): Likewise.
        * tests/test-mbrtowc-w32.c (main): Likewise.
        * tests/test-mbsnrtoc32s.c (main): Likewise.
        * tests/test-mbsrtoc32s.c (main): Likewise.
        * tests/test-mbstoc32s.c (main): Likewise.
        * tests/test-nl_langinfo2.c (main): Likewise.
        * tests/test-nstrftime.c (main): Likewise.
        * tests/test-passfd.c (main): Likewise.
        * tests/test-posix_spawn-script.c (main): Likewise.
        * tests/test-posix_spawnp-script.c (main): Likewise.
        * tests/test-ptsname.c (main): Likewise.
        * tests/test-ptsname_r.c (main): Likewise.
        * tests/test-remove.c (main): Likewise.
        * tests/test-strfmon_l.c (main): Likewise.
        * tests/test-utime.c (main): Likewise.
        * tests/test-wcrtomb-w32.c (main): Likewise.
        * tests/test-execute-script.c (main): Obey CONTINUE_AFTER_ASSERT better.
        * tests/test-spawn-pipe-script.c (main): Likewise.
        * tests/test-linkat.c (main): Use the common idiom.

>From 6b31906d242d903530cf7acde1ceb2fef07435cd Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 25 May 2024 11:44:21 +0200
Subject: [PATCH 1/2] tests: Before declaring a SKIP, test if there were ASSERT
 failures.

* HACKING: Document idiom to use with test_exit_status.
* tests/test-c32isalnum.c (main): If there were ASSERT failures, report
them instead of declaring SKIP.
* tests/test-c32isalpha.c (main): Likewise.
* tests/test-c32isblank.c (main): Likewise.
* tests/test-c32iscntrl.c (main): Likewise.
* tests/test-c32isdigit.c (main): Likewise.
* tests/test-c32isgraph.c (main): Likewise.
* tests/test-c32islower.c (main): Likewise.
* tests/test-c32isprint.c (main): Likewise.
* tests/test-c32ispunct.c (main): Likewise.
* tests/test-c32isspace.c (main): Likewise.
* tests/test-c32isupper.c (main): Likewise.
* tests/test-c32isxdigit.c (main): Likewise.
* tests/test-c32rtomb.c (main): Likewise.
* tests/test-c32rtomb-w32.c (main): Likewise.
* tests/test-c32snrtombs.c (main): Likewise.
* tests/test-c32srtombs.c (main): Likewise.
* tests/test-c32stombs.c (main): Likewise.
* tests/test-c32tolower.c (main): Likewise.
* tests/test-c32toupper.c (main): Likewise.
* tests/test-canonicalize.c (main): Likewise.
* tests/test-canonicalize-lgpl.c (main): Likewise.
* tests/test-duplocale.c (main): Likewise.
* tests/test-fbufmode.c (main): Likewise.
* tests/test-fenv-except-state-3.c (main): Likewise.
* tests/test-fenv-except-trapping-1.c (main): Likewise.
* tests/test-fenv-except-trapping-2.c (main): Likewise.
* tests/test-fnmatch.c (main): Likewise.
* tests/test-fnmatch-w32.c (main): Likewise.
* tests/test-fpurge.c (main): Likewise.
* tests/test-freadable.c (main): Likewise.
* tests/test-fseek.c (main): Likewise.
* tests/test-fseeko.c (main): Likewise.
* tests/test-ftell.c (main): Likewise.
* tests/test-ftell3.c (main): Likewise.
* tests/test-ftello.c (main): Likewise.
* tests/test-ftello3.c (main): Likewise.
* tests/test-fwritable.c (main): Likewise.
* tests/test-fwriting.c (main): Likewise.
* tests/test-getrandom.c (main): Likewise.
* tests/test-mbrlen-w32.c (main): Likewise.
* tests/test-mbrtoc16.c (main): Likewise.
* tests/test-mbrtoc16-w32.c (main): Likewise.
* tests/test-mbrtoc32.c (main): Likewise.
* tests/test-mbrtoc32-w32.c (main): Likewise.
* tests/test-mbrtowc-w32.c (main): Likewise.
* tests/test-mbsnrtoc32s.c (main): Likewise.
* tests/test-mbsrtoc32s.c (main): Likewise.
* tests/test-mbstoc32s.c (main): Likewise.
* tests/test-nl_langinfo2.c (main): Likewise.
* tests/test-nstrftime.c (main): Likewise.
* tests/test-passfd.c (main): Likewise.
* tests/test-posix_spawn-script.c (main): Likewise.
* tests/test-posix_spawnp-script.c (main): Likewise.
* tests/test-ptsname.c (main): Likewise.
* tests/test-ptsname_r.c (main): Likewise.
* tests/test-remove.c (main): Likewise.
* tests/test-strfmon_l.c (main): Likewise.
* tests/test-utime.c (main): Likewise.
* tests/test-wcrtomb-w32.c (main): Likewise.
* tests/test-execute-script.c (main): Obey CONTINUE_AFTER_ASSERT better.
* tests/test-spawn-pipe-script.c (main): Likewise.
* tests/test-linkat.c (main): Use the common idiom.
---
 ChangeLog                           | 68 +++++++++++++++++++++++++++++
 HACKING                             | 35 +++++++++++++++
 tests/test-c32isalnum.c             |  2 +
 tests/test-c32isalpha.c             |  2 +
 tests/test-c32isblank.c             |  2 +
 tests/test-c32iscntrl.c             |  2 +
 tests/test-c32isdigit.c             |  2 +
 tests/test-c32isgraph.c             |  2 +
 tests/test-c32islower.c             |  2 +
 tests/test-c32isprint.c             |  2 +
 tests/test-c32ispunct.c             |  2 +
 tests/test-c32isspace.c             |  2 +
 tests/test-c32isupper.c             |  2 +
 tests/test-c32isxdigit.c            |  2 +
 tests/test-c32rtomb-w32.c           |  8 +++-
 tests/test-c32rtomb.c               |  2 +
 tests/test-c32snrtombs.c            |  2 +
 tests/test-c32srtombs.c             |  2 +
 tests/test-c32stombs.c              |  2 +
 tests/test-c32tolower.c             |  2 +
 tests/test-c32toupper.c             |  2 +
 tests/test-canonicalize-lgpl.c      |  2 +
 tests/test-canonicalize.c           |  2 +
 tests/test-duplocale.c              |  2 +
 tests/test-execute-script.c         |  5 +--
 tests/test-fbufmode.c               |  2 +
 tests/test-fenv-except-state-3.c    |  2 +
 tests/test-fenv-except-trapping-1.c |  2 +
 tests/test-fenv-except-trapping-2.c |  4 ++
 tests/test-fnmatch-w32.c            |  8 +++-
 tests/test-fnmatch.c                |  2 +
 tests/test-fpurge.c                 |  4 +-
 tests/test-freadable.c              |  2 +
 tests/test-fseek.c                  |  2 +
 tests/test-fseeko.c                 |  2 +
 tests/test-ftell.c                  |  2 +
 tests/test-ftell3.c                 |  4 +-
 tests/test-ftello.c                 |  2 +
 tests/test-ftello3.c                |  4 +-
 tests/test-fwritable.c              |  2 +
 tests/test-fwriting.c               |  2 +
 tests/test-getrandom.c              |  2 +
 tests/test-linkat.c                 | 12 +++--
 tests/test-mbrlen-w32.c             |  8 +++-
 tests/test-mbrtoc16-w32.c           |  8 +++-
 tests/test-mbrtoc16.c               |  2 +
 tests/test-mbrtoc32-w32.c           |  8 +++-
 tests/test-mbrtoc32.c               |  2 +
 tests/test-mbrtowc-w32.c            |  8 +++-
 tests/test-mbsnrtoc32s.c            |  2 +
 tests/test-mbsrtoc32s.c             |  2 +
 tests/test-mbstoc32s.c              |  2 +
 tests/test-nl_langinfo2.c           |  2 +
 tests/test-nstrftime.c              |  2 +
 tests/test-passfd.c                 |  2 +
 tests/test-posix_spawn-script.c     |  2 +
 tests/test-posix_spawnp-script.c    |  2 +
 tests/test-ptsname.c                |  6 +++
 tests/test-ptsname_r.c              |  6 +++
 tests/test-remove.c                 |  2 +
 tests/test-spawn-pipe-script.c      |  5 +--
 tests/test-strfmon_l.c              |  4 ++
 tests/test-utime.c                  |  2 +
 tests/test-wcrtomb-w32.c            |  8 +++-
 64 files changed, 273 insertions(+), 30 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0a6def457d..105b051e44 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,71 @@
+2024-05-25  Bruno Haible  <br...@clisp.org>
+
+	tests: Before declaring a SKIP, test if there were ASSERT failures.
+	* HACKING: Document idiom to use with test_exit_status.
+	* tests/test-c32isalnum.c (main): If there were ASSERT failures, report
+	them instead of declaring SKIP.
+	* tests/test-c32isalpha.c (main): Likewise.
+	* tests/test-c32isblank.c (main): Likewise.
+	* tests/test-c32iscntrl.c (main): Likewise.
+	* tests/test-c32isdigit.c (main): Likewise.
+	* tests/test-c32isgraph.c (main): Likewise.
+	* tests/test-c32islower.c (main): Likewise.
+	* tests/test-c32isprint.c (main): Likewise.
+	* tests/test-c32ispunct.c (main): Likewise.
+	* tests/test-c32isspace.c (main): Likewise.
+	* tests/test-c32isupper.c (main): Likewise.
+	* tests/test-c32isxdigit.c (main): Likewise.
+	* tests/test-c32rtomb.c (main): Likewise.
+	* tests/test-c32rtomb-w32.c (main): Likewise.
+	* tests/test-c32snrtombs.c (main): Likewise.
+	* tests/test-c32srtombs.c (main): Likewise.
+	* tests/test-c32stombs.c (main): Likewise.
+	* tests/test-c32tolower.c (main): Likewise.
+	* tests/test-c32toupper.c (main): Likewise.
+	* tests/test-canonicalize.c (main): Likewise.
+	* tests/test-canonicalize-lgpl.c (main): Likewise.
+	* tests/test-duplocale.c (main): Likewise.
+	* tests/test-fbufmode.c (main): Likewise.
+	* tests/test-fenv-except-state-3.c (main): Likewise.
+	* tests/test-fenv-except-trapping-1.c (main): Likewise.
+	* tests/test-fenv-except-trapping-2.c (main): Likewise.
+	* tests/test-fnmatch.c (main): Likewise.
+	* tests/test-fnmatch-w32.c (main): Likewise.
+	* tests/test-fpurge.c (main): Likewise.
+	* tests/test-freadable.c (main): Likewise.
+	* tests/test-fseek.c (main): Likewise.
+	* tests/test-fseeko.c (main): Likewise.
+	* tests/test-ftell.c (main): Likewise.
+	* tests/test-ftell3.c (main): Likewise.
+	* tests/test-ftello.c (main): Likewise.
+	* tests/test-ftello3.c (main): Likewise.
+	* tests/test-fwritable.c (main): Likewise.
+	* tests/test-fwriting.c (main): Likewise.
+	* tests/test-getrandom.c (main): Likewise.
+	* tests/test-mbrlen-w32.c (main): Likewise.
+	* tests/test-mbrtoc16.c (main): Likewise.
+	* tests/test-mbrtoc16-w32.c (main): Likewise.
+	* tests/test-mbrtoc32.c (main): Likewise.
+	* tests/test-mbrtoc32-w32.c (main): Likewise.
+	* tests/test-mbrtowc-w32.c (main): Likewise.
+	* tests/test-mbsnrtoc32s.c (main): Likewise.
+	* tests/test-mbsrtoc32s.c (main): Likewise.
+	* tests/test-mbstoc32s.c (main): Likewise.
+	* tests/test-nl_langinfo2.c (main): Likewise.
+	* tests/test-nstrftime.c (main): Likewise.
+	* tests/test-passfd.c (main): Likewise.
+	* tests/test-posix_spawn-script.c (main): Likewise.
+	* tests/test-posix_spawnp-script.c (main): Likewise.
+	* tests/test-ptsname.c (main): Likewise.
+	* tests/test-ptsname_r.c (main): Likewise.
+	* tests/test-remove.c (main): Likewise.
+	* tests/test-strfmon_l.c (main): Likewise.
+	* tests/test-utime.c (main): Likewise.
+	* tests/test-wcrtomb-w32.c (main): Likewise.
+	* tests/test-execute-script.c (main): Obey CONTINUE_AFTER_ASSERT better.
+	* tests/test-spawn-pipe-script.c (main): Likewise.
+	* tests/test-linkat.c (main): Use the common idiom.
+
 2024-05-24  Collin Funk  <collin.fu...@gmail.com>
 
 	readutmp: Fix dependencies.
diff --git a/HACKING b/HACKING
index 964b880d20..34c3adf033 100644
--- a/HACKING
+++ b/HACKING
@@ -76,6 +76,41 @@ Test Suite
 When adding a module, add a unit test module as well.  This is our best
 chance to catch portability problems.
 
+A unit test can have many sub-tests. Try to make the sub-tests independent
+of each other, so that it becomes easy to disable some sub-tests by enclosing
+them in #if 0 ... #endif.
+
+The main() function's exit code meaning is:
+  - 0: PASS
+  - 77: SKIP; you should print the reason why the test is skipped.
+  - 99: ERROR, i.e. test framework error
+  - any other exit code < 126: FAIL
+
+In tests that #include "macros.h" and use the ASSERT macro:
+The main() function should, before it returns 0 (for PASS) or 77 (for SKIP)
+test the value of test_exit_status and return that instead. So:
+  - not
+        return 0;
+    but instead
+        return test_exit_status;
+  - not
+        return result; // where result can be 0 or 1
+    but instead
+        return (result ? result : test_exit_status);
+  - not
+        fputs ("Skipping test: <reason>\n", stderr);
+        return 77;
+    but instead
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
+        fputs ("Skipping test: <reason>\n", stderr);
+        return 77;
+    Only at the beginning of the main() function, when ASSERT has not yet been
+    invoked, we know that test_exit_status must be zero and can therefore write
+        fputs ("Skipping test: <reason>\n", stderr);
+        return 77;
+    directly.
+
 
 Maintaining high quality
 ========================
diff --git a/tests/test-c32isalnum.c b/tests/test-c32isalnum.c
index b35c2a1f20..d5f8dcf5d2 100644
--- a/tests/test-c32isalnum.c
+++ b/tests/test-c32isalnum.c
@@ -213,6 +213,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32isalpha.c b/tests/test-c32isalpha.c
index 3e177d8c8d..1e5431eae0 100644
--- a/tests/test-c32isalpha.c
+++ b/tests/test-c32isalpha.c
@@ -211,6 +211,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32isblank.c b/tests/test-c32isblank.c
index be4fde3350..3aa6a28b7c 100644
--- a/tests/test-c32isblank.c
+++ b/tests/test-c32isblank.c
@@ -170,6 +170,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32iscntrl.c b/tests/test-c32iscntrl.c
index a00209a5ac..6933cb1068 100644
--- a/tests/test-c32iscntrl.c
+++ b/tests/test-c32iscntrl.c
@@ -172,6 +172,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32isdigit.c b/tests/test-c32isdigit.c
index 3d950ee181..44cca8f024 100644
--- a/tests/test-c32isdigit.c
+++ b/tests/test-c32isdigit.c
@@ -184,6 +184,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32isgraph.c b/tests/test-c32isgraph.c
index 1ea9f782b5..0198fc7a32 100644
--- a/tests/test-c32isgraph.c
+++ b/tests/test-c32isgraph.c
@@ -195,6 +195,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32islower.c b/tests/test-c32islower.c
index 2fae4006e6..4075e2dd11 100644
--- a/tests/test-c32islower.c
+++ b/tests/test-c32islower.c
@@ -268,6 +268,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32isprint.c b/tests/test-c32isprint.c
index cab10ddbe9..0d66989668 100644
--- a/tests/test-c32isprint.c
+++ b/tests/test-c32isprint.c
@@ -198,6 +198,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32ispunct.c b/tests/test-c32ispunct.c
index 8d96f03b9c..ee21852601 100644
--- a/tests/test-c32ispunct.c
+++ b/tests/test-c32ispunct.c
@@ -266,6 +266,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32isspace.c b/tests/test-c32isspace.c
index c5ce347891..9409bb695c 100644
--- a/tests/test-c32isspace.c
+++ b/tests/test-c32isspace.c
@@ -166,6 +166,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32isupper.c b/tests/test-c32isupper.c
index a824747f66..4856f3eb66 100644
--- a/tests/test-c32isupper.c
+++ b/tests/test-c32isupper.c
@@ -260,6 +260,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32isxdigit.c b/tests/test-c32isxdigit.c
index 68d1ce7697..c9c5da5711 100644
--- a/tests/test-c32isxdigit.c
+++ b/tests/test-c32isxdigit.c
@@ -201,6 +201,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32rtomb-w32.c b/tests/test-c32rtomb-w32.c
index ad08859d04..f474776c90 100644
--- a/tests/test-c32rtomb-w32.c
+++ b/tests/test-c32rtomb-w32.c
@@ -330,8 +330,12 @@ main (int argc, char *argv[])
     }
 
   if (result == 77)
-    fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
-             codepage);
+    {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
+      fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
+               codepage);
+    }
   return (result ? result : test_exit_status);
 }
 
diff --git a/tests/test-c32rtomb.c b/tests/test-c32rtomb.c
index b54de70aa6..c02657c630 100644
--- a/tests/test-c32rtomb.c
+++ b/tests/test-c32rtomb.c
@@ -157,6 +157,8 @@ main (int argc, char *argv[])
       case '5':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32snrtombs.c b/tests/test-c32snrtombs.c
index 26b2dd8ef6..7bb2709c3a 100644
--- a/tests/test-c32snrtombs.c
+++ b/tests/test-c32snrtombs.c
@@ -161,6 +161,8 @@ main (int argc, char *argv[])
         case '5':
           /* Locale encoding is GB18030.  */
           #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+          if (test_exit_status != EXIT_SUCCESS)
+            return test_exit_status;
           fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
           return 77;
           #endif
diff --git a/tests/test-c32srtombs.c b/tests/test-c32srtombs.c
index 7153f4f1c0..3a36aaeee8 100644
--- a/tests/test-c32srtombs.c
+++ b/tests/test-c32srtombs.c
@@ -161,6 +161,8 @@ main (int argc, char *argv[])
         case '5':
           /* Locale encoding is GB18030.  */
           #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+          if (test_exit_status != EXIT_SUCCESS)
+            return test_exit_status;
           fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
           return 77;
           #endif
diff --git a/tests/test-c32stombs.c b/tests/test-c32stombs.c
index 0b7f78812e..62f77342e4 100644
--- a/tests/test-c32stombs.c
+++ b/tests/test-c32stombs.c
@@ -140,6 +140,8 @@ main (int argc, char *argv[])
         case '5':
           /* Locale encoding is GB18030.  */
           #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+          if (test_exit_status != EXIT_SUCCESS)
+            return test_exit_status;
           fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
           return 77;
           #endif
diff --git a/tests/test-c32tolower.c b/tests/test-c32tolower.c
index fd017edb86..eb956b5009 100644
--- a/tests/test-c32tolower.c
+++ b/tests/test-c32tolower.c
@@ -337,6 +337,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-c32toupper.c b/tests/test-c32toupper.c
index 740ccdca18..d0c2ba634a 100644
--- a/tests/test-c32toupper.c
+++ b/tests/test-c32toupper.c
@@ -349,6 +349,8 @@ main (int argc, char *argv[])
       case '4':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-canonicalize-lgpl.c b/tests/test-canonicalize-lgpl.c
index e388154d55..769f7c3968 100644
--- a/tests/test-canonicalize-lgpl.c
+++ b/tests/test-canonicalize-lgpl.c
@@ -157,6 +157,8 @@ main (void)
     {
       ASSERT (remove (BASE "/tra") == 0);
       ASSERT (rmdir (BASE) == 0);
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       fputs ("skipping test: symlinks not supported on this file system\n",
              stderr);
       return 77;
diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c
index cdd428259d..0224c2bbcf 100644
--- a/tests/test-canonicalize.c
+++ b/tests/test-canonicalize.c
@@ -181,6 +181,8 @@ main (void)
     {
       ASSERT (remove (BASE "/tra") == 0);
       ASSERT (rmdir (BASE) == 0);
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       fputs ("skipping test: symlinks not supported on this file system\n",
              stderr);
       return 77;
diff --git a/tests/test-duplocale.c b/tests/test-duplocale.c
index 803772b662..a27f1378f0 100644
--- a/tests/test-duplocale.c
+++ b/tests/test-duplocale.c
@@ -226,6 +226,8 @@ main ()
 
   if (skipped)
     {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       fprintf (stderr, "Skipping test: Spanish Unicode locale is not installed\n");
       return 77;
     }
diff --git a/tests/test-execute-script.c b/tests/test-execute-script.c
index b9d381d573..dfb9d8c259 100644
--- a/tests/test-execute-script.c
+++ b/tests/test-execute-script.c
@@ -63,14 +63,13 @@ main ()
       }
   }
 
-  if (test_exit_status)
-    return test_exit_status;
-
 #if defined _WIN32 && !defined __CYGWIN__
   /* On native Windows, scripts - even with '#!' marker - are not executable.
      Only .bat and .cmd files are.  */
   ASSERT (fclose (fp) == 0);
   ASSERT (unlink (DATA_FILENAME) == 0);
+  if (test_exit_status)
+    return test_exit_status;
   fprintf (stderr, "Skipping test: scripts are not executable on this platform.\n");
   return 77;
 #else
diff --git a/tests/test-fbufmode.c b/tests/test-fbufmode.c
index 20ca02a15c..a726ab53db 100644
--- a/tests/test-fbufmode.c
+++ b/tests/test-fbufmode.c
@@ -102,6 +102,8 @@ main ()
   return ret;
 
  skip:
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fprintf (stderr, "Skipping test: file operations failed.\n");
   return 77;
 }
diff --git a/tests/test-fenv-except-state-3.c b/tests/test-fenv-except-state-3.c
index 7298be4007..ad4d81d52b 100644
--- a/tests/test-fenv-except-state-3.c
+++ b/tests/test-fenv-except-state-3.c
@@ -60,6 +60,8 @@ main ()
      terminates the program.  */
   if (sigfpe_on_invalid () < 0)
     {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       fputs ("Skipping test: trapping floating-point exceptions are not supported on this machine.\n", stderr);
       return 77;
     }
diff --git a/tests/test-fenv-except-trapping-1.c b/tests/test-fenv-except-trapping-1.c
index 2fde5587fa..8d9f3e9111 100644
--- a/tests/test-fenv-except-trapping-1.c
+++ b/tests/test-fenv-except-trapping-1.c
@@ -57,6 +57,8 @@ main ()
         if (fedisableexcept (FE_ALL_EXCEPT) == -1
             || feenableexcept (uint_to_exceptions (a)) == -1)
           {
+            if (test_exit_status != EXIT_SUCCESS)
+              return test_exit_status;
             fputs ("Skipping test: trapping floating-point exceptions are not supported on this machine.\n", stderr);
             return 77;
           }
diff --git a/tests/test-fenv-except-trapping-2.c b/tests/test-fenv-except-trapping-2.c
index d97567bc1e..166454080e 100644
--- a/tests/test-fenv-except-trapping-2.c
+++ b/tests/test-fenv-except-trapping-2.c
@@ -492,6 +492,8 @@ main (int argc, char *argv[])
       #endif
       if (known_failure)
         {
+          if (test_exit_status != EXIT_SUCCESS)
+            return test_exit_status;
           fputs ("Skipping test: known failure on this platform\n", stderr);
           return 77;
         }
@@ -510,6 +512,8 @@ main (int argc, char *argv[])
   return test_exit_status;
 
  skip:
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fputs ("Skipping test: trapping floating-point exceptions are not supported on this machine.\n", stderr);
   return 77;
 }
diff --git a/tests/test-fnmatch-w32.c b/tests/test-fnmatch-w32.c
index 486e7fe217..7f15855535 100644
--- a/tests/test-fnmatch-w32.c
+++ b/tests/test-fnmatch-w32.c
@@ -392,8 +392,12 @@ main (int argc, char *argv[])
     }
 
   if (result == 77)
-    fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
-             codepage);
+    {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
+      fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
+               codepage);
+    }
   return (result ? result : test_exit_status);
 }
 
diff --git a/tests/test-fnmatch.c b/tests/test-fnmatch.c
index 96e2d1f949..87fc4145f7 100644
--- a/tests/test-fnmatch.c
+++ b/tests/test-fnmatch.c
@@ -854,6 +854,8 @@ main (int argc, char *argv[])
       case '5':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15)
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-fpurge.c b/tests/test-fpurge.c
index 07663e2e76..ac3ddb5010 100644
--- a/tests/test-fpurge.c
+++ b/tests/test-fpurge.c
@@ -128,7 +128,9 @@ main (void)
   return test_exit_status;
 
  skip:
-  fprintf (stderr, "Skipping test: prerequisite file operations failed.\n");
   remove (TESTFILE);
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
+  fprintf (stderr, "Skipping test: prerequisite file operations failed.\n");
   return 77;
 }
diff --git a/tests/test-freadable.c b/tests/test-freadable.c
index 1122053611..734b411187 100644
--- a/tests/test-freadable.c
+++ b/tests/test-freadable.c
@@ -112,6 +112,8 @@ main ()
   return test_exit_status;
 
  skip:
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fprintf (stderr, "Skipping test: file operations failed.\n");
   return 77;
 }
diff --git a/tests/test-fseek.c b/tests/test-fseek.c
index f33cdb4a45..f1d398851a 100644
--- a/tests/test-fseek.c
+++ b/tests/test-fseek.c
@@ -52,6 +52,8 @@ main (int argc, char **argv)
         {
           if (FUNC_UNGETC_BROKEN)
             {
+              if (test_exit_status != EXIT_SUCCESS)
+                return test_exit_status;
               fputs ("Skipping test: ungetc cannot handle arbitrary bytes\n",
                      stderr);
               return 77;
diff --git a/tests/test-fseeko.c b/tests/test-fseeko.c
index a251333b95..c6f132d6d0 100644
--- a/tests/test-fseeko.c
+++ b/tests/test-fseeko.c
@@ -56,6 +56,8 @@ main (int argc, _GL_UNUSED char **argv)
         {
           if (FUNC_UNGETC_BROKEN)
             {
+              if (test_exit_status != EXIT_SUCCESS)
+                return test_exit_status;
               fputs ("Skipping test: ungetc cannot handle arbitrary bytes\n",
                      stderr);
               return 77;
diff --git a/tests/test-ftell.c b/tests/test-ftell.c
index 34bbd0ccbe..3951acfc7e 100644
--- a/tests/test-ftell.c
+++ b/tests/test-ftell.c
@@ -82,6 +82,8 @@ main (int argc, char **argv)
     {
       if (FUNC_UNGETC_BROKEN)
         {
+          if (test_exit_status != EXIT_SUCCESS)
+            return test_exit_status;
           fputs ("Skipping test: ungetc cannot handle arbitrary bytes\n",
                  stderr);
           return 77;
diff --git a/tests/test-ftell3.c b/tests/test-ftell3.c
index 44540fde2f..5e777d1e7c 100644
--- a/tests/test-ftell3.c
+++ b/tests/test-ftell3.c
@@ -72,7 +72,9 @@ main (void)
   return test_exit_status;
 
  skip:
-  fprintf (stderr, "Skipping test: prerequisite file operations failed.\n");
   remove (TESTFILE);
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
+  fprintf (stderr, "Skipping test: prerequisite file operations failed.\n");
   return 77;
 }
diff --git a/tests/test-ftello.c b/tests/test-ftello.c
index 62dbac43c4..bafb7fa7e3 100644
--- a/tests/test-ftello.c
+++ b/tests/test-ftello.c
@@ -90,6 +90,8 @@ main (int argc, _GL_UNUSED char **argv)
     {
       if (FUNC_UNGETC_BROKEN)
         {
+          if (test_exit_status != EXIT_SUCCESS)
+            return test_exit_status;
           fputs ("Skipping test: ungetc cannot handle arbitrary bytes\n",
                  stderr);
           return 77;
diff --git a/tests/test-ftello3.c b/tests/test-ftello3.c
index e5174fd2b6..6874784643 100644
--- a/tests/test-ftello3.c
+++ b/tests/test-ftello3.c
@@ -72,7 +72,9 @@ main (void)
   return test_exit_status;
 
  skip:
-  fprintf (stderr, "Skipping test: prerequisite file operations failed.\n");
   remove (TESTFILE);
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
+  fprintf (stderr, "Skipping test: prerequisite file operations failed.\n");
   return 77;
 }
diff --git a/tests/test-fwritable.c b/tests/test-fwritable.c
index ef1539ff9c..f5b5f87687 100644
--- a/tests/test-fwritable.c
+++ b/tests/test-fwritable.c
@@ -112,6 +112,8 @@ main ()
   return test_exit_status;
 
  skip:
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fprintf (stderr, "Skipping test: file operations failed.\n");
   return 77;
 }
diff --git a/tests/test-fwriting.c b/tests/test-fwriting.c
index 4c1ff18c24..4ccf428cce 100644
--- a/tests/test-fwriting.c
+++ b/tests/test-fwriting.c
@@ -159,6 +159,8 @@ main ()
   return test_exit_status;
 
  skip:
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fprintf (stderr, "Skipping test: file operations failed.\n");
   return 77;
 }
diff --git a/tests/test-getrandom.c b/tests/test-getrandom.c
index 0102ffa24e..a658bf098c 100644
--- a/tests/test-getrandom.c
+++ b/tests/test-getrandom.c
@@ -84,6 +84,8 @@ main (void)
   if (getrandom (buf1, 1, 0) < 1)
     if (getrandom (buf1, 1, GRND_RANDOM) < 1)
       {
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: getrandom is ineffective\n", stderr);
         return 77;
       }
diff --git a/tests/test-linkat.c b/tests/test-linkat.c
index 04814ddd1b..eb7ac4e556 100644
--- a/tests/test-linkat.c
+++ b/tests/test-linkat.c
@@ -202,13 +202,11 @@ main (void)
       ASSERT (rmdir (BASE "sub1") == 0);
       ASSERT (rmdir (BASE "sub2") == 0);
       free (cwd);
-      if (!test_exit_status)
-        {
-          fputs ("skipping test: symlinks not supported on this file system\n",
-                 stderr);
-          return 77;
-        }
-      return test_exit_status;
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
+      fputs ("skipping test: symlinks not supported on this file system\n",
+             stderr);
+      return 77;
     }
   dfd = open (".", O_RDONLY);
   ASSERT (0 <= dfd);
diff --git a/tests/test-mbrlen-w32.c b/tests/test-mbrlen-w32.c
index cb0802a677..4f1415dedb 100644
--- a/tests/test-mbrlen-w32.c
+++ b/tests/test-mbrlen-w32.c
@@ -546,8 +546,12 @@ main (int argc, char *argv[])
     }
 
   if (result == 77)
-    fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
-             codepage);
+    {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
+      fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
+               codepage);
+    }
   return (result ? result : test_exit_status);
 }
 
diff --git a/tests/test-mbrtoc16-w32.c b/tests/test-mbrtoc16-w32.c
index 0aa23a721a..36528483a3 100644
--- a/tests/test-mbrtoc16-w32.c
+++ b/tests/test-mbrtoc16-w32.c
@@ -755,8 +755,12 @@ main (int argc, char *argv[])
     }
 
   if (result == 77)
-    fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
-             codepage);
+    {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
+      fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
+               codepage);
+    }
   return (result ? result : test_exit_status);
 }
 
diff --git a/tests/test-mbrtoc16.c b/tests/test-mbrtoc16.c
index 5bb769fd26..25b39fc22c 100644
--- a/tests/test-mbrtoc16.c
+++ b/tests/test-mbrtoc16.c
@@ -362,6 +362,8 @@ main (int argc, char *argv[])
       case '5':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-mbrtoc32-w32.c b/tests/test-mbrtoc32-w32.c
index 1ec7c99666..07f4d3ccf9 100644
--- a/tests/test-mbrtoc32-w32.c
+++ b/tests/test-mbrtoc32-w32.c
@@ -731,8 +731,12 @@ main (int argc, char *argv[])
     }
 
   if (result == 77)
-    fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
-             codepage);
+    {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
+      fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
+               codepage);
+    }
   return (result ? result : test_exit_status);
 }
 
diff --git a/tests/test-mbrtoc32.c b/tests/test-mbrtoc32.c
index b1c50c963c..b26c7888a2 100644
--- a/tests/test-mbrtoc32.c
+++ b/tests/test-mbrtoc32.c
@@ -388,6 +388,8 @@ main (int argc, char *argv[])
       case '5':
         /* Locale encoding is GB18030.  */
         #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
         return 77;
         #endif
diff --git a/tests/test-mbrtowc-w32.c b/tests/test-mbrtowc-w32.c
index 2edd5660ab..832f3672fc 100644
--- a/tests/test-mbrtowc-w32.c
+++ b/tests/test-mbrtowc-w32.c
@@ -715,8 +715,12 @@ main (int argc, char *argv[])
     }
 
   if (result == 77)
-    fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
-             codepage);
+    {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
+      fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
+               codepage);
+    }
   return (result ? result : test_exit_status);
 }
 
diff --git a/tests/test-mbsnrtoc32s.c b/tests/test-mbsnrtoc32s.c
index 63776aad37..79237b7398 100644
--- a/tests/test-mbsnrtoc32s.c
+++ b/tests/test-mbsnrtoc32s.c
@@ -316,6 +316,8 @@ main (int argc, char *argv[])
             case '5':
               /* Locale encoding is GB18030.  */
               #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+              if (test_exit_status != EXIT_SUCCESS)
+                return test_exit_status;
               fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
               return 77;
               #endif
diff --git a/tests/test-mbsrtoc32s.c b/tests/test-mbsrtoc32s.c
index 066cfbc215..35d87a2e46 100644
--- a/tests/test-mbsrtoc32s.c
+++ b/tests/test-mbsrtoc32s.c
@@ -316,6 +316,8 @@ main (int argc, char *argv[])
             case '5':
               /* Locale encoding is GB18030.  */
               #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+              if (test_exit_status != EXIT_SUCCESS)
+                return test_exit_status;
               fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
               return 77;
               #endif
diff --git a/tests/test-mbstoc32s.c b/tests/test-mbstoc32s.c
index 987e18ee56..c481dc3354 100644
--- a/tests/test-mbstoc32s.c
+++ b/tests/test-mbstoc32s.c
@@ -264,6 +264,8 @@ main (int argc, char *argv[])
             case '5':
               /* Locale encoding is GB18030.  */
               #if (defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 13 && __GLIBC_MINOR__ <= 15) || (GL_CHAR32_T_IS_UNICODE && (defined __FreeBSD__ || defined __NetBSD__ || defined __sun))
+              if (test_exit_status != EXIT_SUCCESS)
+                return test_exit_status;
               fputs ("Skipping test: The GB18030 converter in this system's iconv is broken.\n", stderr);
               return 77;
               #endif
diff --git a/tests/test-nl_langinfo2.c b/tests/test-nl_langinfo2.c
index 7fe8e1d451..fd3ebbde1e 100644
--- a/tests/test-nl_langinfo2.c
+++ b/tests/test-nl_langinfo2.c
@@ -134,6 +134,8 @@ main (int argc, char *argv[])
 
   if (skipped_all)
     {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       fputs ("Skipping test: French locale is not installed\n", stderr);
       return 77;
     }
diff --git a/tests/test-nstrftime.c b/tests/test-nstrftime.c
index 391bb72c14..c363eea067 100644
--- a/tests/test-nstrftime.c
+++ b/tests/test-nstrftime.c
@@ -61,6 +61,8 @@ main (void)
 #if MUSL_LIBC
       if (fail == 0)
         {
+          if (test_exit_status != EXIT_SUCCESS)
+            return test_exit_status;
           fputs ("Skipping test: musl libc does not come with localizations\n",
                  stderr);
           return 77;
diff --git a/tests/test-passfd.c b/tests/test-passfd.c
index 86623a6da8..72dcd83b71 100644
--- a/tests/test-passfd.c
+++ b/tests/test-passfd.c
@@ -140,6 +140,8 @@ main ()
   ASSERT(recvfd (0, 0) == -1);
   ASSERT(errno == ENOSYS);
 
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fputs ("skipping test: socketpair not supported on this system\n",
          stderr);
   return 77;
diff --git a/tests/test-posix_spawn-script.c b/tests/test-posix_spawn-script.c
index 287ab52072..e00b38da07 100644
--- a/tests/test-posix_spawn-script.c
+++ b/tests/test-posix_spawn-script.c
@@ -93,6 +93,8 @@ main ()
 #if defined _WIN32 && !defined __CYGWIN__
   /* On native Windows, scripts - even with '#!' marker - are not executable.
      Only .bat and .cmd files are.  */
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fprintf (stderr, "Skipping test: scripts are not executable on this platform.\n");
   return 77;
 #else
diff --git a/tests/test-posix_spawnp-script.c b/tests/test-posix_spawnp-script.c
index d1ed9d9a18..160d5d8c91 100644
--- a/tests/test-posix_spawnp-script.c
+++ b/tests/test-posix_spawnp-script.c
@@ -93,6 +93,8 @@ main ()
 #if defined _WIN32 && !defined __CYGWIN__
   /* On native Windows, scripts - even with '#!' marker - are not executable.
      Only .bat and .cmd files are.  */
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fprintf (stderr, "Skipping test: scripts are not executable on this platform.\n");
   return 77;
 #else
diff --git a/tests/test-ptsname.c b/tests/test-ptsname.c
index bbeeb0a1a3..934a12f2a1 100644
--- a/tests/test-ptsname.c
+++ b/tests/test-ptsname.c
@@ -87,6 +87,8 @@ main (void)
     fd = open ("/dev/tty", O_RDONLY);
     if (fd < 0)
       {
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fprintf (stderr, "Skipping test: cannot open controlling tty\n");
         return 77;
       }
@@ -114,6 +116,8 @@ main (void)
     fd = open ("/dev/ptmx", O_RDWR | O_NOCTTY);
     if (fd < 0)
       {
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fprintf (stderr, "Skipping test: cannot open pseudo-terminal\n");
         return 77;
       }
@@ -142,6 +146,8 @@ main (void)
     fd = open ("/dev/ptc", O_RDWR | O_NOCTTY);
     if (fd < 0)
       {
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fprintf (stderr, "Skipping test: cannot open pseudo-terminal\n");
         return 77;
       }
diff --git a/tests/test-ptsname_r.c b/tests/test-ptsname_r.c
index 04e27f007b..5e89dfa249 100644
--- a/tests/test-ptsname_r.c
+++ b/tests/test-ptsname_r.c
@@ -136,6 +136,8 @@ main (void)
     fd = open ("/dev/tty", O_RDONLY);
     if (fd < 0)
       {
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fprintf (stderr, "Skipping test: cannot open controlling tty\n");
         return 77;
       }
@@ -164,6 +166,8 @@ main (void)
     fd = open ("/dev/ptmx", O_RDWR | O_NOCTTY);
     if (fd < 0)
       {
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fprintf (stderr, "Skipping test: cannot open pseudo-terminal\n");
         return 77;
       }
@@ -195,6 +199,8 @@ main (void)
     fd = open ("/dev/ptc", O_RDWR | O_NOCTTY);
     if (fd < 0)
       {
+        if (test_exit_status != EXIT_SUCCESS)
+          return test_exit_status;
         fprintf (stderr, "Skipping test: cannot open pseudo-terminal\n");
         return 77;
       }
diff --git a/tests/test-remove.c b/tests/test-remove.c
index 3d0645fbbe..91e7524e2d 100644
--- a/tests/test-remove.c
+++ b/tests/test-remove.c
@@ -86,6 +86,8 @@ main (void)
      symlink.  */
   if (symlink (BASE "dir", BASE "link") != 0)
     {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       fputs ("skipping test: symlinks not supported on this file system\n",
              stderr);
       return 77;
diff --git a/tests/test-spawn-pipe-script.c b/tests/test-spawn-pipe-script.c
index 744e2054d5..07b06c1b29 100644
--- a/tests/test-spawn-pipe-script.c
+++ b/tests/test-spawn-pipe-script.c
@@ -67,12 +67,11 @@ main ()
       }
   }
 
-  if (test_exit_status != EXIT_SUCCESS)
-    return test_exit_status;
-
 #if defined _WIN32 && !defined __CYGWIN__
   /* On native Windows, scripts - even with '#!' marker - are not executable.
      Only .bat and .cmd files are.  */
+  if (test_exit_status != EXIT_SUCCESS)
+    return test_exit_status;
   fprintf (stderr, "Skipping test: scripts are not executable on this platform.\n");
   return 77;
 #else
diff --git a/tests/test-strfmon_l.c b/tests/test-strfmon_l.c
index 80147c188d..c9a7544932 100644
--- a/tests/test-strfmon_l.c
+++ b/tests/test-strfmon_l.c
@@ -55,11 +55,15 @@ main (void)
      glibc bug <https://sourceware.org/bugzilla/show_bug.cgi?id=19633>.  */
   if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
     {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       fprintf (stderr, "Skipping test: English Unicode locale is not installed\n");
       return 77;
     }
   if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
     {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       fprintf (stderr, "Skipping test: English Unicode locale is not installed\n");
       return 77;
     }
diff --git a/tests/test-utime.c b/tests/test-utime.c
index 63fbe20eba..00cee63265 100644
--- a/tests/test-utime.c
+++ b/tests/test-utime.c
@@ -100,6 +100,8 @@ test_utime (bool print)
   if (symlink (BASE "file", BASE "link"))
     {
       ASSERT (unlink (BASE "file") == 0);
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
       if (print)
         fputs ("skipping test: symlinks not supported on this file system\n",
                stderr);
diff --git a/tests/test-wcrtomb-w32.c b/tests/test-wcrtomb-w32.c
index b2b8f35cab..d275ec46d7 100644
--- a/tests/test-wcrtomb-w32.c
+++ b/tests/test-wcrtomb-w32.c
@@ -318,8 +318,12 @@ main (int argc, char *argv[])
     }
 
   if (result == 77)
-    fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
-             codepage);
+    {
+      if (test_exit_status != EXIT_SUCCESS)
+        return test_exit_status;
+      fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
+               codepage);
+    }
   return (result ? result : test_exit_status);
 }
 
-- 
2.34.1

>From 44802b6a6f8c82ad53d1cd43d4d7a2fbbf9910d2 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 25 May 2024 11:46:11 +0200
Subject: [PATCH 2/2] tests: Refactor.

* tests/test-inttostr.c (main): Report SKIP in the 'if' branch.
* tests/test-quotearg.c (main): Likewise.
---
 ChangeLog             |  6 ++++++
 tests/test-inttostr.c | 21 +++++++++++----------
 tests/test-quotearg.c | 36 ++++++++++++++++++------------------
 3 files changed, 35 insertions(+), 28 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 105b051e44..ea87d0d68d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-05-25  Bruno Haible  <br...@clisp.org>
+
+	tests: Refactor.
+	* tests/test-inttostr.c (main): Report SKIP in the 'if' branch.
+	* tests/test-quotearg.c (main): Likewise.
+
 2024-05-25  Bruno Haible  <br...@clisp.org>
 
 	tests: Before declaring a SKIP, test if there were ASSERT failures.
diff --git a/tests/test-inttostr.c b/tests/test-inttostr.c
index e7632cb736..e85025ed9e 100644
--- a/tests/test-inttostr.c
+++ b/tests/test-inttostr.c
@@ -76,19 +76,20 @@ main (void)
   /* Ideally we would rely on the snprintf-posix module, in which case
      this guard would not be required, but due to limitations in gnulib's
      implementation (see modules/snprintf-posix), we cannot.  */
-  if (snprintf (b, b_size, "%ju", (uintmax_t) 3) == 1
-      && b[0] == '3' && b[1] == '\0')
+  if (!(snprintf (b, b_size, "%ju", (uintmax_t) 3) == 1
+        && b[0] == '3' && b[1] == '\0'))
     {
-      CK (int,          inttostr);
-      CK (unsigned int, uinttostr);
-      CK (off_t,        offtostr);
-      CK (uintmax_t,    umaxtostr);
-      CK (intmax_t,     imaxtostr);
+      /* snprintf doesn't accept %ju; skip this test.  */
       free (b);
-      return test_exit_status;
+      fputs ("Skipping test: %ju format directive not supported\n", stderr);
+      return 77;
     }
 
-  /* snprintf doesn't accept %ju; skip this test.  */
+  CK (int,          inttostr);
+  CK (unsigned int, uinttostr);
+  CK (off_t,        offtostr);
+  CK (uintmax_t,    umaxtostr);
+  CK (intmax_t,     imaxtostr);
   free (b);
-  return 77;
+  return test_exit_status;
 }
diff --git a/tests/test-quotearg.c b/tests/test-quotearg.c
index d454b5acd8..0283f1ca1c 100644
--- a/tests/test-quotearg.c
+++ b/tests/test-quotearg.c
@@ -75,30 +75,30 @@ main (_GL_UNUSED int argc, char *argv[])
   {
     const char *locale_name = getenv ("LOCALE");
 
-    if (locale_name != NULL && strcmp (locale_name, "none") != 0
-        && setenv ("LC_ALL", locale_name, 1) == 0
-        && setlocale (LC_ALL, "") != NULL)
+    if (!(locale_name != NULL && strcmp (locale_name, "none") != 0
+          && setenv ("LC_ALL", locale_name, 1) == 0
+          && setlocale (LC_ALL, "") != NULL))
       {
-        textdomain ("test-quotearg");
-        bindtextdomain ("test-quotearg", getenv ("LOCALEDIR"));
+        fputs ("Skipping test: no french Unicode locale is installed\n", stderr);
+        return 77;
+      }
+    textdomain ("test-quotearg");
+    bindtextdomain ("test-quotearg", getenv ("LOCALEDIR"));
 
-        set_quoting_style (NULL, locale_quoting_style);
-        compare_strings (use_quotearg_buffer, &locale_results[0].group1, false);
-        compare_strings (use_quotearg, &locale_results[0].group2, false);
-        compare_strings (use_quotearg_colon, &locale_results[0].group3, false);
+    set_quoting_style (NULL, locale_quoting_style);
+    compare_strings (use_quotearg_buffer, &locale_results[0].group1, false);
+    compare_strings (use_quotearg, &locale_results[0].group2, false);
+    compare_strings (use_quotearg_colon, &locale_results[0].group3, false);
 
-        set_quoting_style (NULL, clocale_quoting_style);
-        compare_strings (use_quotearg_buffer, &locale_results[1].group1, false);
-        compare_strings (use_quotearg, &locale_results[1].group2, false);
-        compare_strings (use_quotearg_colon, &locale_results[1].group3, false);
+    set_quoting_style (NULL, clocale_quoting_style);
+    compare_strings (use_quotearg_buffer, &locale_results[1].group1, false);
+    compare_strings (use_quotearg, &locale_results[1].group2, false);
+    compare_strings (use_quotearg_colon, &locale_results[1].group3, false);
 
-        quotearg_free ();
-        return test_exit_status;
-      }
+    quotearg_free ();
+    return test_exit_status;
   }
 
-  fputs ("Skipping test: no french Unicode locale is installed\n", stderr);
-  return 77;
 #else
   fputs ("Skipping test: internationalization is disabled\n", stderr);
   return 77;
-- 
2.34.1

Reply via email to