diff --git a/tests/Data/Containers/RingBufferTest.cpp b/tests/Data/Containers/RingBufferTest.cpp index 5e01357..348df8d 100644 --- a/tests/Data/Containers/RingBufferTest.cpp +++ b/tests/Data/Containers/RingBufferTest.cpp @@ -15,7 +15,8 @@ using namespace OpenVulkano; // Helper to track construction/destruction -struct Tracked { +struct Tracked +{ static inline int ctorCount = 0; static inline int dtorCount = 0; static inline int moveCount = 0; @@ -23,44 +24,62 @@ struct Tracked { int value; Tracked(int v = 0) : value(v) { ++ctorCount; } - Tracked(const Tracked& other) : value(other.value) { ++ctorCount; ++copyCount; } - Tracked(Tracked&& other) noexcept : value(other.value) { ++ctorCount; ++moveCount; } + + Tracked(const Tracked& other) : value(other.value) + { + ++ctorCount; + ++copyCount; + } + + Tracked(Tracked&& other) noexcept: value(other.value) + { + ++ctorCount; + ++moveCount; + } + ~Tracked() { ++dtorCount; } - Tracked& operator=(const Tracked& other) { + Tracked& operator=(const Tracked& other) + { value = other.value; ++copyCount; return *this; } - - Tracked& operator=(Tracked&& other) noexcept { + + Tracked& operator=(Tracked&& other) noexcept + { value = other.value; ++moveCount; return *this; } - friend bool operator==(const Tracked& lhs, const Tracked& rhs) { + friend bool operator==(const Tracked& lhs, const Tracked& rhs) + { return lhs.value == rhs.value; } }; -void reset_tracking() { +void reset_tracking() +{ Tracked::ctorCount = 0; Tracked::dtorCount = 0; Tracked::moveCount = 0; Tracked::copyCount = 0; } -TEST_CASE("RingBuffer Basic Construction", "[RingBuffer]") { - SECTION("Static buffer construction") { +TEST_CASE("RingBuffer Basic Construction", "[RingBuffer]") +{ + SECTION("Static buffer construction") + { RingBuffer buf; REQUIRE(buf.Capacity() == 5); REQUIRE(buf.IsEmpty()); REQUIRE(buf.Count() == 0); REQUIRE(buf.HasFree()); } - - SECTION("Dynamic buffer construction") { + + SECTION("Dynamic buffer construction") + { RingBuffer buf(10); REQUIRE(buf.Capacity() == 10); REQUIRE(buf.IsEmpty()); @@ -69,7 +88,8 @@ TEST_CASE("RingBuffer Basic Construction", "[RingBuffer]") { } } -TEST_CASE("RingBuffer Tracking Destruction", "[RingBuffer][Tracked]") { +TEST_CASE("RingBuffer Tracking Destruction", "[RingBuffer][Tracked]") +{ reset_tracking(); { @@ -83,38 +103,43 @@ TEST_CASE("RingBuffer Tracking Destruction", "[RingBuffer][Tracked]") { REQUIRE(Tracked::dtorCount == Tracked::ctorCount); } -TEST_CASE("RingBuffer Move and Copy Semantics", "[RingBuffer][Tracked]") { +TEST_CASE("RingBuffer Move and Copy Semantics", "[RingBuffer][Tracked]") +{ reset_tracking(); - + { RingBuffer buf; - - SECTION("Push with move") { + + SECTION("Push with move") + { Tracked t(42); buf.Push(std::move(t)); REQUIRE(Tracked::moveCount >= 1); REQUIRE(buf.Front().value == 42); } - - SECTION("Push with copy") { + + SECTION("Push with copy") + { Tracked t(42); buf.Push(t); REQUIRE(Tracked::copyCount >= 1); REQUIRE(buf.Front().value == 42); } - - SECTION("Emplace constructs in-place") { + + SECTION("Emplace constructs in-place") + { int initialCtors = Tracked::ctorCount; buf.Emplace(99); REQUIRE(Tracked::ctorCount == initialCtors + 1); REQUIRE(buf.Front().value == 99); } } - + REQUIRE(Tracked::dtorCount == Tracked::ctorCount); } -TEST_CASE("RingBuffer Push and Pop Operations", "[RingBuffer]") { +TEST_CASE("RingBuffer Push and Pop Operations", "[RingBuffer]") +{ RingBuffer buf; buf.Push(1); @@ -124,7 +149,8 @@ TEST_CASE("RingBuffer Push and Pop Operations", "[RingBuffer]") { REQUIRE(buf.Count() == 3); REQUIRE_FALSE(buf.HasFree()); - SECTION("PopFront/Back correctness") { + SECTION("PopFront/Back correctness") + { REQUIRE(buf.PopBack() == 1); REQUIRE(buf.PopFront() == 3); REQUIRE(buf.Count() == 1); @@ -134,34 +160,38 @@ TEST_CASE("RingBuffer Push and Pop Operations", "[RingBuffer]") { REQUIRE_THROWS_AS(buf.PopBack(), std::underflow_error); } - SECTION("Clear empties the buffer") { + SECTION("Clear empties the buffer") + { buf.Clear(); REQUIRE(buf.IsEmpty()); REQUIRE(buf.Count() == 0); } - - SECTION("Front and Back access") { + + SECTION("Front and Back access") + { REQUIRE(buf.Front() == 3); REQUIRE(buf.Back() == 1); - + buf.PopFront(); REQUIRE(buf.Front() == 2); REQUIRE(buf.Back() == 1); - + buf.PopBack(); REQUIRE(buf.Front() == 2); REQUIRE(buf.Back() == 2); } } -TEST_CASE("RingBuffer PushNoOverwrite operation", "[RingBuffer]") { +TEST_CASE("RingBuffer PushNoOverwrite operation", "[RingBuffer]") +{ RingBuffer buf; - + buf.PushNoOverwrite(1); buf.PushNoOverwrite(2); REQUIRE_THROWS_AS(buf.PushNoOverwrite(3), std::overflow_error); - - SECTION("EmplaceNoOverwrite") { + + SECTION("EmplaceNoOverwrite") + { RingBuffer strBuf; strBuf.EmplaceNoOverwrite("first"); strBuf.EmplaceNoOverwrite("second"); @@ -169,18 +199,21 @@ TEST_CASE("RingBuffer PushNoOverwrite operation", "[RingBuffer]") { } } -TEST_CASE("RingBuffer PushAndOverwrite operation", "[RingBuffer]") { +TEST_CASE("RingBuffer PushAndOverwrite operation", "[RingBuffer]") +{ RingBuffer buf; - - SECTION("Cannot use PushAndOverwrite when buffer not full") { + + SECTION("Cannot use PushAndOverwrite when buffer not full") + { buf.Push(1); REQUIRE_THROWS_AS(buf.PushAndOverwrite(5), std::runtime_error); } - - SECTION("PushAndOverwrite returns overwritten value") { + + SECTION("PushAndOverwrite returns overwritten value") + { buf.Fill(42); REQUIRE(buf.Count() == 2); - + int overwritten = buf.PushAndOverwrite(99); REQUIRE(overwritten == 42); REQUIRE(buf.Front() == 99); @@ -188,12 +221,14 @@ TEST_CASE("RingBuffer PushAndOverwrite operation", "[RingBuffer]") { } } -TEST_CASE("PushBack and PushFront Overwrite Logic", "[RingBuffer]") { +TEST_CASE("PushBack and PushFront Overwrite Logic", "[RingBuffer]") +{ RingBuffer buf; buf.Push(1); buf.Push(2); - SECTION("PushFront overwrites correctly") { + SECTION("PushFront overwrites correctly") + { auto overwrittenFront = buf.PushFront(3); REQUIRE(overwrittenFront.has_value()); REQUIRE(overwrittenFront.value() == 1); @@ -201,29 +236,32 @@ TEST_CASE("PushBack and PushFront Overwrite Logic", "[RingBuffer]") { REQUIRE(buf.Back() == 2); } - SECTION("PushBack overwrites correctly") { + SECTION("PushBack overwrites correctly") + { auto overwrittenBack = buf.PushBack(4); REQUIRE(overwrittenBack.has_value()); REQUIRE(overwrittenBack.value() == 1); REQUIRE(buf.Front() == 2); REQUIRE(buf.Back() == 4); } - - SECTION("PushFront with available space doesn't overwrite") { + + SECTION("PushFront with available space doesn't overwrite") + { RingBuffer buf2; buf2.Push(10); - + auto result = buf2.PushFront(20); REQUIRE_FALSE(result.has_value()); REQUIRE(buf2.Count() == 2); REQUIRE(buf2.Front() == 20); REQUIRE(buf2.Back() == 10); } - - SECTION("PushBack with available space doesn't overwrite") { + + SECTION("PushBack with available space doesn't overwrite") + { RingBuffer buf2; buf2.Push(10); - + auto result = buf2.PushBack(20); REQUIRE_FALSE(result.has_value()); REQUIRE(buf2.Count() == 2); @@ -232,7 +270,8 @@ TEST_CASE("PushBack and PushFront Overwrite Logic", "[RingBuffer]") { } } -TEST_CASE("at() bounds checking", "[RingBuffer]") { +TEST_CASE("at() bounds checking", "[RingBuffer]") +{ RingBuffer buf; buf.Push(100); buf.Push(200); @@ -240,8 +279,9 @@ TEST_CASE("at() bounds checking", "[RingBuffer]") { REQUIRE(buf.at(0) == 100); REQUIRE(buf.at(1) == 200); REQUIRE_THROWS_AS(buf.at(2), std::range_error); - - SECTION("const at() works correctly") { + + SECTION("const at() works correctly") + { const auto& constBuf = buf; REQUIRE(constBuf.at(0) == 100); REQUIRE(constBuf.at(1) == 200); @@ -249,7 +289,8 @@ TEST_CASE("at() bounds checking", "[RingBuffer]") { } } -TEST_CASE("Index-based Access and Wraparound", "[RingBuffer]") { +TEST_CASE("Index-based Access and Wraparound", "[RingBuffer]") +{ RingBuffer buf; buf.Push(1); @@ -273,46 +314,52 @@ TEST_CASE("Index-based Access and Wraparound", "[RingBuffer]") { REQUIRE(buf[0] == 4); REQUIRE(buf[1] == 5); REQUIRE(buf[2] == 6); - - SECTION("Wraparound with power-of-2 size") { + + SECTION("Wraparound with power-of-2 size") + { RingBuffer powBuf; // Power of 2 size for different code path - - for (int i = 1; i <= 4; i++) { + + for (int i = 1; i <= 4; i++) + { powBuf.Push(i); } - + REQUIRE(powBuf[0] == 1); REQUIRE(powBuf[3] == 4); - + powBuf.PopBack(); powBuf.Push(5); - + REQUIRE(powBuf[0] == 2); REQUIRE(powBuf[3] == 5); } } -TEST_CASE("Fill operation", "[RingBuffer]") { +TEST_CASE("Fill operation", "[RingBuffer]") +{ RingBuffer buf; - - SECTION("Fill empty buffer") { + + SECTION("Fill empty buffer") + { buf.Fill(42); REQUIRE(buf.Count() == 5); REQUIRE_FALSE(buf.HasFree()); - - for (int i = 0; i < 5; i++) { + + for (int i = 0; i < 5; i++) + { REQUIRE(buf[i] == 42); } } - - SECTION("Fill partially full buffer") { + + SECTION("Fill partially full buffer") + { buf.Push(1); buf.Push(2); - + buf.Fill(99); REQUIRE(buf.Count() == 5); REQUIRE_FALSE(buf.HasFree()); - + REQUIRE(buf[0] == 1); REQUIRE(buf[1] == 2); REQUIRE(buf[2] == 99); @@ -321,7 +368,8 @@ TEST_CASE("Fill operation", "[RingBuffer]") { } } -TEST_CASE("Emplace and EmplaceBack/Front work correctly", "[RingBuffer]") { +TEST_CASE("Emplace and EmplaceBack/Front work correctly", "[RingBuffer]") +{ RingBuffer buf; buf.Emplace("first"); @@ -335,8 +383,9 @@ TEST_CASE("Emplace and EmplaceBack/Front work correctly", "[RingBuffer]") { REQUIRE(overwritten.has_value()); REQUIRE(overwritten.value() == "second"); REQUIRE(buf.Front() == "new"); - - SECTION("EmplaceNoOverwrite throws when full") { + + SECTION("EmplaceNoOverwrite throws when full") + { RingBuffer buf2; buf2.EmplaceNoOverwrite("one"); buf2.EmplaceNoOverwrite("two"); @@ -344,26 +393,30 @@ TEST_CASE("Emplace and EmplaceBack/Front work correctly", "[RingBuffer]") { } } -TEST_CASE("Iterators forward and reverse", "[RingBuffer]") { +TEST_CASE("Iterators forward and reverse", "[RingBuffer]") +{ RingBuffer buf; buf.Push(10); buf.Push(20); buf.Push(30); - SECTION("Forward iteration") { + SECTION("Forward iteration") + { std::vector forward; - for (int val : buf) forward.push_back(val); - REQUIRE(forward == std::vector{10, 20, 30}); + for (int val: buf) forward.push_back(val); + REQUIRE(forward == std::vector {10, 20, 30}); } - SECTION("Reverse iteration") { + SECTION("Reverse iteration") + { std::vector reverse; for (auto it = buf.rbegin(); it != buf.rend(); ++it) reverse.push_back(*it); - REQUIRE(reverse == std::vector{30, 20, 10}); + REQUIRE(reverse == std::vector {30, 20, 10}); } - - SECTION("Iterator decrement") { + + SECTION("Iterator decrement") + { auto it = buf.end(); --it; REQUIRE(*it == 30); @@ -372,8 +425,9 @@ TEST_CASE("Iterators forward and reverse", "[RingBuffer]") { --it; REQUIRE(*it == 10); } - - SECTION("Reverse iterator decrement") { + + SECTION("Reverse iterator decrement") + { auto it = buf.rend(); --it; REQUIRE(*it == 10); @@ -382,54 +436,63 @@ TEST_CASE("Iterators forward and reverse", "[RingBuffer]") { --it; REQUIRE(*it == 30); } - - SECTION("Iterator post-increment/decrement") { + + SECTION("Iterator post-increment/decrement") + { auto it = buf.begin(); REQUIRE(*(it++) == 10); REQUIRE(*it == 20); - + auto it2 = --buf.end(); REQUIRE(*(it2--) == 30); REQUIRE(*it2 == 20); } - - SECTION("Empty buffer iteration") { + + SECTION("Empty buffer iteration") + { RingBuffer emptyBuf; REQUIRE(emptyBuf.begin() == emptyBuf.end()); REQUIRE(emptyBuf.rbegin() == emptyBuf.rend()); } } -TEST_CASE("Const correctness in iterators", "[RingBuffer][Const]") { +TEST_CASE("Const correctness in iterators", "[RingBuffer][Const]") +{ RingBuffer buf; buf.Push(5); buf.Push(6); const auto& constBuf = buf; - SECTION("const_iterator usage") { + SECTION("const_iterator usage") + { std::ostringstream oss; - for (auto it = constBuf.cbegin(); it != constBuf.cend(); ++it) { + for (auto it = constBuf.cbegin(); it != constBuf.cend(); ++it) + { oss << *it << " "; } REQUIRE(oss.str() == "5 6 "); } - - SECTION("const rbegin/rend usage") { + + SECTION("const rbegin/rend usage") + { std::vector values; - for (auto it = constBuf.crbegin(); it != constBuf.crend(); ++it) { + for (auto it = constBuf.crbegin(); it != constBuf.crend(); ++it) + { values.push_back(*it); } - REQUIRE(values == std::vector{6, 5}); + REQUIRE(values == std::vector {6, 5}); } - - SECTION("const operator[]") { + + SECTION("const operator[]") + { REQUIRE(constBuf[0] == 5); REQUIRE(constBuf[1] == 6); } } -TEST_CASE("Dynamic RingBuffer behaves like static", "[RingBuffer][Dynamic]") { +TEST_CASE("Dynamic RingBuffer behaves like static", "[RingBuffer][Dynamic]") +{ RingBuffer buf(5); for (int i = 0; i < 5; ++i) @@ -443,12 +506,13 @@ TEST_CASE("Dynamic RingBuffer behaves like static", "[RingBuffer][Dynamic]") { auto val = buf.PopBack(); REQUIRE(val == 0); REQUIRE(buf.Count() == 4); - - SECTION("Dynamic buffer wraparound") { + + SECTION("Dynamic buffer wraparound") + { buf.Push(50); REQUIRE(buf.Front() == 50); REQUIRE(buf.Back() == 10); - + buf.Push(60); REQUIRE(buf[0] == 20); REQUIRE(buf[1] == 30); @@ -458,112 +522,133 @@ TEST_CASE("Dynamic RingBuffer behaves like static", "[RingBuffer][Dynamic]") { } } -TEST_CASE("RingBuffer with complex types", "[RingBuffer][Complex]") { +TEST_CASE("RingBuffer with complex types", "[RingBuffer][Complex]") +{ RingBuffer, 3> buf; - - buf.Push(std::vector{1, 2, 3}); - buf.Emplace(std::initializer_list{4, 5, 6}); - + + buf.Push(std::vector {1, 2, 3}); + buf.Emplace(std::initializer_list {4, 5, 6}); + REQUIRE(buf.Count() == 2); REQUIRE(buf.Front()[0] == 4); REQUIRE(buf.Front()[2] == 6); REQUIRE(buf.Back()[0] == 1); REQUIRE(buf.Back()[2] == 3); - - const auto ret = buf.PushFront(std::vector{7, 8, 9}); + + const auto ret = buf.PushFront(std::vector {7, 8, 9}); REQUIRE(!ret.has_value()); REQUIRE(buf.Front()[0] == 7); - + buf.Clear(); REQUIRE(buf.IsEmpty()); } -TEST_CASE("Iterator operations with wrapped buffer", "[RingBuffer][Iterators]") { +TEST_CASE("Iterator operations with wrapped buffer", "[RingBuffer][Iterators]") +{ RingBuffer buf; - + // Fill buffer - for (int i = 1; i <= 5; i++) { + for (int i = 1; i <= 5; i++) + { buf.Push(i); } - + // Force wraparound buf.PopBack(); buf.PopBack(); buf.Push(6); buf.Push(7); - + // Buffer should now be: 3, 4, 5, 6, 7 with internal wraparound - + std::vector values; - for (auto val : buf) { + for (auto val: buf) + { values.push_back(val); } - - REQUIRE(values == std::vector{3, 4, 5, 6, 7}); - + + REQUIRE(values == std::vector {3, 4, 5, 6, 7}); + std::vector reverseValues; - for (auto it = buf.rbegin(); it != buf.rend(); ++it) { + for (auto it = buf.rbegin(); it != buf.rend(); ++it) + { reverseValues.push_back(*it); } - - REQUIRE(reverseValues == std::vector{7, 6, 5, 4, 3}); + + REQUIRE(reverseValues == std::vector {7, 6, 5, 4, 3}); } -TEST_CASE("Edge cases", "[RingBuffer][EdgeCases]") { - SECTION("Capacity of 1") { +TEST_CASE("Edge cases", "[RingBuffer][EdgeCases]") +{ + SECTION("Capacity of 1") + { RingBuffer buf; REQUIRE(buf.Capacity() == 1); REQUIRE(buf.IsEmpty()); - + buf.Push(42); REQUIRE(buf.Front() == 42); REQUIRE(buf.Back() == 42); REQUIRE_FALSE(buf.HasFree()); - + buf.Push(99); REQUIRE(buf.Front() == 99); REQUIRE(buf.Back() == 99); - + buf.PopFront(); REQUIRE(buf.IsEmpty()); REQUIRE_THROWS_AS(buf.PopFront(), std::underflow_error); } - - SECTION("Dynamic buffer with size 1") { + + SECTION("Dynamic buffer with size 1") + { RingBuffer buf(1); buf.Push(42); REQUIRE(buf.Front() == 42); REQUIRE_FALSE(buf.HasFree()); - + buf.Push(99); REQUIRE(buf.Front() == 99); } } -TEST_CASE("Algorithm compatibility", "[RingBuffer][Algorithms]") { +TEST_CASE("Algorithm compatibility", "[RingBuffer][Algorithms]") +{ RingBuffer buf; - for (int i = 1; i <= 5; i++) { + for (int i = 1; i <= 5; i++) + { buf.Push(i); } - - SECTION("std::find") { + + SECTION("std::find") + { auto it = std::find(buf.begin(), buf.end(), 3); REQUIRE(it != buf.end()); REQUIRE(*it == 3); - + auto notFound = std::find(buf.begin(), buf.end(), 99); REQUIRE(notFound == buf.end()); } - - SECTION("std::count") { + + SECTION("std::count") + { buf.Push(3); // Overwrites the 1 int count = std::count(buf.begin(), buf.end(), 3); REQUIRE(count == 2); } - - SECTION("std::copy") { + + SECTION("std::copy") + { std::vector target(5); std::copy(buf.begin(), buf.end(), target.begin()); - REQUIRE(target == std::vector{1, 2, 3, 4, 5}); + REQUIRE(target == std::vector {1, 2, 3, 4, 5}); } +} + +TEST_CASE("Class size", "[RingBuffer]") +{ + REQUIRE(sizeof(RingBuffer) == 32); + REQUIRE(sizeof(RingBuffer) == 24); + REQUIRE(sizeof(RingBuffer) == 24); + REQUIRE(sizeof(RingBuffer) == 32); } \ No newline at end of file diff --git a/tests/Math/RunningAverageTest.cpp b/tests/Math/RunningAverageTest.cpp index 7312687..e2f81d4 100644 --- a/tests/Math/RunningAverageTest.cpp +++ b/tests/Math/RunningAverageTest.cpp @@ -13,161 +13,162 @@ using namespace OpenVulkano::Math; TEST_CASE("RunningAverage Basic Functionality - Integer Type", "[RunningAverage]") { - SECTION("Dynamic Size Constructor with Default Value") - { - RunningAverage avg(5); - REQUIRE(avg.Get() == 0); - } - - SECTION("Dynamic Size Constructor with Custom Default") - { - RunningAverage avg(5, 10); - REQUIRE(avg.Get() == 10); - } - - SECTION("Static Size Constructor with Default Value") - { - RunningAverage avg; - REQUIRE(avg.Get() == 0); - } - - SECTION("Static Size Constructor with Custom Default") - { - RunningAverage avg(10); - REQUIRE(avg.Get() == 10); - } - - SECTION("Push Single Value") - { - RunningAverage avg(5, 0); - avg.Push(5); - REQUIRE(avg.Get() == 1); // (0+0+0+0+5)/5 = 1 - } - - SECTION("Push Multiple Values") - { - RunningAverage avg(4, 0); - avg.Push(4); - avg.Push(8); - avg.Push(12); - avg.Push(16); - REQUIRE(avg.Get() == 10); // (4+8+12+16)/4 = 10 - } - - SECTION("Push with Overwrite") - { - RunningAverage avg(3, 0); - avg.Push(3); - avg.Push(6); - avg.Push(9); - REQUIRE(avg.Get() == 6); // (3+6+9)/3 = 6 - - avg.Push(12); // Overwrite 3 - REQUIRE(avg.Get() == 9); // (6+9+12)/3 = 9 - } + SECTION("Dynamic Size Constructor with Default Value") + { + RunningAverage avg(5); + REQUIRE(avg.Get() == 0); + } + + SECTION("Dynamic Size Constructor with Custom Default") + { + RunningAverage avg(5, 10); + REQUIRE(avg.Get() == 10); + } + + SECTION("Static Size Constructor with Default Value") + { + RunningAverage avg; + REQUIRE(avg.Get() == 0); + } + + SECTION("Static Size Constructor with Custom Default") + { + RunningAverage avg(10); + REQUIRE(avg.Get() == 10); + } + + SECTION("Push Single Value") + { + RunningAverage avg(5, 0); + avg.Push(5); + REQUIRE(avg.Get() == 1); // (0+0+0+0+5)/5 = 1 + } + + SECTION("Push Multiple Values") + { + RunningAverage avg(4, 0); + avg.Push(4); + avg.Push(8); + avg.Push(12); + avg.Push(16); + REQUIRE(avg.Get() == 10); // (4+8+12+16)/4 = 10 + } + + SECTION("Push with Overwrite") + { + RunningAverage avg(3, 0); + avg.Push(3); + avg.Push(6); + avg.Push(9); + REQUIRE(avg.Get() == 6); // (3+6+9)/3 = 6 + + avg.Push(12); // Overwrite 3 + REQUIRE(avg.Get() == 9); // (6+9+12)/3 = 9 + } } TEST_CASE("RunningAverage with Floating Point Types", "[RunningAverage]") { - SECTION("Basic Floating Point Operation") - { - RunningAverage avg(3, 0.0); - avg.Push(1.5); - avg.Push(2.5); - avg.Push(3.5); - REQUIRE(avg.Get() == Catch::Approx(2.5)); // (1.5+2.5+3.5)/3 = 2.5 - } - - SECTION("Recalculation with Floating Point") - { - // Set recalculation to happen after 3 operations - RunningAverage::max(), true, 3> avg(3, 0.0); - avg.Push(1.0); - avg.Push(2.0); - avg.Push(3.0); // This should trigger recalculation - REQUIRE(avg.Get() == Catch::Approx(2.0)); // (1.0+2.0+3.0)/3 = 2.0 - - // Push another value to check that recalculation didn't affect the result - avg.Push(4.0); - REQUIRE(avg.Get() == Catch::Approx(3.0)); // (2.0+3.0+4.0)/3 = 3.0 - } - - SECTION("Manual Recalculation") - { - RunningAverage avg(3, 0.0); - avg.Push(1.5); - avg.Push(2.5); - avg.Push(3.5); - - // Force recalculation and verify it doesn't change the result - avg.Recalculate(); - REQUIRE(avg.Get() == Catch::Approx(2.5)); - } + SECTION("Basic Floating Point Operation") + { + RunningAverage avg(3, 0.0); + avg.Push(1.5); + avg.Push(2.5); + avg.Push(3.5); + REQUIRE(avg.Get() == Catch::Approx(2.5)); // (1.5+2.5+3.5)/3 = 2.5 + } + + SECTION("Recalculation with Floating Point") + { + // Set recalculation to happen after 3 operations + RunningAverage::max(), true, 3> avg(3, 0.0); + avg.Push(1.0); + avg.Push(2.0); + avg.Push(3.0); // This should trigger recalculation + REQUIRE(avg.Get() == Catch::Approx(2.0)); // (1.0+2.0+3.0)/3 = 2.0 + + // Push another value to check that recalculation didn't affect the result + avg.Push(4.0); + REQUIRE(avg.Get() == Catch::Approx(3.0)); // (2.0+3.0+4.0)/3 = 3.0 + } + + SECTION("Manual Recalculation") + { + RunningAverage avg(3, 0.0); + avg.Push(1.5); + avg.Push(2.5); + avg.Push(3.5); + + // Force recalculation and verify it doesn't change the result + avg.Recalculate(); + REQUIRE(avg.Get() == Catch::Approx(2.5)); + } } TEST_CASE("RunningAverage Edge Cases", "[RunningAverage]") { - SECTION("Large Values") - { - RunningAverage avg(3, 0); - avg.Push(1000000); - avg.Push(2000000); - avg.Push(3000000); - REQUIRE(avg.Get() == 2000000); - } - - SECTION("Negative Values") - { - RunningAverage avg(3, 0); - avg.Push(-10); - avg.Push(-20); - avg.Push(-30); - REQUIRE(avg.Get() == -20); - } - - SECTION("Mixed Sign Values") - { - RunningAverage avg(4, 0); - avg.Push(-10); - avg.Push(10); - avg.Push(-10); - avg.Push(10); - REQUIRE(avg.Get() == 0); - } + SECTION("Large Values") + { + RunningAverage avg(3, 0); + avg.Push(1000000); + avg.Push(2000000); + avg.Push(3000000); + REQUIRE(avg.Get() == 2000000); + } + + SECTION("Negative Values") + { + RunningAverage avg(3, 0); + avg.Push(-10); + avg.Push(-20); + avg.Push(-30); + REQUIRE(avg.Get() == -20); + } + + SECTION("Mixed Sign Values") + { + RunningAverage avg(4, 0); + avg.Push(-10); + avg.Push(10); + avg.Push(-10); + avg.Push(10); + REQUIRE(avg.Get() == 0); + } } TEST_CASE("Custom Types with RunningAverage", "[RunningAverage]") { - SECTION("Vector Type Average") - { - RunningAverage avg(3, Vector2f(0, 0)); - avg.Push(Vector2f(1, 2)); - avg.Push(Vector2f(3, 4)); - avg.Push(Vector2f(5, 6)); - - Vector2f result = avg.Get(); - REQUIRE(result.x == Catch::Approx(3.0f)); - REQUIRE(result.y == Catch::Approx(4.0f)); - } + SECTION("Vector Type Average") + { + RunningAverage avg(3, Vector2f(0, 0)); + avg.Push(Vector2f(1, 2)); + avg.Push(Vector2f(3, 4)); + avg.Push(Vector2f(5, 6)); + + Vector2f result = avg.Get(); + REQUIRE(result.x == Catch::Approx(3.0f)); + REQUIRE(result.y == Catch::Approx(4.0f)); + } } // This test specifically checks the correctness of recalculation for floating point TEST_CASE("Precision with Floating Point Types", "[RunningAverage]") { - SECTION("Accumulation Error Correction") - { - // Create a running average that would normally suffer from floating point errors - // Force recalculation after 20 operations - RunningAverage::max(), true, 20> avg(5, 0.0); - - // Push values that would cause floating point rounding errors - for (int i = 0; i < 100; i++) { - avg.Push(0.1); // 0.1 cannot be represented exactly in binary floating point - } - - // Check that the result is still accurate due to periodic recalculation - REQUIRE(avg.Get() == Catch::Approx(0.1).epsilon(0.0001)); - } + SECTION("Accumulation Error Correction") + { + // Create a running average that would normally suffer from floating point errors + // Force recalculation after 20 operations + RunningAverage::max(), true, 20> avg(5, 0.0); + + // Push values that would cause floating point rounding errors + for (int i = 0; i < 100; i++) + { + avg.Push(0.1); // 0.1 cannot be represented exactly in binary floating point + } + + // Check that the result is still accurate due to periodic recalculation + REQUIRE(avg.Get() == Catch::Approx(0.1).epsilon(0.0001)); + } } TEST_CASE("Class size", "[RunningAverage]")