coreutils / tests /dd /tests_for_synchronize_output.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#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>
/* The test file is included into the dd translation unit.
We can access static globals like conversions_mask and
the static function synchronize_output(void) directly. */
/* Forward declaration of the target (already defined above in the TU). */
static int synchronize_output (void);
/* Access the conversions_mask and flag bits defined in dd.c. */
extern int conversions_mask; /* visible within the same TU due to inclusion */
/* Flag values should be visible as macros/enum values. */
/* C_FDATASYNC and C_FSYNC are defined in dd.c's enum. */
/* Helpers for stdout redirection. Avoid Unity assertions while redirected. */
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 so it is removed automatically after close. */
unlink(tmpl);
int rc = save_and_redirect_stdout_to_fd(tmpfd, saved_fd_out);
/* tmpfd now duplicated to STDOUT_FILENO; close original. */
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;
/* fds[1] will be new stdout; keep read end around only to close later. */
int rc = save_and_redirect_stdout_to_fd(fds[1], saved_fd_out);
/* Close the original write end fd; STDOUT now refers to it. */
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) {
/* Ensure a known state before each test. */
conversions_mask = 0;
}
void tearDown(void) {
/* Restore global state if needed. */
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)
{
/* Redirect stdout to a regular file so fdatasync/fsync succeed. */
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)
{
/* On a pipe, fdatasync is expected to fail with EINVAL. The code then
also tries fsync, which also fails on a pipe -> overall failure. */
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();
/* Clean up: restore and close pipe read end. */
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();
}