coreutils / tests /cat /tests_for_copy_cat.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* Globals from the program under test (same translation unit). */
/* static int input_desc; */
/* static char const *infile; */
/* Helper: create a temporary file, write data, return fd and path. */
static int test_create_temp_file(char *tmpl_out, size_t tmpl_out_size, const char *prefix, const char *data, size_t data_len)
{
char tmpl[256];
snprintf(tmpl, sizeof(tmpl), "/tmp/%sXXXXXX", prefix ? prefix : "copy_cat_");
if (strlen(tmpl) + 1 > tmpl_out_size) {
return -1;
}
strcpy(tmpl_out, tmpl);
int fd = mkstemp(tmpl_out);
if (fd < 0) {
return -1;
}
/* Ensure file is empty then write if data provided. */
if (ftruncate(fd, 0) != 0) {
close(fd);
unlink(tmpl_out);
return -1;
}
if (data && data_len > 0) {
ssize_t wr = write(fd, data, data_len);
if (wr < 0 || (size_t)wr != data_len) {
close(fd);
unlink(tmpl_out);
return -1;
}
/* Reset offset for readers. */
if (lseek(fd, 0, SEEK_SET) < 0) {
close(fd);
unlink(tmpl_out);
return -1;
}
}
return fd;
}
/* Helper: read entire file content into malloc'd buffer; returns length via out_len. */
static char *test_read_fd_all(int fd, size_t *out_len)
{
if (lseek(fd, 0, SEEK_SET) < 0) {
/* If not seekable, attempt reading anyway. */
}
const size_t chunk = 4096;
size_t cap = chunk;
size_t len = 0;
char *buf = (char *)malloc(cap);
if (!buf) return NULL;
while (1) {
if (len + chunk > cap) {
size_t ncap = cap * 2;
char *nbuf = (char *)realloc(buf, ncap);
if (!nbuf) { free(buf); return NULL; }
buf = nbuf;
cap = ncap;
}
ssize_t rd = read(fd, buf + len, chunk);
if (rd < 0) { free(buf); return NULL; }
if (rd == 0) break;
len += (size_t)rd;
}
*out_len = len;
return buf;
}
/* Helper: redirect stdout to newfd; save original in *saved_out. Returns 0 on success. */
static int test_redirect_stdout(int newfd, int *saved_out)
{
int so = dup(STDOUT_FILENO);
if (so < 0) return -1;
if (dup2(newfd, STDOUT_FILENO) < 0) {
int e = errno;
close(so);
errno = e;
return -1;
}
*saved_out = so;
return 0;
}
/* Helper: restore stdout from saved_out. */
static void test_restore_stdout(int saved_out)
{
dup2(saved_out, STDOUT_FILENO);
close(saved_out);
}
void setUp(void) {
/* Nothing to setup globally. */
}
void tearDown(void) {
/* Nothing to cleanup globally. */
}
/* Test: unsupported path using a pipe for input (and no stdout redirection).
With the write end closed (EOF on first read), copy_file_range should return 0
(no bytes available) at first call, causing copy_cat to return 0. */
void test_copy_cat_unsupported_or_empty_pipe_returns_0(void)
{
int pipefd[2];
TEST_ASSERT_EQUAL_INT(0, pipe(pipefd));
/* Make the input a pipe with EOF: close write end immediately. */
close(pipefd[1]);
/* Set inputs for copy_cat. */
infile = "pipe_in";
input_desc = pipefd[0];
int ret = copy_cat();
/* Clean up. */
close(pipefd[0]);
/* Expect 0 because first copy_file_range should see EOF on pipe (0 bytes). */
TEST_ASSERT_EQUAL_INT(0, ret);
}
/* Test: empty regular file input with stdout redirected to a regular file.
copy_file_range should return 0 immediately (EOF) and copy_cat returns 0.
Output must remain empty. */
void test_copy_cat_empty_file_returns_0_and_no_output(void)
{
char in_path[256];
char out_path[256];
int in_fd = -1, out_fd = -1;
int saved_out = -1;
in_fd = test_create_temp_file(in_path, sizeof(in_path), "cc_in_empty_", NULL, 0);
TEST_ASSERT_TRUE_MESSAGE(in_fd >= 0, "Failed to create input temp file");
out_fd = test_create_temp_file(out_path, sizeof(out_path), "cc_out_empty_", NULL, 0);
TEST_ASSERT_TRUE_MESSAGE(out_fd >= 0, "Failed to create output temp file");
/* Prepare globals. */
infile = in_path;
input_desc = in_fd;
/* Redirect stdout to out_fd (no assertions while redirected). */
int redir_ok = test_redirect_stdout(out_fd, &saved_out);
TEST_ASSERT_EQUAL_INT_MESSAGE(0, redir_ok, "Failed to redirect stdout");
int ret = copy_cat();
/* Restore stdout before making assertions. */
test_restore_stdout(saved_out);
/* Validate return and that output is empty. */
TEST_ASSERT_EQUAL_INT(0, ret);
/* Check output content length is zero. */
size_t out_len = 0;
if (lseek(out_fd, 0, SEEK_SET) >= 0) { /* ensure read from start */ }
char *out_data = test_read_fd_all(out_fd, &out_len);
TEST_ASSERT_NOT_NULL(out_data);
TEST_ASSERT_EQUAL_UINT32(0u, (unsigned int)out_len);
free(out_data);
/* Cleanup */
close(in_fd);
close(out_fd);
unlink(in_path);
unlink(out_path);
}
/* Test: non-empty regular file input with stdout redirected to a regular file.
If copy_file_range is supported, expect return 1 and the output to match input.
If unsupported on this platform, function returns 0 and output should remain empty. */
void test_copy_cat_regular_files_success_or_unsupported(void)
{
const char *payload = "The quick brown fox jumps over the lazy dog.\nSecond line.\n";
size_t payload_len = strlen(payload);
char in_path[256];
char out_path[256];
int in_fd = -1, out_fd = -1;
int saved_out = -1;
in_fd = test_create_temp_file(in_path, sizeof(in_path), "cc_in_", payload, payload_len);
TEST_ASSERT_TRUE_MESSAGE(in_fd >= 0, "Failed to create input file");
out_fd = test_create_temp_file(out_path, sizeof(out_path), "cc_out_", NULL, 0);
TEST_ASSERT_TRUE_MESSAGE(out_fd >= 0, "Failed to create output file");
infile = in_path;
input_desc = in_fd;
int redir_ok = test_redirect_stdout(out_fd, &saved_out);
TEST_ASSERT_EQUAL_INT_MESSAGE(0, redir_ok, "Failed to redirect stdout");
int ret = copy_cat();
test_restore_stdout(saved_out);
/* Read back output. */
if (lseek(out_fd, 0, SEEK_SET) >= 0) { /* reset offset */ }
size_t out_len = 0;
char *out_data = test_read_fd_all(out_fd, &out_len);
TEST_ASSERT_NOT_NULL(out_data);
if (ret == 1) {
/* Supported path: content must match exactly. */
TEST_ASSERT_EQUAL_UINT32((unsigned int)payload_len, (unsigned int)out_len);
TEST_ASSERT_EQUAL_MEMORY(payload, out_data, payload_len);
} else if (ret == 0) {
/* Unsupported path: output should still be empty (no bytes copied). */
TEST_ASSERT_EQUAL_UINT32(0u, (unsigned int)out_len);
} else {
/* Serious error not expected in normal environments. */
TEST_FAIL_MESSAGE("copy_cat returned -1 (unexpected serious error)");
}
free(out_data);
close(in_fd);
close(out_fd);
unlink(in_path);
unlink(out_path);
}
/* Test: invalid input descriptor (EBADF) should be treated as unsupported and return 0. */
void test_copy_cat_invalid_input_fd_returns_0(void)
{
infile = "invalid_fd";
input_desc = -1;
int ret = copy_cat();
TEST_ASSERT_EQUAL_INT(0, ret);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_copy_cat_unsupported_or_empty_pipe_returns_0);
RUN_TEST(test_copy_cat_empty_file_returns_0_and_no_output);
RUN_TEST(test_copy_cat_regular_files_success_or_unsupported);
RUN_TEST(test_copy_cat_invalid_input_fd_returns_0);
return UNITY_END();
}