| #include "../../unity/unity.h" |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
|
|
| |
| |
| |
|
|
| |
| static int synchronize_output (void); |
|
|
| |
| extern int conversions_mask; |
|
|
| |
| |
|
|
| |
|
|
| static int save_and_redirect_stdout_to_fd(int target_fd, int *saved_fd_out) |
| { |
| if (!saved_fd_out) return -1; |
| int saved = dup(STDOUT_FILENO); |
| if (saved < 0) return -1; |
| if (dup2(target_fd, STDOUT_FILENO) < 0) { |
| close(saved); |
| return -1; |
| } |
| *saved_fd_out = saved; |
| return 0; |
| } |
|
|
| static int redirect_stdout_to_tempfile(int *saved_fd_out) |
| { |
| char tmpl[] = "/tmp/unity_dd_XXXXXX"; |
| int tmpfd = mkstemp(tmpl); |
| if (tmpfd < 0) |
| return -1; |
| |
| unlink(tmpl); |
|
|
| int rc = save_and_redirect_stdout_to_fd(tmpfd, saved_fd_out); |
| |
| close(tmpfd); |
| return rc; |
| } |
|
|
| static int redirect_stdout_to_pipe(int *saved_fd_out, int *pipe_read_end_out) |
| { |
| int fds[2]; |
| if (pipe(fds) != 0) |
| return -1; |
| |
| int rc = save_and_redirect_stdout_to_fd(fds[1], saved_fd_out); |
| |
| close(fds[1]); |
| if (rc != 0) { |
| close(fds[0]); |
| return -1; |
| } |
| if (pipe_read_end_out) |
| *pipe_read_end_out = fds[0]; |
| else |
| close(fds[0]); |
| return 0; |
| } |
|
|
| static void restore_stdout(int saved_fd) |
| { |
| if (saved_fd >= 0) { |
| dup2(saved_fd, STDOUT_FILENO); |
| close(saved_fd); |
| } |
| } |
|
|
| void setUp(void) { |
| |
| conversions_mask = 0; |
| } |
|
|
| void tearDown(void) { |
| |
| conversions_mask = 0; |
| } |
|
|
| static void test_synchronize_output_no_flags_returns_success_and_no_change(void) |
| { |
| conversions_mask = 0; |
| int ret = synchronize_output(); |
| TEST_ASSERT_EQUAL_INT(0, ret); |
| TEST_ASSERT_EQUAL_INT(0, conversions_mask); |
| } |
|
|
| static void test_synchronize_output_fdatasync_success_clears_and_returns_success(void) |
| { |
| |
| int saved = -1; |
| TEST_ASSERT_EQUAL_INT(0, redirect_stdout_to_tempfile(&saved)); |
|
|
| conversions_mask = C_FDATASYNC; |
| int ret = synchronize_output(); |
|
|
| restore_stdout(saved); |
|
|
| TEST_ASSERT_EQUAL_INT(0, ret); |
| TEST_ASSERT_EQUAL_INT(0, conversions_mask); |
| } |
|
|
| static void test_synchronize_output_fsync_success_clears_and_returns_success(void) |
| { |
| int saved = -1; |
| TEST_ASSERT_EQUAL_INT(0, redirect_stdout_to_tempfile(&saved)); |
|
|
| conversions_mask = C_FSYNC; |
| int ret = synchronize_output(); |
|
|
| restore_stdout(saved); |
|
|
| TEST_ASSERT_EQUAL_INT(0, ret); |
| TEST_ASSERT_EQUAL_INT(0, conversions_mask); |
| } |
|
|
| static void test_synchronize_output_both_flags_success(void) |
| { |
| int saved = -1; |
| TEST_ASSERT_EQUAL_INT(0, redirect_stdout_to_tempfile(&saved)); |
|
|
| conversions_mask = C_FDATASYNC | C_FSYNC; |
| int ret = synchronize_output(); |
|
|
| restore_stdout(saved); |
|
|
| TEST_ASSERT_EQUAL_INT(0, ret); |
| TEST_ASSERT_EQUAL_INT(0, conversions_mask); |
| } |
|
|
| static void test_synchronize_output_fdatasync_on_pipe_triggers_fsync_and_fails(void) |
| { |
| |
| |
| int saved = -1; |
| int read_end = -1; |
| TEST_ASSERT_EQUAL_INT(0, redirect_stdout_to_pipe(&saved, &read_end)); |
|
|
| conversions_mask = C_FDATASYNC; |
| int ret = synchronize_output(); |
|
|
| |
| restore_stdout(saved); |
| if (read_end >= 0) close(read_end); |
|
|
| TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, ret); |
| TEST_ASSERT_EQUAL_INT(0, conversions_mask); |
| } |
|
|
| static void test_synchronize_output_fsync_on_pipe_fails(void) |
| { |
| int saved = -1; |
| int read_end = -1; |
| TEST_ASSERT_EQUAL_INT(0, redirect_stdout_to_pipe(&saved, &read_end)); |
|
|
| conversions_mask = C_FSYNC; |
| int ret = synchronize_output(); |
|
|
| restore_stdout(saved); |
| if (read_end >= 0) close(read_end); |
|
|
| TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, ret); |
| TEST_ASSERT_EQUAL_INT(0, conversions_mask); |
| } |
|
|
| int main(void) |
| { |
| UNITY_BEGIN(); |
|
|
| RUN_TEST(test_synchronize_output_no_flags_returns_success_and_no_change); |
| RUN_TEST(test_synchronize_output_fdatasync_success_clears_and_returns_success); |
| RUN_TEST(test_synchronize_output_fsync_success_clears_and_returns_success); |
| RUN_TEST(test_synchronize_output_both_flags_success); |
| RUN_TEST(test_synchronize_output_fdatasync_on_pipe_triggers_fsync_and_fails); |
| RUN_TEST(test_synchronize_output_fsync_on_pipe_fails); |
|
|
| return UNITY_END(); |
| } |