File size: 5,628 Bytes
78d2150 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
#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();
} |