#include "fibonacci_line_pattern.h" #include #include #include namespace { float widthOf(const std::string& word) { return static_cast(word.size()) * 10.0f; } } // namespace TEST(FibonacciLinePatternTest, WordCountFollowsFibonacciSequence) { radiantwave::FibonacciLinePattern pattern(13, 100000.0f, 10.0f, widthOf); // Enough words that the first sixteen lines never reach the end of the list, // so line counts follow the pure Fibonacci oscillation. std::vector words; for (int i = 0; i < 100; ++i) { words.push_back("w" + std::to_string(i)); } std::vector expected = {1, 1, 2, 3, 5, 8, 13, 8, 5, 3, 2, 1, 1, 2, 3, 5}; for (int count : expected) { std::vector line; int placed = pattern.nextLine(words, line); EXPECT_EQ(placed, count); EXPECT_EQ(line.size(), static_cast(count)); } } TEST(FibonacciLinePatternTest, SequencePeaksAtConfiguredWordCount) { // A 15-word peak (what a 1920px screen might ask for) becomes the apex of // the oscillation instead of a hardcoded 13. radiantwave::FibonacciLinePattern pattern(15, 100000.0f, 10.0f, widthOf); std::vector words; for (int i = 0; i < 100; ++i) { words.push_back("w" + std::to_string(i)); } std::vector expected = {1, 1, 2, 3, 5, 8, 13, 15, 13, 8, 5, 3, 2, 1, 1, 2}; for (int count : expected) { std::vector line; EXPECT_EQ(pattern.nextLine(words, line), count); } } TEST(FibonacciLinePatternTest, WidthCapTruncatesLines) { // Each word is 100px, space is 10px; the cap is 300px. radiantwave::FibonacciLinePattern pattern( 13, 300.0f, 10.0f, [](const std::string &) { return 100.0f; }); std::vector words = {"aaaa", "bbbb", "cccc", "dddd", "eeee"}; std::vector line; EXPECT_EQ(pattern.nextLine(words, line), 1); // target 1 line.clear(); EXPECT_EQ(pattern.nextLine(words, line), 1); // target 1 line.clear(); EXPECT_EQ(pattern.nextLine(words, line), 2); // target 2: 100 + 10 + 100 = 210 <= 300 line.clear(); // target 3: only "eeee" remains before the end of the list, so the line // stops with one word rather than wrapping mid-line. EXPECT_EQ(pattern.nextLine(words, line), 1); EXPECT_EQ(line[0], "eeee"); } TEST(FibonacciLinePatternTest, FirstWordAlwaysPlaced) { radiantwave::FibonacciLinePattern pattern( 13, 5.0f, 10.0f, [](const std::string &) { return 100.0f; }); std::vector words = {"aaa", "bbb"}; std::vector line; EXPECT_EQ(pattern.nextLine(words, line), 1); EXPECT_EQ(line[0], "aaa"); } TEST(FibonacciLinePatternTest, WrapsOnlyAtLineBoundaries) { radiantwave::FibonacciLinePattern pattern(13, 100000.0f, 10.0f, widthOf); std::vector words = {"a", "b", "c"}; std::vector> lines; for (int i = 0; i < 6; ++i) { std::vector line; pattern.nextLine(words, line); lines.push_back(line); } // Words are consumed in order and never wrap mid-line: every line is a // contiguous slice of "a b c a b c ...". ASSERT_EQ(lines[0].size(), 1u); EXPECT_EQ(lines[0][0], "a"); ASSERT_EQ(lines[1].size(), 1u); EXPECT_EQ(lines[1][0], "b"); ASSERT_EQ(lines[2].size(), 1u); // only "c" remains; the list ends, no wrap EXPECT_EQ(lines[2][0], "c"); ASSERT_EQ(lines[3].size(), 3u); // wraps at the line boundary instead EXPECT_EQ(lines[3][0], "a"); EXPECT_EQ(lines[3][1], "b"); EXPECT_EQ(lines[3][2], "c"); ASSERT_EQ(lines[4].size(), 3u); EXPECT_EQ(lines[4][0], "a"); ASSERT_EQ(lines[5].size(), 3u); EXPECT_EQ(lines[5][0], "a"); } TEST(FibonacciLinePatternTest, EmptyWordListYieldsZero) { radiantwave::FibonacciLinePattern pattern(13, 100.0f, 10.0f, widthOf); std::vector words; std::vector line; EXPECT_EQ(pattern.nextLine(words, line), 0); }