Commit 8ee559bd authored by Steven Murdoch's avatar Steven Murdoch
Browse files

Add a unit test for fgets (currently fails)

- For a non-blocking pipe, check that on EAGAIN fgets returns NULL
  rather than a partial line
parent 23e9f362
Loading
Loading
Loading
Loading
+90 −0
Original line number Diff line number Diff line
@@ -1247,6 +1247,93 @@ test_util_exit_status(void *ptr)
  ;
}

#ifndef MS_WINDOWS
/** Check that fgets waits until a full line, and not return a partial line, on
 * a EAGAIN with a non-blocking pipe */
static void
test_util_fgets_eagain(void *ptr)
{
  int test_pipe[2] = {-1, -1};
  int retval;
  ssize_t retlen;
  char *retptr;
  FILE *test_stream = NULL;
  char buf[10];

  (void)ptr;

  /* Set up a pipe to test on */
  retval = pipe(test_pipe);
  tt_int_op(retval, >=, 0);

  /* Set up the read-end to be non-blocking */
  retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK);
  tt_int_op(retval, >=, 0);

  /* Open it as a stdio stream */
  test_stream = fdopen(test_pipe[0], "r");
  tt_ptr_op(test_stream, !=, NULL);

  /* Send in a partial line */
  retlen = write(test_pipe[1], "A", 1);
  tt_int_op(retlen, ==, 1);
  retptr = fgets(buf, sizeof(buf), test_stream);
  tt_want(retptr == NULL);
  tt_int_op(errno, ==, EAGAIN);

  /* Send in the rest */
  retlen = write(test_pipe[1], "B\n", 2);
  tt_int_op(retlen, ==, 2);
  retptr = fgets(buf, sizeof(buf), test_stream);
  tt_ptr_op(retptr, ==, buf);
  tt_str_op(buf, ==, "AB\n");

  /* Send in a full line */
  retlen = write(test_pipe[1], "CD\n", 3);
  tt_int_op(retlen, ==, 3);
  retptr = fgets(buf, sizeof(buf), test_stream);
  tt_ptr_op(retptr, ==, buf);
  tt_str_op(buf, ==, "CD\n");

  /* Send in a partial line */
  retlen = write(test_pipe[1], "E", 1);
  tt_int_op(retlen, ==, 1);
  retptr = fgets(buf, sizeof(buf), test_stream);
  tt_ptr_op(retptr, ==, NULL);
  tt_int_op(errno, ==, EAGAIN);

  /* Send in the rest */
  retlen = write(test_pipe[1], "F\n", 2);
  tt_int_op(retlen, ==, 2);
  retptr = fgets(buf, sizeof(buf), test_stream);
  tt_ptr_op(retptr, ==, buf);
  tt_str_op(buf, ==, "EF\n");

  /* Send in a full line and close */
  retlen = write(test_pipe[1], "GH", 2);
  tt_int_op(retlen, ==, 2);
  retval = close(test_pipe[1]);
  test_pipe[1] = -1;
  tt_int_op(retval, ==, 0);
  retptr = fgets(buf, sizeof(buf), test_stream);
  tt_ptr_op(retptr, ==, buf);
  tt_str_op(buf, ==, "GH");

  /* Check for EOF */
  retptr = fgets(buf, sizeof(buf), test_stream);
  tt_ptr_op(retptr, ==, NULL);
  tt_int_op(feof(test_stream), >, 0);

 done:
  if (test_stream != NULL)
    fclose(test_stream);
  if (test_pipe[0] != -1)
    close(test_pipe[0]);
  if (test_pipe[1] != -1)
    close(test_pipe[1]);
}
#endif

#define UTIL_LEGACY(name)                                               \
  { #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }

@@ -1274,6 +1361,9 @@ struct testcase_t util_tests[] = {
  UTIL_TEST(load_win_lib, 0),
#endif
  UTIL_TEST(exit_status, 0),
#ifndef MS_WINDOWS
  UTIL_TEST(fgets_eagain, 0),
#endif
  END_OF_TESTCASES
};