coreutils / tests /fmt /tests_for_copy_rest.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
/* We rely on internal symbols from fmt.c:
- static void set_prefix(char *p);
- static int copy_rest(FILE *f, int c);
- static bool tabs;
- static int in_column;
- static int next_prefix_indent;
- static char const *prefix;
- static int prefix_length;
These are available since this test file is included into the same
translation unit. */
/* Prototypes to silence any compiler warnings (available in this TU). */
static void set_prefix (char *p);
static int copy_rest (FILE *f, int c);
/* Globals from the program (declared in the same TU) */
extern bool tabs;
extern int in_column;
extern int next_prefix_indent;
/* Helper: create an input FILE* containing 'content' and rewind it. */
static FILE* make_input_stream(const char* content)
{
FILE* f = tmpfile();
if (!f)
return NULL;
size_t len = content ? strlen(content) : 0;
if (len > 0)
{
if (fwrite(content, 1, len, f) != len)
{
fclose(f);
return NULL;
}
}
rewind(f);
return f;
}
/* Helper: capture stdout while invoking copy_rest(fin, c).
- Returns a heap-allocated string with the captured output (caller frees).
- Writes the return value of copy_rest into *ret_c.
- Returns NULL on failure (allocation or tmpfile issues).
Note: No Unity assertions while stdout is redirected. */
static char* capture_copy_rest_output(FILE* fin, int c, int* ret_c)
{
if (!ret_c)
return NULL;
fflush(stdout);
int saved_fd = dup(fileno(stdout));
if (saved_fd == -1)
return NULL;
FILE* cap = tmpfile();
if (!cap)
{
close(saved_fd);
return NULL;
}
int cap_fd = fileno(cap);
if (dup2(cap_fd, fileno(stdout)) == -1)
{
fclose(cap);
close(saved_fd);
return NULL;
}
int r = copy_rest(fin, c);
fflush(stdout);
fflush(cap);
/* Restore stdout */
if (dup2(saved_fd, fileno(stdout)) == -1)
{
fclose(cap);
close(saved_fd);
return NULL;
}
close(saved_fd);
/* Read captured output */
if (fseek(cap, 0, SEEK_END) != 0)
{
fclose(cap);
return NULL;
}
long sz = ftell(cap);
if (sz < 0)
{
fclose(cap);
return NULL;
}
if (fseek(cap, 0, SEEK_SET) != 0)
{
fclose(cap);
return NULL;
}
char* buf = (char*)malloc((size_t)sz + 1);
if (!buf)
{
fclose(cap);
return NULL;
}
size_t nread = fread(buf, 1, (size_t)sz, cap);
buf[nread] = '\0';
fclose(cap);
*ret_c = r;
return buf;
}
void setUp(void)
{
/* Ensure deterministic spacing (no tabs in output) */
tabs = false;
}
void tearDown(void)
{
/* Nothing to clean */
}
/* Test: c == '\n' with no prefix progress; expect no output and return '\n'. */
static void test_copy_rest_blank_line_no_output(void)
{
char pfx[] = "";
set_prefix(pfx);
next_prefix_indent = 0;
in_column = 0;
FILE* fin = make_input_stream("");
TEST_ASSERT_NOT_NULL(fin);
int retc = 0;
char* out = capture_copy_rest_output(fin, '\n', &retc);
fclose(fin);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_INT('\n', retc);
TEST_ASSERT_EQUAL_UINT(0, strlen(out));
free(out);
}
/* Test: c == '\n' with some indentation and partial prefix print. */
static void test_copy_rest_newline_with_partial_prefix(void)
{
char pfx[] = "ABC";
set_prefix(pfx);
next_prefix_indent = 2; /* two leading spaces */
in_column = 3; /* matched 'A' before newline */
FILE* fin = make_input_stream("");
TEST_ASSERT_NOT_NULL(fin);
int retc = 0;
char* out = capture_copy_rest_output(fin, '\n', &retc);
fclose(fin);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_INT('\n', retc);
/* Expect: " A" (2 spaces + 'A') */
TEST_ASSERT_EQUAL_STRING(" A", out);
free(out);
}
/* Test: mismatch (c not '\n'/EOF) with no extra padding beyond trimmed prefix. */
static void test_copy_rest_mismatch_no_padding(void)
{
char pfx[] = "ABC";
set_prefix(pfx);
next_prefix_indent = 2;
in_column = 3; /* matched 'A' */
/* The remainder of the line (after 'X') will be "YZ\n" */
FILE* fin = make_input_stream("YZ\n");
TEST_ASSERT_NOT_NULL(fin);
int retc = 0;
char* out = capture_copy_rest_output(fin, 'X', &retc);
fclose(fin);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_INT('\n', retc);
/* Expect: " A" + 'X' + "YZ" = " AXYZ" */
TEST_ASSERT_EQUAL_STRING(" AXYZ", out);
free(out);
}
/* Test: mismatch with in_column beyond trimmed prefix -> extra padding spaces added. */
static void test_copy_rest_mismatch_with_padding_beyond_trimmed_prefix(void)
{
char pfx[] = "AB "; /* trimmed prefix becomes "AB", prefix_length = 2 */
set_prefix(pfx);
next_prefix_indent = 1;
in_column = next_prefix_indent + 4; /* 1 (indent) + 4 matched columns */
/* After printing indent + "AB", we need (4 - 2) = 2 padding spaces. */
FILE* fin = make_input_stream("T\n");
TEST_ASSERT_NOT_NULL(fin);
int retc = 0;
char* out = capture_copy_rest_output(fin, 'X', &retc);
fclose(fin);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_INT('\n', retc);
/* Expect: " " + "AB" + " " + 'X' + "T" = " AB XT" */
TEST_ASSERT_EQUAL_STRING(" AB XT", out);
free(out);
}
/* Test: EOF where in_column >= next_prefix_indent + prefix_length -> emits newline. */
static void test_copy_rest_eof_emits_newline_after_full_prefix(void)
{
char pfx[] = "HELLO";
set_prefix(pfx);
next_prefix_indent = 3;
in_column = next_prefix_indent + (int)strlen("HELLO"); /* full trimmed prefix matched */
FILE* fin = make_input_stream("");
TEST_ASSERT_NOT_NULL(fin);
int retc = 0;
char* out = capture_copy_rest_output(fin, EOF, &retc);
fclose(fin);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_INT(EOF, retc);
/* Expect: " HELLO\n" */
TEST_ASSERT_EQUAL_STRING(" HELLO\n", out);
free(out);
}
/* Test: EOF where no progress beyond indent -> no output. */
static void test_copy_rest_eof_no_output_when_no_progress(void)
{
char pfx[] = "HELLO";
set_prefix(pfx);
next_prefix_indent = 2;
in_column = 2; /* no progress beyond indent */
FILE* fin = make_input_stream("");
TEST_ASSERT_NOT_NULL(fin);
int retc = 0;
char* out = capture_copy_rest_output(fin, EOF, &retc);
fclose(fin);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_INT(EOF, retc);
TEST_ASSERT_EQUAL_UINT(0, strlen(out));
free(out);
}
/* Test: No prefix context (empty prefix), c not newline/EOF. */
static void test_copy_rest_no_prefix_context_non_newline(void)
{
char pfx[] = "";
set_prefix(pfx);
next_prefix_indent = 0;
in_column = 0;
FILE* fin = make_input_stream("RS\n"); /* tail after 'Q' */
TEST_ASSERT_NOT_NULL(fin);
int retc = 0;
char* out = capture_copy_rest_output(fin, 'Q', &retc);
fclose(fin);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_INT('\n', retc);
/* Expect: 'Q' + "RS" */
TEST_ASSERT_EQUAL_STRING("QRS", out);
free(out);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_copy_rest_blank_line_no_output);
RUN_TEST(test_copy_rest_newline_with_partial_prefix);
RUN_TEST(test_copy_rest_mismatch_no_padding);
RUN_TEST(test_copy_rest_mismatch_with_padding_beyond_trimmed_prefix);
RUN_TEST(test_copy_rest_eof_emits_newline_after_full_prefix);
RUN_TEST(test_copy_rest_eof_no_output_when_no_progress);
RUN_TEST(test_copy_rest_no_prefix_context_non_newline);
return UNITY_END();
}