#include "../../unity/unity.h" #include #include #include /* 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(); }