maint: update all copyright year number ranges
[gnulib.git] / tests / test-pipe.c
index c542509..93b4866 100644 (file)
@@ -1,5 +1,5 @@
-/* Test of create_pipe_bidi/wait_subprocess.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+/* Test of pipe.
+   Copyright (C) 2009-2013 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
    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, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
-#include "pipe.h"
-#include "wait-process.h"
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (pipe, int, (int[2]));
 
-#include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Depending on arguments, this test intentionally closes stderr or
-   starts life with stderr closed.  So, the error messages might not
-   always print, but at least the exit status will be reliable.  */
-#define ASSERT(expr) \
-  do                                                                         \
-    {                                                                        \
-      if (!(expr))                                                           \
-        {                                                                    \
-          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
-          fflush (stderr);                                                   \
-          abort ();                                                          \
-        }                                                                    \
-    }                                                                        \
-  while (0)
-
-/* Code executed by the child process.  argv[1] = "child".  */
-static int
-child_main (int argc, char *argv[])
-{
-  char buffer[1];
-  int i;
-  int fd;
 
-  ASSERT (argc == 3);
-
-  /* Read one byte from fd 0, and write its value plus one to fd 1.
-     fd 2 should be closed iff the argument is 1.  Check that no other file
-     descriptors leaked.  */
-
-  ASSERT (read (STDIN_FILENO, buffer, 1) == 1);
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Get declarations of the native Windows API functions.  */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+/* Get _get_osfhandle.  */
+# include "msvc-nothrow.h"
+#endif
 
-  buffer[0]++;
-  ASSERT (write (STDOUT_FILENO, buffer, 1) == 1);
+#include "binary-io.h"
+#include "macros.h"
 
-  errno = 0;
-#ifdef F_GETFL
-  /* Try to keep stderr open for better diagnostics.  */
-  i = fcntl (STDERR_FILENO, F_GETFL);
+/* Return true if FD is open.  */
+static bool
+is_open (int fd)
+{
+#if (defined _WIN32 || 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
-  /* But allow compilation on mingw.  You might need to disable this code for
-     debugging failures.  */
-  i = close (STDERR_FILENO);
+# ifndef F_GETFL
+#  error Please port fcntl to your platform
+# endif
+  return 0 <= fcntl (fd, F_GETFL);
 #endif
-  switch (atoi (argv[2]))
-    {
-    case 0:
-      /* Expect fd 2 was open.  */
-      ASSERT (i >= 0);
-      break;
-    case 1:
-      /* Expect fd 2 was closed.  */
-      ASSERT (i < 0);
-      ASSERT (errno == EBADF);
-      break;
-    default:
-      ASSERT (false);
-    }
-
-  for (fd = 3; fd < 7; fd++)
-    {
-      errno = 0;
-      ASSERT (close (fd) == -1);
-      ASSERT (errno == EBADF);
-    }
-
-  return 0;
 }
 
-/* Create a bi-directional pipe to a test child, and validate that the
-   child program returns the expected output.  The child is the same
-   program as the parent ARGV0, but with different arguments.
-   STDERR_CLOSED is true if we have already closed fd 2.  */
-static void
-test_pipe (const char *argv0, bool stderr_closed)
+/* Return true if FD is not inherited to child processes.  */
+static bool
+is_cloexec (int fd)
 {
-  int fd[2];
-  char *argv[4];
-  pid_t pid;
-  char buffer[2] = { 'a', 't' };
-
-  /* Set up child.  */
-  argv[0] = (char *) argv0;
-  argv[1] = (char *) "child";
-  argv[2] = (char *) (stderr_closed ? "1" : "0");
-  argv[3] = NULL;
-  pid = create_pipe_bidi (argv0, argv0, argv, false, true, true, fd);
-  ASSERT (0 <= pid);
-  ASSERT (STDERR_FILENO < fd[0]);
-  ASSERT (STDERR_FILENO < fd[1]);
-
-  /* Push child's input.  */
-  ASSERT (write (fd[1], buffer, 1) == 1);
-
-  /* Get child's output.  */
-  ASSERT (read (fd[0], buffer, 2) == 1);
-
-  /* Wait for child.  */
-  ASSERT (wait_subprocess (pid, argv0, true, false, true, true, NULL) == 0);
-  ASSERT (close (fd[0]) == 0);
-  ASSERT (close (fd[1]) == 0);
-
-  /* Check the result.  */
-  ASSERT (buffer[0] == 'b');
-  ASSERT (buffer[1] == 't');
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+  HANDLE h = (HANDLE) _get_osfhandle (fd);
+  DWORD flags;
+  ASSERT (GetHandleInformation (h, &flags));
+  return (flags & HANDLE_FLAG_INHERIT) == 0;
+#else
+  int flags;
+  ASSERT ((flags = fcntl (fd, F_GETFD)) >= 0);
+  return (flags & FD_CLOEXEC) != 0;
+#endif
 }
 
-/* Code executed by the parent process.  */
-static int
-parent_main (int argc, char *argv[])
+/* Return true if FD is in non-blocking mode.  */
+static bool
+is_nonblocking (int fd)
 {
-  int test;
-  int fd;
-
-  ASSERT (argc == 2);
-
-  /* Selectively close various standard fds, to verify the child process is
-     not impacted by this.  */
-  test = atoi (argv[1]);
-  switch (test)
-    {
-    case 0:
-      break;
-    case 1:
-      close (0);
-      break;
-    case 2:
-      close (1);
-      break;
-    case 3:
-      close (0);
-      close (1);
-      break;
-    case 4:
-      close (2);
-      break;
-    case 5:
-      close (0);
-      close (2);
-      break;
-    case 6:
-      close (1);
-      close (2);
-      break;
-    case 7:
-      close (0);
-      close (1);
-      close (2);
-      break;
-    default:
-      ASSERT (false);
-    }
-
-  /* Plug any file descriptor leaks inherited from outside world before
-     starting, so that child has a clean slate (at least for the fds that we
-     might be manipulating).  */
-  for (fd = 3; fd < 7; fd++)
-    close (fd);
-
-  test_pipe (argv[0], test >= 4);
-
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+  /* We don't use the non-blocking mode for sockets here.  */
   return 0;
+#else
+  int flags;
+  ASSERT ((flags = fcntl (fd, F_GETFL)) >= 0);
+  return (flags & O_NONBLOCK) != 0;
+#endif
 }
 
 int
-main (int argc, char *argv[])
+main ()
 {
-  ASSERT (argc >= 2);
-  if (strcmp (argv[1], "child") == 0)
-    return child_main (argc, argv);
-  else
-    return parent_main (argc, argv);
+  int fd[2];
+
+  fd[0] = -1;
+  fd[1] = -1;
+  ASSERT (pipe (fd) >= 0);
+  ASSERT (fd[0] >= 0);
+  ASSERT (fd[1] >= 0);
+  ASSERT (fd[0] != fd[1]);
+  ASSERT (is_open (fd[0]));
+  ASSERT (is_open (fd[1]));
+  ASSERT (!is_cloexec (fd[0]));
+  ASSERT (!is_cloexec (fd[1]));
+  ASSERT (!is_nonblocking (fd[0]));
+  ASSERT (!is_nonblocking (fd[1]));
+
+  return 0;
 }