// g++ --std=c++11 test.cpp #include "test.h" #include "test.h" #include "fl/circular_buffer.h" #include "fl/namespace.h" using namespace fl; TEST_CASE("circular_buffer basic operations") { CircularBuffer buffer(5); CHECK(buffer.empty()); CHECK_EQ(buffer.size(), 0); buffer.push_back(1); buffer.push_back(2); buffer.push_back(3); CHECK_EQ(buffer.size(), 3); CHECK_FALSE(buffer.empty()); CHECK_FALSE(buffer.full()); CHECK_EQ(buffer.front(), 1); CHECK_EQ(buffer.back(), 3); int value; CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value, 1); CHECK_EQ(buffer.size(), 2); CHECK_EQ(buffer.front(), 2); } TEST_CASE("circular_buffer operator[]") { CircularBuffer buffer(5); CHECK(buffer.empty()); CHECK_EQ(buffer.size(), 0); buffer.push_back(1); buffer.push_back(2); CHECK_EQ(buffer.size(), 2); CHECK_EQ(buffer[0], 1); CHECK_EQ(buffer[1], 2); buffer.pop_front(nullptr); CHECK_EQ(2, buffer[0]); buffer.push_back(3); CHECK_EQ(2, buffer[0]); CHECK_EQ(3, buffer[1]); buffer.pop_back(nullptr); CHECK_EQ(2, buffer[0]); } TEST_CASE("circular_buffer overflow behavior") { CircularBuffer buffer(3); buffer.push_back(1); buffer.push_back(2); buffer.push_back(3); CHECK(buffer.full()); buffer.push_back(4); CHECK(buffer.full()); CHECK_EQ(buffer.size(), 3); int value; CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value, 2); CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value, 3); CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value, 4); CHECK(buffer.empty()); // CHECK_EQ(buffer.pop_front(), 0); // Returns default-constructed int (0) when empty CHECK_EQ(buffer.pop_front(&value), false); } TEST_CASE("circular_buffer edge cases") { CircularBuffer buffer(1); CHECK(buffer.empty()); CHECK_FALSE(buffer.full()); buffer.push_back(42); CHECK_FALSE(buffer.empty()); CHECK(buffer.full()); buffer.push_back(43); CHECK_EQ(buffer.front(), 43); CHECK_EQ(buffer.back(), 43); int value; bool ok = buffer.pop_front(&value); CHECK(ok); CHECK_EQ(value, 43); CHECK(buffer.empty()); } TEST_CASE("circular_buffer clear operation") { CircularBuffer buffer(5); buffer.push_back(1); buffer.push_back(2); buffer.push_back(3); CHECK_EQ(buffer.size(), 3); buffer.clear(); CHECK(buffer.empty()); CHECK_EQ(buffer.size(), 0); buffer.push_back(4); CHECK_EQ(buffer.front(), 4); CHECK_EQ(buffer.back(), 4); } TEST_CASE("circular_buffer indexing") { CircularBuffer buffer(5); buffer.push_back(10); buffer.push_back(20); buffer.push_back(30); CHECK_EQ(buffer[0], 10); CHECK_EQ(buffer[1], 20); CHECK_EQ(buffer[2], 30); buffer.pop_front(nullptr); buffer.push_back(40); CHECK_EQ(buffer[0], 20); CHECK_EQ(buffer[1], 30); CHECK_EQ(buffer[2], 40); } TEST_CASE("circular_buffer with custom type") { struct CustomType { int value; CustomType(int v = 0) : value(v) {} bool operator==(const CustomType& other) const { return value == other.value; } }; CircularBuffer buffer(3); buffer.push_back(CustomType(1)); buffer.push_back(CustomType(2)); buffer.push_back(CustomType(3)); CHECK_EQ(buffer.front().value, 1); CHECK_EQ(buffer.back().value, 3); buffer.push_back(CustomType(4)); CustomType value; CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value.value, 2); CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value.value, 3); CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value.value, 4); } TEST_CASE("circular_buffer writing to full buffer") { CircularBuffer buffer(3); // Fill the buffer buffer.push_back(1); buffer.push_back(2); buffer.push_back(3); CHECK(buffer.full()); // Write to full buffer buffer.push_back(4); CHECK(buffer.full()); CHECK_EQ(buffer.size(), 3); // Check that the oldest element was overwritten CHECK_EQ(buffer[0], 2); CHECK_EQ(buffer[1], 3); CHECK_EQ(buffer[2], 4); // Write multiple elements to full buffer buffer.push_back(5); buffer.push_back(6); CHECK(buffer.full()); CHECK_EQ(buffer.size(), 3); // Check that the buffer contains only the most recent elements CHECK_EQ(buffer[0], 4); CHECK_EQ(buffer[1], 5); CHECK_EQ(buffer[2], 6); // Verify front() and back() CHECK_EQ(buffer.front(), 4); CHECK_EQ(buffer.back(), 6); // Pop all elements and verify //CHECK_EQ(buffer.pop_front(), 4); //CHECK_EQ(buffer.pop_front(), 5); //CHECK_EQ(buffer.pop_front(), 6); int value; CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value, 4); CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value, 5); CHECK_EQ(buffer.pop_front(&value), true); CHECK_EQ(value, 6); CHECK(buffer.empty()); } #if 1 TEST_CASE("circular_buffer zero capacity") { CircularBuffer buffer(0); CHECK(buffer.empty()); CHECK(buffer.full()); CHECK_EQ(buffer.size(), 0); // Attempt to push an element buffer.push_back(1); // Buffer should now contain one element CHECK(buffer.empty()); CHECK(buffer.full()); CHECK_EQ(buffer.size(), 0); // Attempt to pop an element // CHECK_EQ(buffer.pop_front(), 0); int value; CHECK_EQ(buffer.pop_front(&value), false); // Buffer should be empty again CHECK(buffer.empty()); CHECK(buffer.full()); CHECK_EQ(buffer.size(), 0); } #endif TEST_CASE("circular_buffer pop_back operation") { CircularBuffer buffer(5); buffer.push_back(1); buffer.push_back(2); buffer.push_back(3); int value; CHECK_EQ(buffer.pop_back(&value), true); CHECK_EQ(value, 3); CHECK_EQ(buffer.size(), 2); CHECK_EQ(buffer.back(), 2); CHECK_EQ(buffer.pop_back(&value), true); CHECK_EQ(value, 2); CHECK_EQ(buffer.size(), 1); CHECK_EQ(buffer.front(), 1); CHECK_EQ(buffer.back(), 1); CHECK_EQ(buffer.pop_back(&value), true); CHECK_EQ(value, 1); CHECK(buffer.empty()); CHECK_EQ(buffer.pop_back(&value), false); } TEST_CASE("circular_buffer push_front operation") { CircularBuffer buffer(3); buffer.push_front(1); buffer.push_front(2); buffer.push_front(3); CHECK_EQ(buffer.size(), 3); CHECK_EQ(buffer.front(), 3); CHECK_EQ(buffer.back(), 1); buffer.push_front(4); CHECK_EQ(buffer.size(), 3); CHECK_EQ(buffer.front(), 4); CHECK_EQ(buffer.back(), 2); int value; CHECK_EQ(buffer.pop_back(&value), true); CHECK_EQ(value, 2); CHECK_EQ(buffer.pop_back(&value), true); CHECK_EQ(value, 3); CHECK_EQ(buffer.pop_back(&value), true); CHECK_EQ(value, 4); CHECK(buffer.empty()); }