coreutils / tests /fmt /tests_for_usage.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
/* Unity hooks */
void setUp(void) {
/* No setup needed */
}
void tearDown(void) {
/* No teardown needed */
}
/* Helper to read all data from an fd into a NUL-terminated buffer.
The returned buffer must be free()'d by the caller. */
static char* read_all_from_fd(int fd, size_t *out_len) {
size_t cap = 4096;
size_t len = 0;
char *buf = (char*)malloc(cap);
if (!buf) return NULL;
for (;;) {
if (len + 2048 > cap) {
size_t new_cap = cap * 2;
char *nb = (char*)realloc(buf, new_cap);
if (!nb) {
free(buf);
return NULL;
}
buf = nb;
cap = new_cap;
}
ssize_t n = read(fd, buf + len, cap - len - 1);
if (n < 0) {
if (errno == EINTR) continue;
free(buf);
return NULL;
}
if (n == 0) break;
len += (size_t)n;
}
buf[len] = '\0';
if (out_len) *out_len = len;
return buf;
}
/* Run usage(status) in a child process, capturing stdout/stderr and exit code. */
struct usage_run_result {
int exit_code; /* child exit status (0-255 if exited normally, else 128+signal) */
char *out_buf; /* captured stdout (malloc'd) */
size_t out_len;
char *err_buf; /* captured stderr (malloc'd) */
size_t err_len;
int ok; /* 1 on success, 0 on setup error */
};
static struct usage_run_result run_usage_and_capture(int status_code) {
struct usage_run_result res;
memset(&res, 0, sizeof(res));
res.exit_code = -1;
res.ok = 0;
int out_pipe[2] = {-1, -1};
int err_pipe[2] = {-1, -1};
if (pipe(out_pipe) != 0) return res;
if (pipe(err_pipe) != 0) { close(out_pipe[0]); close(out_pipe[1]); return res; }
fflush(stdout);
fflush(stderr);
pid_t pid = fork();
if (pid < 0) {
close(out_pipe[0]); close(out_pipe[1]);
close(err_pipe[0]); close(err_pipe[1]);
return res;
}
if (pid == 0) {
/* Child: redirect stdout/stderr and call usage */
/* Close read ends */
(void)close(out_pipe[0]);
(void)close(err_pipe[0]);
/* Redirect stdout/stderr */
(void)dup2(out_pipe[1], STDOUT_FILENO);
(void)dup2(err_pipe[1], STDERR_FILENO);
/* Close the duplicated write ends */
(void)close(out_pipe[1]);
(void)close(err_pipe[1]);
/* Call the function under test; it should exit(). */
usage(status_code);
/* If it returns unexpectedly, exit with a distinctive code. */
_exit(127);
}
/* Parent */
(void)close(out_pipe[1]);
(void)close(err_pipe[1]);
/* Read all output */
res.out_buf = read_all_from_fd(out_pipe[0], &res.out_len);
res.err_buf = read_all_from_fd(err_pipe[0], &res.err_len);
(void)close(out_pipe[0]);
(void)close(err_pipe[0]);
int wstatus = 0;
pid_t w = waitpid(pid, &wstatus, 0);
if (w < 0) {
/* wait failed */
res.ok = 0;
return res;
}
if (WIFEXITED(wstatus)) {
res.exit_code = WEXITSTATUS(wstatus);
} else if (WIFSIGNALED(wstatus)) {
res.exit_code = 128 + WTERMSIG(wstatus);
} else {
res.exit_code = -2; /* unknown */
}
res.ok = 1;
return res;
}
/* Tests */
static void free_usage_result(struct usage_run_result *r) {
if (!r) return;
free(r->out_buf);
free(r->err_buf);
r->out_buf = NULL;
r->err_buf = NULL;
}
void test_usage_success_exits_zero_and_writes_to_stdout(void) {
struct usage_run_result r = run_usage_and_capture(EXIT_SUCCESS);
TEST_ASSERT_MESSAGE(r.ok, "Failed to set up or run usage()");
TEST_ASSERT_EQUAL_INT_MESSAGE(0, r.exit_code, "usage(EXIT_SUCCESS) should exit with status 0");
/* Expect some help/usage text on stdout */
TEST_ASSERT_TRUE_MESSAGE(r.out_len > 0, "Expected non-empty stdout for EXIT_SUCCESS");
/* We don't assert on stderr content due to localization; it may contain ancillary notes */
free_usage_result(&r);
}
void test_usage_failure_exits_failure_and_writes_try_help_to_stderr(void) {
struct usage_run_result r = run_usage_and_capture(EXIT_FAILURE);
TEST_ASSERT_MESSAGE(r.ok, "Failed to set up or run usage()");
TEST_ASSERT_EQUAL_INT_MESSAGE(EXIT_FAILURE, r.exit_code, "usage(EXIT_FAILURE) should exit with EXIT_FAILURE");
/* For failure, usage() is expected to not print the full usage to stdout. */
TEST_ASSERT_TRUE_MESSAGE(r.out_len == 0, "Expected empty stdout for non-success status");
/* Help hint should go to stderr; assert non-empty */
TEST_ASSERT_TRUE_MESSAGE(r.err_len > 0, "Expected non-empty stderr for non-success status");
free_usage_result(&r);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_usage_success_exits_zero_and_writes_to_stdout);
RUN_TEST(test_usage_failure_exits_failure_and_writes_try_help_to_stderr);
return UNITY_END();
}