coreutils / tests /head /tests_for_copy_fd.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
/* Helper: create a temp file with given data, return fd and path. */
static int create_temp_file_with_data(const void *data, size_t len, char *path_buf, size_t path_buf_sz)
{
/* Create a template in current directory to avoid platform-specific temp dirs */
const char *tmpl = "./test_copyfd_src_XXXXXX";
if (path_buf_sz < strlen(tmpl) + 1)
return -1;
strcpy(path_buf, tmpl);
int fd = mkstemp(path_buf);
if (fd < 0)
return -1;
if (len > 0) {
ssize_t wr = write(fd, data, len);
if (wr < 0 || (size_t)wr != len) {
int saved = errno;
close(fd);
unlink(path_buf);
errno = saved;
return -1;
}
}
/* Rewind for reading */
if (lseek(fd, 0, SEEK_SET) < 0) {
int saved = errno;
close(fd);
unlink(path_buf);
errno = saved;
return -1;
}
return fd;
}
/* Helper: capture stdout to a temp file, run copy_fd, restore stdout, and validate. */
static char *run_and_check_copy_fd(int src_fd,
uintmax_t n_bytes,
enum Copy_fd_status expected_status,
const void *expected_output,
size_t expected_output_len)
{
/* Flush stdout before redirect */
fflush(stdout);
/* Save current stdout */
int saved_stdout = dup(STDOUT_FILENO);
if (saved_stdout < 0) {
char *msg = (char*)malloc(256);
snprintf(msg, 256, "dup(STDOUT) failed: errno=%d", errno);
return msg;
}
/* Create output capture file */
char out_tmpl[] = "./test_copyfd_out_XXXXXX";
int out_fd = mkstemp(out_tmpl);
if (out_fd < 0) {
close(saved_stdout);
char *msg = (char*)malloc(256);
snprintf(msg, 256, "mkstemp for stdout capture failed: errno=%d", errno);
return msg;
}
/* Redirect stdout to capture file */
if (dup2(out_fd, STDOUT_FILENO) < 0) {
int saved = errno;
close(out_fd);
close(saved_stdout);
char *msg = (char*)malloc(256);
snprintf(msg, 256, "dup2 to redirect stdout failed: errno=%d", saved);
return msg;
}
close(out_fd); /* Now captured by fd 1 */
/* Call the function under test (no Unity asserts while redirected!) */
enum Copy_fd_status st = copy_fd(src_fd, n_bytes);
/* Ensure all data is flushed to the capture file */
fflush(stdout);
/* Restore stdout */
if (dup2(saved_stdout, STDOUT_FILENO) < 0) {
int saved = errno;
close(saved_stdout);
char *msg = (char*)malloc(256);
snprintf(msg, 256, "dup2 to restore stdout failed: errno=%d", saved);
return msg;
}
close(saved_stdout);
/* Read back captured output */
int cap_fd = open(out_tmpl, O_RDONLY);
if (cap_fd < 0) {
int saved = errno;
unlink(out_tmpl);
char *msg = (char*)malloc(256);
snprintf(msg, 256, "open captured file failed: errno=%d", saved);
return msg;
}
struct stat stbuf;
if (fstat(cap_fd, &stbuf) < 0) {
int saved = errno;
close(cap_fd);
unlink(out_tmpl);
char *msg = (char*)malloc(256);
snprintf(msg, 256, "fstat captured file failed: errno=%d", saved);
return msg;
}
size_t cap_sz = (size_t)stbuf.st_size;
char *cap = NULL;
if (cap_sz > 0) {
cap = (char*)malloc(cap_sz);
if (!cap) {
close(cap_fd);
unlink(out_tmpl);
char *msg = (char*)malloc(256);
snprintf(msg, 256, "malloc(%zu) failed for capture buffer", cap_sz);
return msg;
}
size_t off = 0;
while (off < cap_sz) {
ssize_t r = read(cap_fd, cap + off, cap_sz - off);
if (r < 0) {
int saved = errno;
free(cap);
close(cap_fd);
unlink(out_tmpl);
char *msg = (char*)malloc(256);
snprintf(msg, 256, "read captured file failed: errno=%d", saved);
return msg;
}
if (r == 0) break;
off += (size_t)r;
}
/* cap_sz is from st_size; off should equal cap_sz. */
}
close(cap_fd);
unlink(out_tmpl);
/* Validate status */
if (st != expected_status) {
char *msg = (char*)malloc(256);
snprintf(msg, 256, "Status mismatch: got %d, expected %d", (int)st, (int)expected_status);
free(cap);
return msg;
}
/* Validate output length */
if (cap_sz != expected_output_len) {
char *msg = (char*)malloc(256);
snprintf(msg, 256, "Output length mismatch: got %zu, expected %zu", cap_sz, expected_output_len);
free(cap);
return msg;
}
/* Validate output content if any */
if (cap_sz > 0 && memcmp(cap, expected_output, cap_sz) != 0) {
/* Find first mismatch for easier debugging */
size_t idx = 0;
while (idx < cap_sz && ((unsigned char*)cap)[idx] == ((const unsigned char*)expected_output)[idx])
idx++;
char *msg = (char*)malloc(256);
snprintf(msg, 256, "Output content mismatch at byte %zu", idx);
free(cap);
return msg;
}
free(cap);
return NULL; /* success */
}
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
static void fill_pattern(char *buf, size_t len)
{
for (size_t i = 0; i < len; i++)
buf[i] = (char)('A' + (i % 26));
}
/* Tests */
void test_copy_fd_zero_bytes_no_output(void)
{
const char data[] = "ignored";
char path[64];
int fd = create_temp_file_with_data(data, sizeof(data) - 1, path, sizeof(path));
TEST_ASSERT_MESSAGE(fd >= 0, "Failed to create temp source file");
/* Request 0 bytes */
char *err = run_and_check_copy_fd(fd, 0, COPY_FD_OK, "", 0);
close(fd);
unlink(path);
TEST_ASSERT_NULL_MESSAGE(err, err ? err : "");
free(err);
}
void test_copy_fd_partial_copy(void)
{
const char data[] = "abcdef";
const size_t req = 3;
char path[64];
int fd = create_temp_file_with_data(data, sizeof(data) - 1, path, sizeof(path));
TEST_ASSERT_MESSAGE(fd >= 0, "Failed to create temp source file");
char *err = run_and_check_copy_fd(fd, req, COPY_FD_OK, data, req);
close(fd);
unlink(path);
TEST_ASSERT_NULL_MESSAGE(err, err ? err : "");
free(err);
}
void test_copy_fd_exact_copy(void)
{
const char data[] = "Hello, world!";
const size_t len = sizeof(data) - 1;
char path[64];
int fd = create_temp_file_with_data(data, len, path, sizeof(path));
TEST_ASSERT_MESSAGE(fd >= 0, "Failed to create temp source file");
char *err = run_and_check_copy_fd(fd, len, COPY_FD_OK, data, len);
close(fd);
unlink(path);
TEST_ASSERT_NULL_MESSAGE(err, err ? err : "");
free(err);
}
void test_copy_fd_oversized_request_unexpected_eof(void)
{
const char data[] = "abcd";
const size_t len = sizeof(data) - 1;
const uintmax_t req = 10; /* larger than len */
char path[64];
int fd = create_temp_file_with_data(data, len, path, sizeof(path));
TEST_ASSERT_MESSAGE(fd >= 0, "Failed to create temp source file");
/* Expect all available bytes written, status UNEXPECTED_EOF */
char *err = run_and_check_copy_fd(fd, req, COPY_FD_UNEXPECTED_EOF, data, len);
close(fd);
unlink(path);
TEST_ASSERT_NULL_MESSAGE(err, err ? err : "");
free(err);
}
void test_copy_fd_read_error_returns_status(void)
{
/* Create a file, then open it write-only to induce read error */
const char data[] = "some data";
char path[64];
int tmpfd = create_temp_file_with_data(data, sizeof(data) - 1, path, sizeof(path));
TEST_ASSERT_MESSAGE(tmpfd >= 0, "Failed to create temp source file");
close(tmpfd);
int wfd = open(path, O_WRONLY);
TEST_ASSERT_MESSAGE(wfd >= 0, "Failed to open file write-only to induce read error");
/* Expect READ_ERROR and no output */
char *err = run_and_check_copy_fd(wfd, 5, COPY_FD_READ_ERROR, "", 0);
close(wfd);
unlink(path);
TEST_ASSERT_NULL_MESSAGE(err, err ? err : "");
free(err);
}
void test_copy_fd_large_transfer_multiple_buffers(void)
{
size_t len = (size_t)BUFSIZ * 3 + 123; /* span multiple reads */
char *data = (char*)malloc(len);
TEST_ASSERT_NOT_NULL(data);
fill_pattern(data, len);
char path[64];
int fd = create_temp_file_with_data(data, len, path, sizeof(path));
TEST_ASSERT_MESSAGE(fd >= 0, "Failed to create temp source file");
char *err = run_and_check_copy_fd(fd, len, COPY_FD_OK, data, len);
close(fd);
unlink(path);
free(data);
TEST_ASSERT_NULL_MESSAGE(err, err ? err : "");
free(err);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_copy_fd_zero_bytes_no_output);
RUN_TEST(test_copy_fd_partial_copy);
RUN_TEST(test_copy_fd_exact_copy);
RUN_TEST(test_copy_fd_oversized_request_unexpected_eof);
RUN_TEST(test_copy_fd_read_error_returns_status);
RUN_TEST(test_copy_fd_large_transfer_multiple_buffers);
return UNITY_END();
}