coreutils / tests /fmt /tests_for_fmt_paragraph.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/* We rely on the program's globals and the static function under test:
- static void fmt_paragraph(void);
- Globals: word[], word_limit, max_width, goal_width, first_indent, other_indent, last_line_length
These are declared/defined in the fmt program source that includes this test. */
/* Helper to reset a slice of the global word array to zero. */
static void reset_words_range(int from, int to_exclusive) {
/* word is a global array defined in the program. */
memset(&word[from], 0, (size_t)(to_exclusive - from) * sizeof(word[0]));
}
/* Helper to prepare a paragraph with given lengths and spaces.
count: number of real words
lengths[count], spaces[count] (spaces for each word; last one's space value is harmless)
sentinel_len: a known value to verify restoration after fmt_paragraph
*/
static void prepare_words(const int *lengths, const int *spaces, int count, int sentinel_len) {
/* Clear a safe range including the sentinel slot. */
reset_words_range(0, count + 1);
for (int i = 0; i < count; i++) {
word[i].length = lengths[i];
word[i].space = spaces ? spaces[i] : 1;
word[i].paren = 0;
word[i].period = 0;
word[i].punct = 0;
word[i].final = 0;
word[i].text = NULL; /* Not used by fmt_paragraph */
/* best_cost/next_break/line_length are set by fmt_paragraph */
}
/* Set word_limit to point just past the last real word. */
word_limit = &word[count];
/* Set a recognizable sentinel length to ensure it's restored. */
word_limit->length = sentinel_len;
/* Also zero fields that fmt_paragraph expects to use for the sentinel. */
word_limit->best_cost = 0;
word_limit->next_break = NULL;
word_limit->line_length = 0;
}
void setUp(void) {
/* Ensure a neutral default for globals possibly affecting costs. */
last_line_length = 0;
first_indent = 0;
other_indent = 0;
max_width = 0;
goal_width = 0;
}
void tearDown(void) {
/* Nothing persistent to clean. */
}
/* Test 1: Forced wrap with two words not fitting the max width.
Expect: first line contains only word[0], second line word[1]. */
static void test_fmt_paragraph_forced_wrap(void) {
/* Two words of length 3, one space between them -> combined line 7 */
const int lengths[] = {3, 3};
const int spaces[] = {1, 1};
prepare_words(lengths, spaces, 2, 123);
max_width = 5; /* Force wrap: 7 >= 5 so only one word can fit per line */
goal_width = 5; /* Goal same as max for simple short-cost expectations */
first_indent = 0;
other_indent = 0;
last_line_length = 0;
fmt_paragraph();
/* Verify breaking decisions */
TEST_ASSERT_EQUAL_PTR(&word[1], word[0].next_break);
TEST_ASSERT_EQUAL_INT(3, word[0].line_length); /* indent 0 + len 3 */
TEST_ASSERT_EQUAL_PTR(word_limit, word[1].next_break);
TEST_ASSERT_EQUAL_INT(3, word[1].line_length); /* indent 0 + len 3 */
/* Sentinel length restored */
TEST_ASSERT_EQUAL_INT(123, word_limit->length);
}
/* Test 2: Two words fit on one line with indentation; verify line_length includes indents and best break goes to word_limit. */
static void test_fmt_paragraph_two_words_single_line_with_indent(void) {
const int lengths[] = {3, 3};
const int spaces[] = {1, 1};
prepare_words(lengths, spaces, 2, 99);
max_width = 20;
goal_width = 20;
first_indent = 2;
other_indent = 4;
fmt_paragraph();
/* With ample width and large goal, the best is to keep both words on the first line. */
TEST_ASSERT_EQUAL_PTR(word_limit, word[0].next_break);
/* line_length = first_indent + 3 + 1 + 3 = 2 + 7 = 9 */
TEST_ASSERT_EQUAL_INT(9, word[0].line_length);
/* Second word alone (as if starting a line) uses other_indent. */
TEST_ASSERT_EQUAL_PTR(word_limit, word[1].next_break);
TEST_ASSERT_EQUAL_INT(other_indent + 3, word[1].line_length); /* 4 + 3 = 7 */
TEST_ASSERT_EQUAL_INT(99, word_limit->length);
}
/* Test 3: Three words, small width forces one word per line.
Verify the next_break chain and the computed line_length values. */
static void test_fmt_paragraph_three_words_forced_each_line(void) {
const int lengths[] = {3, 3, 3};
const int spaces[] = {1, 1, 1};
prepare_words(lengths, spaces, 3, 77);
max_width = 5; /* 3 + 1 + 3 = 7 >= 5, so only one per line */
goal_width = 5;
first_indent = 0;
other_indent = 0;
fmt_paragraph();
TEST_ASSERT_EQUAL_PTR(&word[1], word[0].next_break);
TEST_ASSERT_EQUAL_INT(3, word[0].line_length);
TEST_ASSERT_EQUAL_PTR(&word[2], word[1].next_break);
TEST_ASSERT_EQUAL_INT(3, word[1].line_length);
TEST_ASSERT_EQUAL_PTR(word_limit, word[2].next_break);
TEST_ASSERT_EQUAL_INT(3, word[2].line_length);
TEST_ASSERT_EQUAL_INT(77, word_limit->length);
}
/* Test 4: last_line_length influences the first-line decision via raggedness.
Construct a tie on short-costs for len=3 vs len=7 around goal=5, then
set last_line_length=10 to prefer len=7 (smaller raggedness). */
static void test_fmt_paragraph_raggedness_with_last_line_length(void) {
const int lengths[] = {3, 3};
const int spaces[] = {1, 1};
prepare_words(lengths, spaces, 2, 55);
max_width = 20; /* Allow both options (3 and 7) */
goal_width = 5; /* |5-3| == |5-7| -> tie in short-cost */
first_indent = 0;
other_indent = 0;
last_line_length = 10; /* Penalize len=3 more than len=7 */
fmt_paragraph();
/* Expect the first line to include both words due to smaller raggedness penalty */
TEST_ASSERT_EQUAL_PTR(word_limit, word[0].next_break);
TEST_ASSERT_EQUAL_INT(7, word[0].line_length); /* 3 + 1 + 3 */
TEST_ASSERT_EQUAL_PTR(word_limit, word[1].next_break);
TEST_ASSERT_EQUAL_INT(3, word[1].line_length);
TEST_ASSERT_EQUAL_INT(55, word_limit->length);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_fmt_paragraph_forced_wrap);
RUN_TEST(test_fmt_paragraph_two_words_single_line_with_indent);
RUN_TEST(test_fmt_paragraph_three_words_forced_each_line);
RUN_TEST(test_fmt_paragraph_raggedness_with_last_line_length);
return UNITY_END();
}