coreutils / tests /dd /tests_for_ifsync.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
/*
Test strategy:
- Provide a mock fsync() in this translation unit to control return
values and errno across calls.
- Call the target static function ifsync(int fd) directly.
- Verify that ifsync retries on EINTR and returns appropriately on
success or on non-EINTR errors.
- Ensure only the target function behavior is tested.
*/
/* Mock machinery for fsync */
typedef struct {
int ret; /* return value for fsync */
int err; /* errno to set for fsync */
} mock_fsync_step_t;
static mock_fsync_step_t mock_fsync_steps[64];
static int mock_fsync_len = 0;
static int mock_fsync_pos = 0;
static int mock_fsync_calls = 0;
static void mock_fsync_reset(void)
{
mock_fsync_len = 0;
mock_fsync_pos = 0;
mock_fsync_calls = 0;
}
static void mock_fsync_set_steps(const mock_fsync_step_t *steps, int len)
{
if (len > (int)(sizeof(mock_fsync_steps) / sizeof(mock_fsync_steps[0])))
len = (int)(sizeof(mock_fsync_steps) / sizeof(mock_fsync_steps[0]));
for (int i = 0; i < len; i++)
mock_fsync_steps[i] = steps[i];
mock_fsync_len = len;
mock_fsync_pos = 0;
mock_fsync_calls = 0;
}
/*
Mocked fsync used by ifsync(). Since this test file is included
in the same translation unit after the dd source, this definition
will satisfy references to fsync within this TU for testing.
*/
int fsync(int fd)
{
(void)fd; /* Not used in mock */
mock_fsync_calls++;
if (mock_fsync_pos < mock_fsync_len) {
int r = mock_fsync_steps[mock_fsync_pos].ret;
errno = mock_fsync_steps[mock_fsync_pos].err;
mock_fsync_pos++;
return r;
}
/* Default fall-through if sequence exhausted: succeed */
errno = 0;
return 0;
}
void setUp(void)
{
mock_fsync_reset();
}
void tearDown(void)
{
/* nothing */
}
/* Tests */
/* Immediate success: ifsync should return 0 and call fsync once. */
void test_ifsync_immediate_success(void)
{
mock_fsync_step_t seq[] = {
{ 0, 0 }
};
mock_fsync_set_steps(seq, 1);
int rc = ifsync(123);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_INT(1, mock_fsync_calls);
}
/* One EINTR then success: ifsync should retry and return 0; two calls total. */
void test_ifsync_eintr_then_success(void)
{
mock_fsync_step_t seq[] = {
{ -1, EINTR },
{ 0, 0 }
};
mock_fsync_set_steps(seq, 2);
int rc = ifsync(5);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_INT(2, mock_fsync_calls);
}
/* Multiple EINTRs then success: ensure loop continues appropriately. */
void test_ifsync_multiple_eintr_then_success(void)
{
mock_fsync_step_t seq[] = {
{ -1, EINTR },
{ -1, EINTR },
{ -1, EINTR },
{ 0, 0 }
};
mock_fsync_set_steps(seq, 4);
int rc = ifsync(7);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_INT(4, mock_fsync_calls);
}
/* Immediate non-EINTR failure: ifsync should return -1 and not retry. */
void test_ifsync_immediate_non_eintr_failure(void)
{
mock_fsync_step_t seq[] = {
{ -1, EIO }
};
mock_fsync_set_steps(seq, 1);
errno = 0;
int rc = ifsync(9);
TEST_ASSERT_EQUAL_INT(-1, rc);
TEST_ASSERT_EQUAL_INT(EIO, errno);
TEST_ASSERT_EQUAL_INT(1, mock_fsync_calls);
}
/* EINTR followed by non-EINTR failure: should retry once then return -1. */
void test_ifsync_eintr_then_non_eintr_failure(void)
{
mock_fsync_step_t seq[] = {
{ -1, EINTR },
{ -1, EFAULT }
};
mock_fsync_set_steps(seq, 2);
errno = 0;
int rc = ifsync(11);
TEST_ASSERT_EQUAL_INT(-1, rc);
TEST_ASSERT_EQUAL_INT(EFAULT, errno);
TEST_ASSERT_EQUAL_INT(2, mock_fsync_calls);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_ifsync_immediate_success);
RUN_TEST(test_ifsync_eintr_then_success);
RUN_TEST(test_ifsync_multiple_eintr_then_success);
RUN_TEST(test_ifsync_immediate_non_eintr_failure);
RUN_TEST(test_ifsync_eintr_then_non_eintr_failure);
return UNITY_END();
}