summaryrefslogtreecommitdiff
path: root/tests/test-execute-child.c
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2020-11-29 21:27:57 +0100
committerBruno Haible <bruno@clisp.org>2020-11-29 21:34:04 +0100
commitd43e61a65dcba77cbfddb96b19847daced7ef426 (patch)
tree23d4e805b5184f399d29dabdcd2defbfc9ee20cd /tests/test-execute-child.c
parenta5a7a76caa23695c8b8229e48366cba980291cb4 (diff)
downloadgnulib-d43e61a65dcba77cbfddb96b19847daced7ef426.tar.gz
execute: Add tests.
* tests/test-execute.sh: New file. * tests/test-execute-main.c: New file. * tests/test-execute-child.c: New file. * modules/execute-tests: New file.
Diffstat (limited to 'tests/test-execute-child.c')
-rw-r--r--tests/test-execute-child.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/tests/test-execute-child.c b/tests/test-execute-child.c
new file mode 100644
index 0000000000..2994476bb7
--- /dev/null
+++ b/tests/test-execute-child.c
@@ -0,0 +1,176 @@
+/* Child program invoked by test-execute-main.
+ Copyright (C) 2009-2020 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, 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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if defined _WIN32 && ! defined __CYGWIN__
+/* Get declarations of the native Windows API functions. */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+/* Get _get_osfhandle. */
+# include <io.h>
+#endif
+
+/* In this file, we use only system functions, no overrides from gnulib. */
+#undef atoi
+#undef fcntl
+#undef fflush
+#undef fgetc
+#undef fprintf
+#undef fputs
+#undef fstat
+#undef raise
+#undef sprintf
+#undef stat
+#undef strcmp
+#undef strlen
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+static void __cdecl
+gl_msvc_invalid_parameter_handler (const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
+ unsigned int line,
+ uintptr_t dummy)
+{
+}
+#endif
+
+/* Return non-zero if FD is open. */
+static int
+is_open (int fd)
+{
+#if defined _WIN32 && ! defined __CYGWIN__
+ /* On native Windows, the initial state of unassigned standard file
+ descriptors is that they are open but point to an
+ INVALID_HANDLE_VALUE, and there is no fcntl. */
+ return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
+#else
+# ifndef F_GETFL
+# error Please port fcntl to your platform
+# endif
+ return 0 <= fcntl (fd, F_GETFL);
+#endif
+}
+
+int
+main (int argc, char *argv[])
+{
+ if (argc == 1)
+ /* Check an invocation without arguments. Check the exit code. */
+ return 40;
+
+ int test = atoi (argv[1]);
+ switch (test)
+ {
+ case 2:
+ /* Check argument passing. */
+ return !(argc == 12
+ && strcmp (argv[2], "abc def") == 0
+ && strcmp (argv[3], "abc\"def\"ghi") == 0
+ && strcmp (argv[4], "xyz\"") == 0
+ && strcmp (argv[5], "abc\\def\\ghi") == 0
+ && strcmp (argv[6], "xyz\\") == 0
+ && strcmp (argv[7], "???") == 0
+ && strcmp (argv[8], "***") == 0
+ && strcmp (argv[9], "") == 0
+ && strcmp (argv[10], "foo") == 0
+ && strcmp (argv[11], "") == 0);
+ #if !(defined _WIN32 && !defined __CYGWIN__)
+ case 3:
+ /* Check SIGPIPE handling with ignore_sigpipe = false. */
+ case 4:
+ /* Check SIGPIPE handling with ignore_sigpipe = true. */
+ raise (SIGPIPE);
+ return 71;
+ #endif
+ case 5:
+ /* Check other signal. */
+ raise (SIGINT);
+ return 71;
+ case 6:
+ /* Check stdin is inherited. */
+ return !(fgetc (stdin) == 'F' && fgetc (stdin) == 'o');
+ case 7:
+ /* Check null_stdin = true. */
+ return !(fgetc (stdin) == EOF);
+ case 8:
+ /* Check stdout is inherited, part 1 (regular file). */
+ return !(fputs ("bar", stdout) != EOF && fflush (stdout) == 0);
+ case 9:
+ /* Check stdout is inherited, part 2 (device). */
+ case 10:
+ /* Check null_stdout = true. */
+ {
+ struct stat st;
+ return !(fstat (STDOUT_FILENO, &st) >= 0 && !S_ISREG (st.st_mode));
+ }
+ case 11:
+ /* Check stderr is inherited, part 1 (regular file). */
+ return !(fputs ("bar", stderr) != EOF && fflush (stderr) == 0);
+ case 12:
+ /* Check stderr is inherited, part 2 (device). */
+ case 13:
+ /* Check null_stderr = true. */
+ {
+ struct stat st;
+ return !(fstat (STDERR_FILENO, &st) >= 0 && !S_ISREG (st.st_mode));
+ }
+ case 14:
+ case 15:
+ /* Check file descriptors >= 3 can be inherited. */
+ case 16:
+ /* Check file descriptors >= 3 with O_CLOEXEC bit are not inherited. */
+ #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+ /* Avoid exceptions from within _get_osfhandle. */
+ _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
+ #endif
+ {
+ char buf[300];
+ buf[0] = '\0';
+ char *p = buf;
+ int fd;
+ for (fd = 0; fd < 20; fd++)
+ #ifdef __NetBSD__
+ if (fd != 3)
+ #endif
+ if (is_open (fd))
+ {
+ sprintf (p, "%d ", fd);
+ p += strlen (p);
+ }
+ const char *expected = (test < 16 ? "0 1 2 10 " : "0 1 2 ");
+ if (strcmp (buf, expected) == 0)
+ return 0;
+ else
+ {
+ fprintf (stderr, "Test case %d: %s\n", test, buf); fflush (stderr);
+ return 1;
+ }
+ }
+ default:
+ abort ();
+ }
+}