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