coreutils / tests /comm /tests_for_writeline.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
/* Unity fixtures */
void setUp(void) {
/* no-op */
}
void tearDown(void) {
/* no-op */
}
/* Helper: capture output of writeline into outbuf.
Returns NULL on success; otherwise returns a static error message string.
This helper must not use Unity asserts because it redirects stdout. */
static const char* capture_writeline_output(const char* line_data, size_t line_len,
int cls,
bool enable_col1, bool enable_col2, bool enable_both,
const char* sep, size_t sep_len,
char* outbuf, size_t outcap, size_t* outlen)
{
static char errbuf[256];
/* Set the globals used by writeline. These are defined in the program source. */
only_file_1 = enable_col1;
only_file_2 = enable_col2;
both = enable_both;
col_sep = sep;
col_sep_len = sep_len;
/* Prepare temporary sink for stdout. */
FILE* tmp = tmpfile();
if (!tmp) {
snprintf(errbuf, sizeof errbuf, "tmpfile failed: %s", strerror(errno));
return errbuf;
}
int saved_fd = dup(fileno(stdout));
if (saved_fd < 0) {
snprintf(errbuf, sizeof errbuf, "dup failed: %s", strerror(errno));
fclose(tmp);
return errbuf;
}
if (fflush(stdout) != 0) {
snprintf(errbuf, sizeof errbuf, "fflush(stdout) failed: %s", strerror(errno));
close(saved_fd);
fclose(tmp);
return errbuf;
}
if (dup2(fileno(tmp), fileno(stdout)) < 0) {
snprintf(errbuf, sizeof errbuf, "dup2 failed: %s", strerror(errno));
close(saved_fd);
fclose(tmp);
return errbuf;
}
/* Construct the linebuffer expected by writeline. */
struct linebuffer lb;
lb.buffer = (char*) line_data;
lb.length = line_len;
/* Call the function under test. */
writeline(&lb, cls);
/* Flush and measure captured output. */
if (fflush(stdout) != 0) {
snprintf(errbuf, sizeof errbuf, "fflush after writeline failed: %s", strerror(errno));
/* Attempt to restore stdout before returning. */
}
long endpos = ftell(tmp);
if (endpos < 0) {
snprintf(errbuf, sizeof errbuf, "ftell failed: %s", strerror(errno));
/* Attempt to restore stdout before returning. */
}
if (fseek(tmp, 0, SEEK_SET) != 0) {
snprintf(errbuf, sizeof errbuf, "fseek failed: %s", strerror(errno));
/* Attempt to restore stdout before returning. */
}
size_t toread = (endpos > 0) ? (size_t) endpos : 0;
if (toread > outcap) {
/* We will read only up to outcap to not overflow, but signal an error. */
toread = outcap;
snprintf(errbuf, sizeof errbuf, "captured output larger than buffer");
} else {
errbuf[0] = '\0'; /* No error so far */
}
size_t nread = (toread > 0) ? fread(outbuf, 1, toread, tmp) : 0;
if (nread != toread) {
snprintf(errbuf, sizeof errbuf, "fread failed or short read: %s", ferror(tmp) ? strerror(errno) : "short read");
}
/* Restore stdout. */
fflush(stdout);
dup2(saved_fd, fileno(stdout));
close(saved_fd);
fclose(tmp);
*outlen = nread;
if (errbuf[0] != '\0') {
return errbuf;
}
return NULL;
}
/* Utility to check expected output easily. */
static void assert_capture_equals(const char* line, size_t line_len, int cls,
bool c1, bool c2, bool cboth,
const char* sep, size_t sep_len,
const char* expected, size_t expected_len)
{
char buf[256];
size_t got_len = 0;
const char* err = capture_writeline_output(line, line_len, cls, c1, c2, cboth,
sep, sep_len, buf, sizeof buf, &got_len);
TEST_ASSERT_NULL_MESSAGE(err, err ? err : "unexpected error capturing output");
TEST_ASSERT_EQUAL_UINT64(expected_len, got_len);
TEST_ASSERT_EQUAL_MEMORY(expected, buf, expected_len);
}
/* Tests */
/* class=1: suppressed column -> no output */
void test_writeline_class1_suppressed_no_output(void) {
const char line[] = "alpha\n";
assert_capture_equals(line, strlen(line), 1,
false, /* only_file_1 disabled */
false, /* only_file_2 irrelevant */
false, /* both irrelevant */
"\t", 1,
"", 0);
}
/* class=1: enabled -> prints line with no separators */
void test_writeline_class1_enabled_prints_line(void) {
const char line[] = "alpha\n";
assert_capture_equals(line, strlen(line), 1,
true, /* only_file_1 enabled */
false,
false,
"\t", 1,
line, strlen(line));
}
/* class=2: suppressed column -> no output */
void test_writeline_class2_suppressed_no_output(void) {
const char line[] = "beta\n";
assert_capture_equals(line, strlen(line), 2,
false, /* only_file_1 irrelevant for printing */
false, /* only_file_2 disabled */
false,
"|", 1,
"", 0);
}
/* class=2: enabled, col1 disabled -> no separator, just line */
void test_writeline_class2_enabled_no_col1_no_prefix(void) {
const char line[] = "beta\n";
assert_capture_equals(line, strlen(line), 2,
false, /* only_file_1 disabled -> no prefix */
true, /* only_file_2 enabled -> print */
false,
"|", 1,
line, strlen(line));
}
/* class=2: enabled, col1 enabled -> one separator then line */
void test_writeline_class2_enabled_with_col1_prefix_once(void) {
const char line[] = "beta\n";
const char sep[] = "|";
char expected[16];
size_t e_len = 0;
memcpy(expected + e_len, sep, 1); e_len += 1;
memcpy(expected + e_len, line, strlen(line)); e_len += strlen(line);
assert_capture_equals(line, strlen(line), 2,
true, /* only_file_1 enabled -> prefix once */
true, /* only_file_2 enabled -> print */
false,
sep, strlen(sep),
expected, e_len);
}
/* class=3: both enabled, neither col1 nor col2 -> no prefix, just line */
void test_writeline_class3_enabled_no_columns_no_prefix(void) {
const char line[] = "gamma\n";
assert_capture_equals(line, strlen(line), 3,
false, /* only_file_1 disabled */
false, /* only_file_2 disabled */
true, /* both enabled -> print */
"\t", 1,
line, strlen(line));
}
/* class=3: both enabled, only col1 enabled -> one prefix then line */
void test_writeline_class3_enabled_with_col1_one_prefix(void) {
const char line[] = "delta\n";
const char sep[] = "+++";
char expected[32];
size_t e_len = 0;
memcpy(expected + e_len, sep, strlen(sep)); e_len += strlen(sep);
memcpy(expected + e_len, line, strlen(line)); e_len += strlen(line);
assert_capture_equals(line, strlen(line), 3,
true, /* only_file_1 enabled */
false, /* only_file_2 disabled */
true, /* both enabled */
sep, strlen(sep),
expected, e_len);
}
/* class=3: both enabled, only col2 enabled -> one prefix then line */
void test_writeline_class3_enabled_with_col2_one_prefix(void) {
const char line[] = "epsilon\n";
const char sep[] = "::";
char expected[32];
size_t e_len = 0;
memcpy(expected + e_len, sep, strlen(sep)); e_len += strlen(sep);
memcpy(expected + e_len, line, strlen(line)); e_len += strlen(line);
assert_capture_equals(line, strlen(line), 3,
false, /* only_file_1 disabled */
true, /* only_file_2 enabled */
true, /* both enabled */
sep, strlen(sep),
expected, e_len);
}
/* class=3: both enabled, col1 and col2 enabled -> two prefixes then line */
void test_writeline_class3_enabled_with_both_columns_two_prefixes(void) {
const char line[] = "zeta\n";
const char sep[] = "::";
char expected[64];
size_t e_len = 0;
memcpy(expected + e_len, sep, strlen(sep)); e_len += strlen(sep);
memcpy(expected + e_len, sep, strlen(sep)); e_len += strlen(sep);
memcpy(expected + e_len, line, strlen(line)); e_len += strlen(line);
assert_capture_equals(line, strlen(line), 3,
true, /* only_file_1 enabled -> first prefix */
true, /* only_file_2 enabled -> second prefix */
true, /* both enabled -> print */
sep, strlen(sep),
expected, e_len);
}
/* Ensure col_sep_len controls actual emitted bytes (sep non-empty but length 0 => no prefix) */
void test_writeline_separator_len_zero_emits_no_prefix(void) {
const char line[] = "theta\n";
/* sep string is non-empty, but we pass sep_len=0 explicitly */
assert_capture_equals(line, strlen(line), 2,
true, /* would normally cause prefix for class=2 */
true, /* print class 2 */
false,
"XYZ", 0 /* col_sep_len zero */,
line, strlen(line));
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_writeline_class1_suppressed_no_output);
RUN_TEST(test_writeline_class1_enabled_prints_line);
RUN_TEST(test_writeline_class2_suppressed_no_output);
RUN_TEST(test_writeline_class2_enabled_no_col1_no_prefix);
RUN_TEST(test_writeline_class2_enabled_with_col1_prefix_once);
RUN_TEST(test_writeline_class3_enabled_no_columns_no_prefix);
RUN_TEST(test_writeline_class3_enabled_with_col1_one_prefix);
RUN_TEST(test_writeline_class3_enabled_with_col2_one_prefix);
RUN_TEST(test_writeline_class3_enabled_with_both_columns_two_prefixes);
RUN_TEST(test_writeline_separator_len_zero_emits_no_prefix);
return UNITY_END();
}