| | #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(); |
| | } |