File size: 7,206 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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#include "../../unity/unity.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* We rely on being included after the fmt implementation, so we can
   access static functions and globals like get_paragraph, set_prefix,
   get_prefix, word, word_limit, etc. */

/* Helper: persistent buffer for set_prefix. */
static char prefix_buf[64];

/* Reset core global state to a known baseline before each test. */
static void reset_state(void)
{
    /* Options */
    crown = false;
    tagged = false;
    split = false;
    uniform = false;

    /* Prefix: empty */
    strcpy(prefix_buf, "");
    set_prefix(prefix_buf);

    /* Widths: defaults safe; fmt_paragraph isn't called by get_paragraph,
       but keep sane values anyway. */
    max_width = 75; /* WIDTH */
    goal_width = (max_width * (100 - 7)) / 100; /* LEEWAY = 7 */

    /* Dynamic state */
    in_column = 0;
    out_column = 0;
    tabs = false;

    prefix_indent = 0;
    first_indent = 0;
    other_indent = 0;

    next_char = 0;
    next_prefix_indent = 0;
    last_line_length = 0;

    /* Paragraph buffers */
    wptr = parabuf;
    word_limit = word;
}

/* Helper: create a FILE* from a string using tmpfile. */
static FILE *make_file(const char *s)
{
    FILE *f = tmpfile();
    TEST_ASSERT_NOT_NULL_MESSAGE(f, "tmpfile() failed");
    if (fputs(s, f) == EOF)
    {
        fclose(f);
        TEST_FAIL_MESSAGE("fputs() to tmpfile failed");
    }
    rewind(f);
    return f;
}

/* Count words currently parsed for the paragraph. */
static int count_words(void)
{
    return (int)(word_limit - word);
}

void setUp(void)
{
    /* Setup code here */
    reset_state();
}

void tearDown(void)
{
    /* Cleanup code here */
}

/* 1) Basic: single-line paragraph, no prefix, default mode */
static void test_get_paragraph_basic_single_line(void)
{
    const char *input = "hello world\n\n"; /* paragraph then blank line */
    FILE *f = make_file(input);

    /* Initialize next_char as fmt() would */
    next_char = get_prefix(f);

    TEST_ASSERT_TRUE_MESSAGE(get_paragraph(f), "get_paragraph should find a paragraph");

    /* Should have parsed two words: hello, world */
    TEST_ASSERT_EQUAL_INT(2, count_words());

    /* Indentation expectations */
    TEST_ASSERT_EQUAL_INT(0, prefix_indent);
    TEST_ASSERT_EQUAL_INT(0, first_indent);
    TEST_ASSERT_EQUAL_INT(0, other_indent);

    /* Words content and flags */
    TEST_ASSERT_EQUAL_INT(5, word[0].length);
    TEST_ASSERT_TRUE(!word[0].final);
    TEST_ASSERT_TRUE(word_limit[-1].final);
    TEST_ASSERT_TRUE(word_limit[-1].period); /* get_paragraph forces last word period=true */

    /* After paragraph, next_char should be '\n' for the following blank line */
    TEST_ASSERT_EQUAL_INT('\n', next_char);

    fclose(f);
}

/* 2) Crown mode: second+ lines must have same indent as second line */
static void test_get_paragraph_crown_mode(void)
{
    crown = true;
    const char *input =
        "one\n"
        "  two words\n"
        "  three\n"
        "   four\n"; /* fourth line different indent -> next paragraph */
    FILE *f = make_file(input);

    next_char = get_prefix(f);

    TEST_ASSERT_TRUE_MESSAGE(get_paragraph(f), "crown: should read a paragraph");

    /* First three lines included: 1 + 2 + 1 = 4 words */
    TEST_ASSERT_EQUAL_INT(4, count_words());

    /* First line indent 0, secondary indent equals second line's indent (2). */
    TEST_ASSERT_EQUAL_INT(0, first_indent);
    TEST_ASSERT_EQUAL_INT(2, other_indent);

    /* Next char should be 'f' from "   four" */
    TEST_ASSERT_EQUAL_INT('f', next_char);

    /* Last word of the paragraph is final and period-marked by get_paragraph */
    TEST_ASSERT_TRUE(word_limit[-1].final);
    TEST_ASSERT_TRUE(word_limit[-1].period);

    fclose(f);
}

