#include "../../unity/unity.h" #include #include #include #include #include #include #include #include #include /* The test file is included into dd.c, so we can directly access internal static variables and the target function ifdatasync(). */ static int make_tempfile(char *tmpl, size_t tmpls) { /* Use a template in /tmp. */ const char *prefix = "/tmp/dd_ifdatasync_test_XXXXXX"; size_t need = strlen(prefix) + 1; if (tmpls < need) return -1; strcpy(tmpl, prefix); int fd = mkstemp(tmpl); return fd; } void setUp(void) { /* Ensure process_signals() is safe to run during tests. */ /* These globals come from dd.c and are visible here due to inclusion. */ /* Avoid printing transfer stats that might use uninitialized timing. */ extern int status_level; /* from dd.c */ extern sigset_t caught_signals; /* from dd.c */ extern volatile sig_atomic_t interrupt_signal; /* from dd.c */ extern volatile sig_atomic_t info_signal_count; /* from dd.c */ extern int progress_len; /* from dd.c */ status_level = 2; /* STATUS_NOXFER */ sigemptyset(&caught_signals); interrupt_signal = 0; info_signal_count = 0; progress_len = 0; } void tearDown(void) { /* Nothing to clean up globally. */ } /* Test that ifdatasync succeeds (returns 0) on a valid regular file descriptor. */ void test_ifdatasync_valid_fd_returns_zero(void) { char path[128]; int fd = make_tempfile(path, sizeof(path)); TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "mkstemp failed to create temp file"); /* Write some data so there is something to sync. */ const char *data = "hello"; ssize_t w = write(fd, data, (size_t)5); TEST_ASSERT_TRUE_MESSAGE(w == 5, "write to temp file failed"); /* Call the target. */ errno = 0; int ret = ifdatasync(fd); /* On a regular file with fdatasync available, this should succeed. */ TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, "ifdatasync failed on regular file"); /* Cleanup */ close(fd); unlink(path); } /* Test that ifdatasync returns -1 and sets errno to EBADF for an invalid fd. */ void test_ifdatasync_invalid_fd_sets_errno_and_returns_minus1(void) { errno = 0; int ret = ifdatasync(-1); TEST_ASSERT_EQUAL_INT(-1, ret); TEST_ASSERT_EQUAL_INT(EBADF, errno); } /* Test that ifdatasync processes pending signals by consuming an info signal. */ void test_ifdatasync_process_signals_consumes_info_signal(void) { /* Prepare a valid fd to ensure fdatasync itself can succeed. */ char path[128]; int fd = make_tempfile(path, sizeof(path)); TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "mkstemp failed to create temp file"); const char *data = "abc"; ssize_t w = write(fd, data, (size_t)3); TEST_ASSERT_TRUE_MESSAGE(w == 3, "write to temp file failed"); /* Set a pending info signal and ensure caught_signals is safe. */ extern volatile sig_atomic_t info_signal_count; /* from dd.c */ extern sigset_t caught_signals; /* from dd.c */ extern int status_level; /* from dd.c */ sigemptyset(&caught_signals); status_level = 2; /* STATUS_NOXFER to avoid print_xfer_stats */ info_signal_count = 1; /* Simulate an info signal pending */ errno = 0; int ret = ifdatasync(fd); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_INT(0, info_signal_count); close(fd); unlink(path); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_ifdatasync_valid_fd_returns_zero); RUN_TEST(test_ifdatasync_invalid_fd_sets_errno_and_returns_minus1); RUN_TEST(test_ifdatasync_process_signals_consumes_info_signal); return UNITY_END(); }