coreutils / tests /dd /tests_for_cache_round.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <unistd.h> /* STDIN_FILENO, STDOUT_FILENO */
#include <stdint.h>
#include <inttypes.h>
#include <limits.h>
/* We test the static function cache_round(int fd, off_t len) that
is visible here because this test file is included into dd.c. */
/* Helper: read current pending remainder for a given fd without modifying it. */
static off_t get_pending_for_fd(int fd) {
return cache_round(fd, 0);
}
/* Helper: reset the internal pending remainder for a given fd back to 0. */
static void reset_pending_for_fd(int fd) {
off_t p = cache_round(fd, 0);
if (p != 0) {
off_t need = (off_t)IO_BUFSIZE - p;
/* need is in (0, IO_BUFSIZE-1] when p != 0 */
(void)cache_round(fd, need);
/* Now pending should be 0. */
}
}
/* Helper: assert equality as 64-bit signed integers for portability. */
static void assert_off_t_eq(off_t actual, intmax_t expected) {
TEST_ASSERT_EQUAL_INT64((int64_t)expected, (int64_t)actual);
}
void setUp(void) {
/* Ensure both buckets start clean for independent tests. */
reset_pending_for_fd(STDIN_FILENO);
reset_pending_for_fd(STDOUT_FILENO);
}
void tearDown(void) {
/* Leave state clean for good hygiene. */
reset_pending_for_fd(STDIN_FILENO);
reset_pending_for_fd(STDOUT_FILENO);
}
/* Basic sanity: IO_BUFSIZE > 0 and initial pending is zero for both fds. */
void test_cache_round_initial_state(void) {
TEST_ASSERT(IO_BUFSIZE > 0);
off_t p_in = get_pending_for_fd(STDIN_FILENO);
off_t p_out = get_pending_for_fd(STDOUT_FILENO);
assert_off_t_eq(p_in, 0);
assert_off_t_eq(p_out, 0);
}
/* Accumulate two pieces that sum to exactly one IO_BUFSIZE on STDIN. */
void test_cache_round_accumulate_and_round_stdin(void) {
TEST_ASSERT(IO_BUFSIZE > 1);
off_t part1 = (off_t)(IO_BUFSIZE / 2);
if (part1 == 0) part1 = 1; /* Fallback if IO_BUFSIZE == 1 (shouldn't happen). */
off_t part2 = (off_t)IO_BUFSIZE - part1;
off_t r1 = cache_round(STDIN_FILENO, part1);
assert_off_t_eq(r1, 0); /* Not enough to round yet. */
assert_off_t_eq(get_pending_for_fd(STDIN_FILENO), part1);
off_t r2 = cache_round(STDIN_FILENO, part2);
assert_off_t_eq(r2, IO_BUFSIZE); /* Now we've crossed a full buffer. */
assert_off_t_eq(get_pending_for_fd(STDIN_FILENO), 0); /* remainder cleared */
}
/* Ensure STDIN and STDOUT buckets are independent. */
void test_cache_round_independent_stdin_stdout(void) {
/* Seed STDIN with some remainder. */
off_t r_in1 = cache_round(STDIN_FILENO, 1);
assert_off_t_eq(r_in1, 0);
assert_off_t_eq(get_pending_for_fd(STDIN_FILENO), 1);
/* STDOUT should be unaffected. */
assert_off_t_eq(get_pending_for_fd(STDOUT_FILENO), 0);
/* Now operate on STDOUT; it should have its own remainder. */
off_t r_out1 = cache_round(STDOUT_FILENO, (off_t)IO_BUFSIZE + 3);
assert_off_t_eq(r_out1, IO_BUFSIZE);
assert_off_t_eq(get_pending_for_fd(STDOUT_FILENO), 3);
/* Verify STDIN remainder unchanged. */
assert_off_t_eq(get_pending_for_fd(STDIN_FILENO), 1);
}
/* len == 0 should return the current pending remainder and not modify it. */
void test_cache_round_len_zero_returns_pending(void) {
/* Create a known pending remainder for STDIN. */
off_t r = cache_round(STDIN_FILENO, 5);
assert_off_t_eq(r, 0);
off_t p1 = cache_round(STDIN_FILENO, 0);
assert_off_t_eq(p1, 5);
/* Calling again should not change it. */
off_t p2 = cache_round(STDIN_FILENO, 0);
assert_off_t_eq(p2, 5);
}
/* Exact multiple input should be returned as-is and remainder cleared. */
void test_cache_round_exact_multiple_returns_len_and_clears_pending(void) {
off_t len = (off_t)IO_BUFSIZE * 3;
off_t r = cache_round(STDIN_FILENO, len);
assert_off_t_eq(r, len);
assert_off_t_eq(get_pending_for_fd(STDIN_FILENO), 0);
/* Follow-up partial should accumulate fresh. */
off_t r2 = cache_round(STDIN_FILENO, 2);
assert_off_t_eq(r2, 0);
assert_off_t_eq(get_pending_for_fd(STDIN_FILENO), 2);
}
/* Overflow path: when pending + len would overflow intmax_t, c_pending
becomes INTMAX_MAX; verify return and remainder reflect that value. */
void test_cache_round_overflow_behavior(void) {
/* Seed a small pending remainder to force overflow on next addition. */
(void)cache_round(STDIN_FILENO, 1); /* pending := 1 */
assert_off_t_eq(get_pending_for_fd(STDIN_FILENO), 1);
/* Now add INTMAX_MAX; ckd_add will overflow and c_pending := INTMAX_MAX. */
off_t r = cache_round(STDIN_FILENO, (off_t)INTMAX_MAX);
intmax_t remainder = (intmax_t)(INTMAX_MAX % (intmax_t)IO_BUFSIZE);
intmax_t expected_return = (intmax_t)INTMAX_MAX - remainder;
assert_off_t_eq(r, expected_return);
assert_off_t_eq(get_pending_for_fd(STDIN_FILENO), remainder);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_cache_round_initial_state);
RUN_TEST(test_cache_round_accumulate_and_round_stdin);
RUN_TEST(test_cache_round_independent_stdin_stdout);
RUN_TEST(test_cache_round_len_zero_returns_pending);
RUN_TEST(test_cache_round_exact_multiple_returns_len_and_clears_pending);
RUN_TEST(test_cache_round_overflow_behavior);
return UNITY_END();
}