gettimeofday: port recent C++ fix to Emacs
[gnulib.git] / tests / test-pipe.c
index 16c72f6..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>
 
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-/* Get declarations of the Win32 API functions.  */
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-#endif
+#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, we arrange to have fd 10
-   (outside the range of interesting fd's during the test) set up to
-   duplicate the original stderr.  */
 
-#define BACKUP_STDERR_FILENO 10
-static FILE *myerr;
+#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
 
-#define ASSERT(expr) \
-  do                                                                         \
-    {                                                                        \
-      if (!(expr))                                                           \
-        {                                                                    \
-          fprintf (myerr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
-          fflush (myerr);                                                    \
-          abort ();                                                          \
-        }                                                                    \
-    }                                                                        \
-  while (0)
+#include "binary-io.h"
+#include "macros.h"
 
-/* Code executed by the child process.  argv[1] = "child".  */
-static int
-child_main (int argc, char *argv[])
+/* Return true if FD is open.  */
+static bool
+is_open (int fd)
 {
-  char buffer[2] = { 's', 't' };
-  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, 2) == 1);
-
-  buffer[0]++;
-  ASSERT (write (STDOUT_FILENO, buffer, 1) == 1);
-
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-  /* On Win32, the initial state of unassigned standard file descriptors is
-     that they are open but point to an INVALID_HANDLE_VALUE.  Thus
-     close (STDERR_FILENO) would always succeed.  */
-  switch (atoi (argv[2]))
-    {
-    case 0:
-      /* Expect fd 2 is open to a valid handle.  */
-      ASSERT ((HANDLE) _get_osfhandle (STDERR_FILENO) != INVALID_HANDLE_VALUE);
-      break;
-    case 1:
-      /* Expect fd 2 is pointing to INVALID_HANDLE_VALUE.  */
-      ASSERT ((HANDLE) _get_osfhandle (STDERR_FILENO) == INVALID_HANDLE_VALUE);
-      break;
-    default:
-      ASSERT (false);
-    }
-#elif defined F_GETFL
-  /* On Unix, the initial state of unassigned standard file descriptors is
-     that they are closed.  */
-  {
-    int ret;
-    errno = 0;
-    ret = fcntl (STDERR_FILENO, F_GETFL);
-    switch (atoi (argv[2]))
-      {
-      case 0:
-       /* Expect fd 2 is open.  */
-       ASSERT (ret >= 0);
-       break;
-      case 1:
-       /* Expect fd 2 is closed.  */
-       ASSERT (ret < 0);
-       ASSERT (errno == EBADF);
-       break;
-      default:
-       ASSERT (false);
-      }
-  }
+  /* 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
-
-  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);
-  ASSERT (close (fd[1]) == 0);
-
-  /* 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);
-
-  /* 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 ()
 {
-  if (argc < 2)
-    {
-      fprintf (stderr, "%s: need arguments\n", argv[0]);
-      return 2;
-    }
-  if (strcmp (argv[1], "child") == 0)
-    {
-      /* fd 2 might be closed, but fd BACKUP_STDERR_FILENO is the original
-        stderr.  */
-      myerr = fdopen (BACKUP_STDERR_FILENO, "w");
-      if (!myerr)
-       return 2;
-      return child_main (argc, argv);
-    }
-  /* We might close fd 2 later, so save it in fd 10.  */
-  if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
-      || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
-    return 2;
-  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;
 }