coreutils / tests /join /tests_for_prfield.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 <stdbool.h>
#include <unistd.h>
/* Unity fixtures */
void setUp(void) {
/* Ensure default state before each test */
/* empty_filler is a static global from the program; reset here */
extern const char *empty_filler;
empty_filler = NULL;
}
void tearDown(void) {
/* Reset empty_filler after each test to avoid cross-test bleed */
extern const char *empty_filler;
empty_filler = NULL;
}
/* Helper: initialize a struct line with given fields.
datas: array of pointers to byte buffers (can contain NUL)
lens: array of lengths for each field (if NULL, strlen(datas[i]) is used)
n: number of fields
*/
static void helper_init_line(struct line *line,
const char *const *datas,
const size_t *lens,
size_t n)
{
memset(line, 0, sizeof(*line));
line->nfields = (idx_t)n;
line->nfields_allocated = (idx_t)n;
if (n) {
line->fields = (struct field *)calloc(n, sizeof(struct field));
for (size_t i = 0; i < n; i++) {
size_t len = lens ? lens[i] : strlen(datas[i]);
char *buf = (char *)malloc(len + 1);
if (len) memcpy(buf, datas[i], len);
buf[len] = '\0'; /* for safety; not used by prfield */
line->fields[i].beg = buf;
line->fields[i].len = (idx_t)len;
}
} else {
line->fields = NULL;
}
}
/* Helper: free any allocations within a struct line created by helper_init_line */
static void helper_free_line(struct line *line)
{
if (!line) return;
for (idx_t i = 0; i < line->nfields; i++) {
free(line->fields[i].beg);
line->fields[i].beg = NULL;
}
free(line->fields);
line->fields = NULL;
line->nfields = 0;
line->nfields_allocated = 0;
}
/* Capture stdout while invoking prfield(n, line).
Returns malloc'd buffer containing captured bytes (NUL-terminated for convenience).
out_len, if non-NULL, is set to the number of bytes captured.
Returns NULL on failure. */
static char *capture_prfield_output(idx_t n, const struct line *line, size_t *out_len)
{
fflush(stdout);
int saved_fd = dup(STDOUT_FILENO);
if (saved_fd < 0) {
return NULL;
}
FILE *tmp = tmpfile();
if (!tmp) {
close(saved_fd);
return NULL;
}
int tmp_fd = fileno(tmp);
if (dup2(tmp_fd, STDOUT_FILENO) < 0) {
fclose(tmp);
close(saved_fd);
return NULL;
}
/* Call the target function while stdout is redirected.
Do not use Unity assertions until stdout is restored. */
prfield(n, line);
fflush(stdout);
/* Determine size and read back */
long sz = 0;
if (fseek(tmp, 0, SEEK_END) == 0) {
sz = ftell(tmp);
if (sz < 0) sz = 0;
fseek(tmp, 0, SEEK_SET);
}
size_t size = (size_t)sz;
char *buf = (char *)malloc(size + 1);
if (!buf) {
/* Restore stdout before returning on failure */
dup2(saved_fd, STDOUT_FILENO);
close(saved_fd);
fclose(tmp);
return NULL;
}
if (size) {
size_t r = fread(buf, 1, size, tmp);
(void)r; /* best effort */
}
buf[size] = '\0';
/* Restore stdout */
fflush(stdout);
dup2(saved_fd, STDOUT_FILENO);
close(saved_fd);
fclose(tmp);
if (out_len) *out_len = size;
return buf;
}
/* Tests */
static void test_prfield_prints_existing_nonempty_field(void)
{
struct line line;
const char *datas[] = { "key", "value", "foo" };
helper_init_line(&line, datas, NULL, 3);
size_t out_len = 0;
char *out = capture_prfield_output((idx_t)1, &line, &out_len);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_size_t(strlen("value"), out_len);
TEST_ASSERT_EQUAL_STRING_LEN("value", out, out_len);
free(out);
helper_free_line(&line);
}
static void test_prfield_uses_empty_filler_for_empty_field(void)
{
extern const char *empty_filler;
empty_filler = "(nil)";
struct line line;
const char *datas[] = { "" };
size_t lens[] = { 0 }; /* explicitly empty field */
helper_init_line(&line, datas, lens, 1);
size_t out_len = 0;
char *out = capture_prfield_output((idx_t)0, &line, &out_len);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_size_t(strlen("(nil)"), out_len);
TEST_ASSERT_EQUAL_STRING_LEN("(nil)", out, out_len);
free(out);
helper_free_line(&line);
}
static void test_prfield_prints_nothing_for_empty_field_without_filler(void)
{
extern const char *empty_filler;
empty_filler = NULL;
struct line line;
const char *datas[] = { "" };
size_t lens[] = { 0 };
helper_init_line(&line, datas, lens, 1);
size_t out_len = 0;
char *out = capture_prfield_output((idx_t)0, &line, &out_len);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_size_t(0, out_len);
TEST_ASSERT_EQUAL_STRING("", out);
free(out);
helper_free_line(&line);
}
static void test_prfield_uses_empty_filler_for_missing_field(void)
{
extern const char *empty_filler;
empty_filler = "[MISSING]";
struct line line;
const char *datas[] = { "only-one" };
helper_init_line(&line, datas, NULL, 1);
size_t out_len = 0;
char *out = capture_prfield_output((idx_t)5, &line, &out_len); /* beyond nfields */
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_size_t(strlen("[MISSING]"), out_len);
TEST_ASSERT_EQUAL_STRING_LEN("[MISSING]", out, out_len);
free(out);
helper_free_line(&line);
}
static void test_prfield_prints_nothing_for_missing_field_without_filler(void)
{
extern const char *empty_filler;
empty_filler = NULL;
struct line line;
const char *datas[] = { "field0" };
helper_init_line(&line, datas, NULL, 1);
size_t out_len = 0;
char *out = capture_prfield_output((idx_t)1000, &line, &out_len); /* far beyond nfields */
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_size_t(0, out_len);
TEST_ASSERT_EQUAL_STRING("", out);
free(out);
helper_free_line(&line);
}
static void test_prfield_handles_binary_field_data(void)
{
/* Field contains embedded NUL: "AB\0C" length 4 */
char bin[4];
bin[0] = 'A'; bin[1] = 'B'; bin[2] = '\0'; bin[3] = 'C';
const char *datas[] = { bin };
size_t lens[] = { 4 };
struct line line;
helper_init_line(&line, datas, lens, 1);
size_t out_len = 0;
char *out = capture_prfield_output((idx_t)0, &line, &out_len);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_size_t(4, out_len);
TEST_ASSERT_EQUAL_CHAR('A', out[0]);
TEST_ASSERT_EQUAL_CHAR('B', out[1]);
TEST_ASSERT_EQUAL_CHAR('\0', out[2]);
TEST_ASSERT_EQUAL_CHAR('C', out[3]);
free(out);
helper_free_line(&line);
}
/* Unity runner */
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_prfield_prints_existing_nonempty_field);
RUN_TEST(test_prfield_uses_empty_filler_for_empty_field);
RUN_TEST(test_prfield_prints_nothing_for_empty_field_without_filler);
RUN_TEST(test_prfield_uses_empty_filler_for_missing_field);
RUN_TEST(test_prfield_prints_nothing_for_missing_field_without_filler);
RUN_TEST(test_prfield_handles_binary_field_data);
return UNITY_END();
}