| #include "../../unity/unity.h" |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <sys/wait.h> |
| #include <signal.h> |
|
|
| |
| |
|
|
| static int saved_stdin_fd = -1; |
|
|
| |
| static int make_pipe_and_set_stdin(void) { |
| int fds[2]; |
| if (pipe(fds) != 0) { |
| TEST_FAIL_MESSAGE("pipe() failed"); |
| } |
| |
| if (dup2(fds[0], STDIN_FILENO) < 0) { |
| close(fds[0]); |
| close(fds[1]); |
| TEST_FAIL_MESSAGE("dup2() failed to set STDIN"); |
| } |
| close(fds[0]); |
| return fds[1]; |
| } |
|
|
| void setUp(void) { |
| |
| saved_stdin_fd = dup(STDIN_FILENO); |
| if (saved_stdin_fd < 0) { |
| TEST_FAIL_MESSAGE("dup(STDIN_FILENO) failed in setUp"); |
| } |
|
|
| |
| have_read_eof = false; |
|
|
| |
| sigemptyset(&caught_signals); |
| } |
|
|
| void tearDown(void) { |
| |
| if (saved_stdin_fd >= 0) { |
| if (dup2(saved_stdin_fd, STDIN_FILENO) < 0) { |
| TEST_FAIL_MESSAGE("dup2() failed restoring STDIN"); |
| } |
| close(saved_stdin_fd); |
| saved_stdin_fd = -1; |
| } |
| } |
|
|
| |
| void test_read_input_zero_max_does_not_change_eof(void) { |
| have_read_eof = false; |
| char buf[4] = {0}; |
| idx_t n = read_input(buf, 0); |
| TEST_ASSERT_EQUAL_INT(0, (int)n); |
| TEST_ASSERT_FALSE(have_read_eof); |
|
|
| have_read_eof = true; |
| n = read_input(buf, 0); |
| TEST_ASSERT_EQUAL_INT(0, (int)n); |
| TEST_ASSERT_TRUE(have_read_eof); |
| } |
|
|
| |
| void test_read_input_reads_available_bytes(void) { |
| int w = make_pipe_and_set_stdin(); |
| const char *msg = "hello world"; |
| size_t len = strlen(msg); |
| ssize_t wr = write(w, msg, len); |
| close(w); |
| TEST_ASSERT_EQUAL_INT((int)len, (int)wr); |
|
|
| char buf[64]; |
| memset(buf, 0, sizeof buf); |
| idx_t n = read_input(buf, (idx_t)sizeof buf); |
| TEST_ASSERT_EQUAL_INT((int)len, (int)n); |
| TEST_ASSERT_EQUAL_MEMORY(msg, buf, len); |
| TEST_ASSERT_FALSE(have_read_eof); |
| } |
|
|
| |
| void test_read_input_sets_eof_when_no_data(void) { |
| int w = make_pipe_and_set_stdin(); |
| |
| close(w); |
|
|
| char buf[8]; |
| idx_t n1 = read_input(buf, (idx_t)sizeof buf); |
| TEST_ASSERT_EQUAL_INT(0, (int)n1); |
| TEST_ASSERT_TRUE(have_read_eof); |
|
|
| |
| idx_t n2 = read_input(buf, (idx_t)sizeof buf); |
| TEST_ASSERT_EQUAL_INT(0, (int)n2); |
| TEST_ASSERT_TRUE(have_read_eof); |
| } |
|
|
| |
| void test_read_input_respects_max_bytes_limit(void) { |
| int w = make_pipe_and_set_stdin(); |
| const char *msg = "abcdef"; |
| ssize_t wr = write(w, msg, 6); |
| close(w); |
| TEST_ASSERT_EQUAL_INT(6, (int)wr); |
|
|
| char buf[4] = {0}; |
| idx_t n = read_input(buf, 3); |
| TEST_ASSERT_EQUAL_INT(3, (int)n); |
| TEST_ASSERT_EQUAL_MEMORY("abc", buf, 3); |
| TEST_ASSERT_FALSE(have_read_eof); |
| } |
|
|
| |
| |
| void test_read_input_on_bad_fd_exits_failure(void) { |
| fflush(stdout); |
| fflush(stderr); |
| pid_t pid = fork(); |
| TEST_ASSERT_TRUE_MESSAGE(pid >= 0, "fork() failed"); |
|
|
| if (pid == 0) { |
| |
| sigemptyset(&caught_signals); |
| close(STDIN_FILENO); |
| char buf[1]; |
| |
| (void)read_input(buf, 1); |
|
|
| |
| _exit(0); |
| } else { |
| int status = 0; |
| pid_t wp = waitpid(pid, &status, 0); |
| TEST_ASSERT_EQUAL_INT_MESSAGE(pid, wp, "waitpid failed"); |
| TEST_ASSERT_TRUE(WIFEXITED(status)); |
| TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, WEXITSTATUS(status)); |
| } |
| } |
|
|
| int main(void) { |
| UNITY_BEGIN(); |
| RUN_TEST(test_read_input_zero_max_does_not_change_eof); |
| RUN_TEST(test_read_input_reads_available_bytes); |
| RUN_TEST(test_read_input_sets_eof_when_no_data); |
| RUN_TEST(test_read_input_respects_max_bytes_limit); |
| RUN_TEST(test_read_input_on_bad_fd_exits_failure); |
| return UNITY_END(); |
| } |