initial commit

This commit is contained in:
NeilClack
2026-08-07 14:51:41 -05:00
commit 9251b3a196
604 changed files with 464448 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
#include "fibonacci_line_pattern.h"
#include <gtest/gtest.h>
#include <string>
#include <vector>
namespace {
float widthOf(const std::string& word)
{
return static_cast<float>(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<std::string> words;
for (int i = 0; i < 100; ++i)
{
words.push_back("w" + std::to_string(i));
}
std::vector<int> expected = {1, 1, 2, 3, 5, 8, 13, 8, 5, 3, 2, 1, 1, 2, 3, 5};
for (int count : expected)
{
std::vector<std::string> line;
int placed = pattern.nextLine(words, line);
EXPECT_EQ(placed, count);
EXPECT_EQ(line.size(), static_cast<size_t>(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<std::string> words;
for (int i = 0; i < 100; ++i)
{
words.push_back("w" + std::to_string(i));
}
std::vector<int> expected = {1, 1, 2, 3, 5, 8, 13, 15, 13, 8, 5, 3, 2, 1, 1, 2};
for (int count : expected)
{
std::vector<std::string> 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<std::string> words = {"aaaa", "bbbb", "cccc", "dddd", "eeee"};
std::vector<std::string> 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<std::string> words = {"aaa", "bbb"};
std::vector<std::string> 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<std::string> words = {"a", "b", "c"};
std::vector<std::vector<std::string>> lines;
for (int i = 0; i < 6; ++i)
{
std::vector<std::string> 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<std::string> words;
std::vector<std::string> line;
EXPECT_EQ(pattern.nextLine(words, line), 0);
}