/* 3) Tagged mode: first and second lines must have different indents.
      If equal, paragraph is just the first line, and other_indent updated. */
static void test_get_paragraph_tagged_mode_requires_diff_indent(void)
{
    tagged = true;
    const char *input =
        "first\n"
        "second\n"; /* same indent (0), so only first line included */

    FILE *f = make_file(input);
    next_char = get_prefix(f);

    TEST_ASSERT_TRUE_MESSAGE(get_paragraph(f), "tagged: should read a paragraph");

    /* Only the first line included: 1 word */
    TEST_ASSERT_EQUAL_INT(1, count_words());

    /* First indent 0; other_indent should become DEF_INDENT when identical */
    TEST_ASSERT_EQUAL_INT(0, first_indent);
    TEST_ASSERT_EQUAL_INT(DEF_INDENT, other_indent);

    /* Next paragraph starts at 's' from second line */
    TEST_ASSERT_EQUAL_INT('s', next_char);

    fclose(f);
}

/* 4) Split-only mode: a paragraph is a single non-blank line */
static void test_get_paragraph_split_only_single_line(void)
{
    split = true;
    const char *input =
        "aaa bbb\n"
        "ccc ddd\n";

    FILE *f = make_file(input);
    next_char = get_prefix(f);

    TEST_ASSERT_TRUE_MESSAGE(get_paragraph(f), "split: should read a single-line paragraph");

    /* Only first line included: 2 words */
    TEST_ASSERT_EQUAL_INT(2, count_words());

    /* other_indent must equal first_indent in split mode */
    TEST_ASSERT_EQUAL_INT(first_indent, other_indent);

    /* Next char should be 'c' from second line */
    TEST_ASSERT_EQUAL_INT('c', next_char);

    fclose(f);
}

/* 5) Prefix handling: lines must begin with the prefix; words exclude the prefix. */
static void test_get_paragraph_with_prefix_included_lines(void)
{
    /* Set a non-empty prefix ">>" */
    strcpy(prefix_buf, ">>");
    set_prefix(prefix_buf);

    const char *input =
        ">> a b\n"
        ">> c\n";
    FILE *f = make_file(input);

    next_char = get_prefix(f);

    TEST_ASSERT_TRUE_MESSAGE(get_paragraph(f), "prefix: should read a paragraph with prefixed lines");

    /* Words from after the prefix should be captured: a, b, c */
    TEST_ASSERT_EQUAL_INT(3, count_words());

    /* The first word should be 'a' */
    TEST_ASSERT_EQUAL_INT(1, word[0].length);
    TEST_ASSERT_EQUAL_CHAR('a', word[0].text[0]);

    /* prefix_indent should be 0 given no leading spaces before prefix */
    TEST_ASSERT_EQUAL_INT(0, prefix_indent);

    /* Next char should be EOF (end of file) */
    TEST_ASSERT_EQUAL_INT(EOF, next_char);

    /* Last word flags */
    TEST_ASSERT_TRUE(word_limit[-1].final);
    TEST_ASSERT_TRUE(word_limit[-1].period);

    fclose(f);
}

/* 6) EOF before any paragraph: should return false and not touch buffers */
static void test_get_paragraph_empty_file_returns_false(void)
{
    const char *input = ""; /* empty file */
    FILE *f = make_file(input);

    next_char = get_prefix(f); /* sets to EOF */

    TEST_ASSERT_FALSE_MESSAGE(get_paragraph(f), "Empty file: should return false");

    fclose(f);
}

int main(void)
{
    UNITY_BEGIN();
    RUN_TEST(test_get_paragraph_basic_single_line);
    RUN_TEST(test_get_paragraph_crown_mode);
    RUN_TEST(test_get_paragraph_tagged_mode_requires_diff_indent);
    RUN_TEST(test_get_paragraph_split_only_single_line);
    RUN_TEST(test_get_paragraph_with_prefix_included_lines);
    RUN_TEST(test_get_paragraph_empty_file_returns_false);
    return UNITY_END();
}