coreutils / tests /join /tests_for_getseq.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* setUp and tearDown are required by Unity */
void setUp(void) {
/* Disable order checking to avoid dereferencing any stale prevline pointers
left from previous tests, since we free lines after each test. */
check_input_order = CHECK_ORDER_DISABLED;
/* Reset the unpairable flag just in case any logic consults it. */
seen_unpairable = false;
}
void tearDown(void) {
/* Ensure any spare lines are freed to avoid leaks across tests. */
free_spareline();
}
/* Helper: create a temporary file preloaded with 'content' and rewound. */
static FILE* make_tempfile_with(const char* content) {
FILE *fp = tmpfile();
TEST_ASSERT_NOT_NULL_MESSAGE(fp, "tmpfile() failed");
if (content && *content) {
size_t len = strlen(content);
TEST_ASSERT_EQUAL_MESSAGE(len, fwrite(content, 1, len, fp),
"Failed to write content to tmp file");
}
fflush(fp);
rewind(fp);
return fp;
}
/* Validate a field equals the given string (length and bytes). */
static void assert_field_equals(const struct field *f, const char *s) {
size_t slen = strlen(s);
TEST_ASSERT_EQUAL_size_t(slen, (size_t)f->len);
if (slen > 0) {
TEST_ASSERT_NOT_NULL(f->beg);
TEST_ASSERT_EQUAL_INT(0, memcmp(f->beg, s, slen));
}
}
/* Test: getseq reads a single line and parses three fields separated by blanks. */
void test_getseq_reads_single_line_and_fields(void) {
FILE *fp = make_tempfile_with("a b c\n");
struct seq s;
initseq(&s);
bool ok = getseq(fp, &s, 1);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_TRUE(s.count == 1);
TEST_ASSERT_NOT_NULL(s.lines);
TEST_ASSERT_TRUE(s.alloc >= 1);
TEST_ASSERT_NOT_NULL(s.lines[0]);
struct line *l = s.lines[0];
TEST_ASSERT_NOT_NULL(l);
TEST_ASSERT_TRUE(l->nfields == 3);
TEST_ASSERT_NOT_NULL(l->fields);
assert_field_equals(&l->fields[0], "a");
assert_field_equals(&l->fields[1], "b");
assert_field_equals(&l->fields[2], "c");
delseq(&s);
fclose(fp);
}
/* Test: getseq returns false on EOF and does not increment count. */
void test_getseq_returns_false_on_empty_file(void) {
FILE *fp = make_tempfile_with("");
struct seq s;
initseq(&s);
bool ok = getseq(fp, &s, 1);
TEST_ASSERT_FALSE(ok);
TEST_ASSERT_TRUE(s.count == 0);
/* Storage should have been allocated, and the first slot initialized to NULL. */
TEST_ASSERT_NOT_NULL(s.lines);
TEST_ASSERT_TRUE(s.alloc >= 1);
TEST_ASSERT_NULL(s.lines[0]);
delseq(&s);
fclose(fp);
}
/* Test: getseq reads multiple lines and increments count appropriately. */
void test_getseq_reads_multiple_lines(void) {
FILE *fp = make_tempfile_with("x\ny\nz\n");
struct seq s;
initseq(&s);
bool ok1 = getseq(fp, &s, 1);
TEST_ASSERT_TRUE(ok1);
TEST_ASSERT_TRUE(s.count == 1);
TEST_ASSERT_NOT_NULL(s.lines[0]);
TEST_ASSERT_TRUE(s.lines[0]->nfields == 1);
assert_field_equals(&s.lines[0]->fields[0], "x");
bool ok2 = getseq(fp, &s, 1);
TEST_ASSERT_TRUE(ok2);
TEST_ASSERT_TRUE(s.count == 2);
TEST_ASSERT_NOT_NULL(s.lines[1]);
TEST_ASSERT_TRUE(s.lines[1]->nfields == 1);
assert_field_equals(&s.lines[1]->fields[0], "y");
bool ok3 = getseq(fp, &s, 1);
TEST_ASSERT_TRUE(ok3);
TEST_ASSERT_TRUE(s.count == 3);
TEST_ASSERT_NOT_NULL(s.lines[2]);
TEST_ASSERT_TRUE(s.lines[2]->nfields == 1);
assert_field_equals(&s.lines[2]->fields[0], "z");
/* Next call should hit EOF and return false; count should remain unchanged. */
bool ok4 = getseq(fp, &s, 1);
TEST_ASSERT_FALSE(ok4);
TEST_ASSERT_TRUE(s.count == 3);
delseq(&s);
fclose(fp);
}
/* Test: getseq works for both whichfile values independently. */
void test_getseq_works_for_both_files(void) {
FILE *fp1 = make_tempfile_with("a\nb\n");
FILE *fp2 = make_tempfile_with("c\nd\n");
struct seq s1, s2;
initseq(&s1);
initseq(&s2);
/* Read first line from file 1 */
TEST_ASSERT_TRUE(getseq(fp1, &s1, 1));
TEST_ASSERT_TRUE(s1.count == 1);
TEST_ASSERT_TRUE(s1.lines[0]->nfields == 1);
assert_field_equals(&s1.lines[0]->fields[0], "a");
/* Read first line from file 2 */
TEST_ASSERT_TRUE(getseq(fp2, &s2, 2));
TEST_ASSERT_TRUE(s2.count == 1);
TEST_ASSERT_TRUE(s2.lines[0]->nfields == 1);
assert_field_equals(&s2.lines[0]->fields[0], "c");
/* Read second line from each */
TEST_ASSERT_TRUE(getseq(fp1, &s1, 1));
TEST_ASSERT_TRUE(s1.count == 2);
assert_field_equals(&s1.lines[1]->fields[0], "b");
TEST_ASSERT_TRUE(getseq(fp2, &s2, 2));
TEST_ASSERT_TRUE(s2.count == 2);
assert_field_equals(&s2.lines[1]->fields[0], "d");
/* EOF on both */
TEST_ASSERT_FALSE(getseq(fp1, &s1, 1));
TEST_ASSERT_FALSE(getseq(fp2, &s2, 2));
delseq(&s1);
delseq(&s2);
fclose(fp1);
fclose(fp2);
}
/* Test: handle a line without a trailing newline */
void test_getseq_handles_line_without_trailing_newline(void) {
FILE *fp = make_tempfile_with("no-trailing-newline");
struct seq s;
initseq(&s);
TEST_ASSERT_TRUE(getseq(fp, &s, 1));
TEST_ASSERT_TRUE(s.count == 1);
TEST_ASSERT_NOT_NULL(s.lines[0]);
TEST_ASSERT_TRUE(s.lines[0]->nfields == 1);
assert_field_equals(&s.lines[0]->fields[0], "no-trailing-newline");
/* Next should be EOF */
TEST_ASSERT_FALSE(getseq(fp, &s, 1));
delseq(&s);
fclose(fp);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_getseq_reads_single_line_and_fields);
RUN_TEST(test_getseq_returns_false_on_empty_file);
RUN_TEST(test_getseq_reads_multiple_lines);
RUN_TEST(test_getseq_works_for_both_files);
RUN_TEST(test_getseq_handles_line_without_trailing_newline);
return UNITY_END();
}