coreutils / tests /join /tests_for_get_line.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* The test file is included after the program, so we can access the
program's internal (file-scope static) data and helpers directly. */
/* Forward declarations for clarity are unnecessary since we're included
after definitions, but we annotate intent here: we use
- static bool get_line (FILE *fp, struct line **linep, int which)
- static void freeline (struct line *line)
- static void free_spareline (void)
and we access globals like prevline, spareline, line_no, eolchar,
check_input_order, join_field_1/2, issued_disorder_warning, etc. */
/* Helper: create a temporary FILE* preloaded with the provided data. */
static FILE* make_temp_file_with(const char* data)
{
FILE* fp = tmpfile();
TEST_ASSERT_NOT_NULL_MESSAGE(fp, "tmpfile failed");
size_t len = strlen(data);
if (len) {
size_t nw = fwrite(data, 1, len, fp);
TEST_ASSERT_EQUAL_size_t(len, nw);
}
rewind(fp);
return fp;
}
/* Helper: free and null any prevline/spareline state to keep tests isolated. */
static void cleanup_lines_state(void)
{
for (int i = 0; i < 2; ++i) {
if (prevline[i]) {
freeline(prevline[i]);
free(prevline[i]);
prevline[i] = NULL;
}
if (spareline[i]) {
freeline(spareline[i]);
free(spareline[i]);
spareline[i] = NULL;
}
}
}
void setUp(void)
{
/* Reset line-related state */
cleanup_lines_state();
line_no[0] = 0;
line_no[1] = 0;
/* Reset parsing and behavior globals to simple defaults */
eolchar = '\n';
/* Ensure we never call check_order during these tests */
check_input_order = CHECK_ORDER_DISABLED;
/* Reset other global flags that could affect behavior */
seen_unpairable = false;
issued_disorder_warning[0] = false;
issued_disorder_warning[1] = false;
join_field_1 = -1;
join_field_2 = -1;
}
void tearDown(void)
{
cleanup_lines_state();
}
static void assert_field_eq(const struct field* f, const char* expect)
{
size_t elen = strlen(expect);
TEST_ASSERT_EQUAL_size_t(elen, (size_t)f->len);
TEST_ASSERT_EQUAL_INT(0, memcmp(f->beg, expect, elen));
}
void test_get_line_basic_parsing_file1(void)
{
FILE* fp = make_temp_file_with("a b c\n");
struct line* line = NULL;
bool ok = get_line(fp, &line, 1);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NOT_NULL(line);
TEST_ASSERT_NOT_NULL(line->buf.buffer);
TEST_ASSERT_EQUAL_UINT64(1, line_no[0]);
TEST_ASSERT_EQUAL_UINT64(0, line_no[1]);
TEST_ASSERT_EQUAL_PTR(line, prevline[0]);
/* Basic field parsing with default blank separators */
TEST_ASSERT_EQUAL_INT(3, (int)line->nfields);
assert_field_eq(&line->fields[0], "a");
assert_field_eq(&line->fields[1], "b");
assert_field_eq(&line->fields[2], "c");
/* Buffer should end with eolchar */
TEST_ASSERT_TRUE(line->buf.length > 0);
TEST_ASSERT_EQUAL_CHAR('\n', line->buf.buffer[line->buf.length - 1]);
fclose(fp);
}
void test_get_line_spareline_swap_prevents_overwrite(void)
{
/* Two lines; ensure spareline swap triggers on second read when *linep
equals prevline */
FILE* fp = make_temp_file_with("x y\nxy z\n");
struct line* line = NULL;
bool ok1 = get_line(fp, &line, 1);
TEST_ASSERT_TRUE(ok1);
struct line* first_line = line; /* This equals prevline[0] now */
/* Read next line using the same line pointer; this triggers the swap to spareline */
bool ok2 = get_line(fp, &line, 1);
TEST_ASSERT_TRUE(ok2);
/* After swap, spareline[0] should hold the previous line, and prevline[0] should be the new line */
TEST_ASSERT_EQUAL_PTR(first_line, spareline[0]);
TEST_ASSERT_EQUAL_PTR(line, prevline[0]);
TEST_ASSERT_EQUAL_UINT64(2, line_no[0]);
/* Verify content of the newly read line */
TEST_ASSERT_NOT_NULL(line);
TEST_ASSERT_EQUAL_INT(2, (int)line->nfields);
assert_field_eq(&line->fields[0], "xy");
assert_field_eq(&line->fields[1], "z");
/* Ensure the first line's data remains intact in spareline */
TEST_ASSERT_NOT_NULL(spareline[0]);
TEST_ASSERT_TRUE(spareline[0]->nfields >= 2);
assert_field_eq(&spareline[0]->fields[0], "x");
assert_field_eq(&spareline[0]->fields[1], "y");
fclose(fp);
}
void test_get_line_empty_line_zero_fields(void)
{
FILE* fp = make_temp_file_with("\n");
struct line* line = NULL;
bool ok = get_line(fp, &line, 1);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NOT_NULL(line);
TEST_ASSERT_EQUAL_INT(0, (int)line->nfields);
fclose(fp);
}
void test_get_line_eof_returns_false_and_frees_buffers(void)
{
FILE* fp = make_temp_file_with("a\n");
struct line* line = NULL;
bool ok1 = get_line(fp, &line, 1);
TEST_ASSERT_TRUE(ok1);
TEST_ASSERT_NOT_NULL(line);
struct line* prev = line; /* equals prevline[0] */
/* Next call should hit EOF. Since we pass the same pointer, swap logic runs. */
bool ok2 = get_line(fp, &line, 1);
TEST_ASSERT_FALSE(ok2);
/* After false return, the (new) line struct remains allocated but buffers are freed. */
TEST_ASSERT_NOT_NULL(line);
TEST_ASSERT_NULL(line->buf.buffer);
TEST_ASSERT_NULL(line->fields);
/* prevline[0] remains the previous successfully-read line; swap set spareline[0]=prev too */
TEST_ASSERT_EQUAL_PTR(prev, prevline[0]);
TEST_ASSERT_EQUAL_PTR(prev, spareline[0]);
fclose(fp);
}
void test_get_line_parsing_with_leading_blanks(void)
{
FILE* fp = make_temp_file_with(" hello world \n");
struct line* line = NULL;
bool ok = get_line(fp, &line, 1);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NOT_NULL(line);
TEST_ASSERT_EQUAL_INT(2, (int)line->nfields);
assert_field_eq(&line->fields[0], "hello");
assert_field_eq(&line->fields[1], "world");
fclose(fp);
}
void test_get_line_file2_independent_state(void)
{
FILE* fp1 = make_temp_file_with("a1 b1\n");
FILE* fp2 = make_temp_file_with("a2 b2 c2\n");
struct line* l1 = NULL;
struct line* l2 = NULL;
bool ok1 = get_line(fp1, &l1, 1);
bool ok2 = get_line(fp2, &l2, 2);
TEST_ASSERT_TRUE(ok1);
TEST_ASSERT_TRUE(ok2);
TEST_ASSERT_EQUAL_UINT64(1, line_no[0]);
TEST_ASSERT_EQUAL_UINT64(1, line_no[1]);
TEST_ASSERT_EQUAL_PTR(l1, prevline[0]);
TEST_ASSERT_EQUAL_PTR(l2, prevline[1]);
TEST_ASSERT_EQUAL_INT(2, (int)l1->nfields);
assert_field_eq(&l1->fields[0], "a1");
assert_field_eq(&l1->fields[1], "b1");
TEST_ASSERT_EQUAL_INT(3, (int)l2->nfields);
assert_field_eq(&l2->fields[0], "a2");
assert_field_eq(&l2->fields[1], "b2");
assert_field_eq(&l2->fields[2], "c2");
fclose(fp1);
fclose(fp2);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_get_line_basic_parsing_file1);
RUN_TEST(test_get_line_spareline_swap_prevents_overwrite);
RUN_TEST(test_get_line_empty_line_zero_fields);
RUN_TEST(test_get_line_eof_returns_false_and_frees_buffers);
RUN_TEST(test_get_line_parsing_with_leading_blanks);
RUN_TEST(test_get_line_file2_independent_state);
return UNITY_END();
}