Update tests
This commit is contained in:
@@ -477,6 +477,7 @@ namespace OpenVulkano
|
|||||||
else
|
else
|
||||||
return (Parent::head = (Parent::HeadId() + 1) % Capacity());
|
return (Parent::head = (Parent::HeadId() + 1) % Capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~RingBuffer() { Parent::Clear(); }
|
~RingBuffer() { Parent::Clear(); }
|
||||||
|
|
||||||
|
|||||||
@@ -13,167 +13,177 @@ using namespace OpenVulkano;
|
|||||||
|
|
||||||
// Helper to track construction/destruction
|
// Helper to track construction/destruction
|
||||||
struct Tracked {
|
struct Tracked {
|
||||||
static inline int ctorCount = 0;
|
static inline int ctorCount = 0;
|
||||||
static inline int dtorCount = 0;
|
static inline int dtorCount = 0;
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
Tracked(int v = 0) : value(v) { ++ctorCount; }
|
Tracked(int v = 0) : value(v) { ++ctorCount; }
|
||||||
Tracked(const Tracked& other) : value(other.value) { ++ctorCount; }
|
Tracked(const Tracked& other) : value(other.value) { ++ctorCount; }
|
||||||
Tracked(Tracked&& other) noexcept : value(other.value) { ++ctorCount; }
|
Tracked(Tracked&& other) noexcept : value(other.value) { ++ctorCount; }
|
||||||
~Tracked() { ++dtorCount; }
|
~Tracked() { ++dtorCount; }
|
||||||
|
|
||||||
Tracked& operator=(const Tracked&) = default;
|
Tracked& operator=(const Tracked&) = default;
|
||||||
Tracked& operator=(Tracked&&) = default;
|
Tracked& operator=(Tracked&&) = default;
|
||||||
|
|
||||||
friend bool operator==(const Tracked& lhs, const Tracked& rhs) {
|
friend bool operator==(const Tracked& lhs, const Tracked& rhs) {
|
||||||
return lhs.value == rhs.value;
|
return lhs.value == rhs.value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void reset_tracking() {
|
void reset_tracking() {
|
||||||
Tracked::ctorCount = 0;
|
Tracked::ctorCount = 0;
|
||||||
Tracked::dtorCount = 0;
|
Tracked::dtorCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("RingBuffer Tracking Destruction", "[RingBuffer][Tracked]") {
|
TEST_CASE("RingBuffer Tracking Destruction", "[RingBuffer][Tracked]") {
|
||||||
reset_tracking();
|
reset_tracking();
|
||||||
|
|
||||||
{
|
{
|
||||||
RingBuffer<Tracked, 4> buf;
|
RingBuffer<Tracked, 4> buf;
|
||||||
buf.Push(Tracked(1));
|
buf.Push(Tracked(1));
|
||||||
buf.Push(Tracked(2));
|
buf.Push(Tracked(2));
|
||||||
buf.PopFront();
|
buf.PopFront();
|
||||||
buf.Clear();
|
buf.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(Tracked::dtorCount == Tracked::ctorCount);
|
REQUIRE(Tracked::dtorCount == Tracked::ctorCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("RingBuffer Push and Pop Operations", "[RingBuffer]") {
|
TEST_CASE("RingBuffer Push and Pop Operations", "[RingBuffer]") {
|
||||||
RingBuffer<int, 3> buf;
|
RingBuffer<int, 3> buf;
|
||||||
|
|
||||||
buf.Push(1);
|
buf.Push(1);
|
||||||
buf.Push(2);
|
buf.Push(2);
|
||||||
buf.Push(3);
|
buf.Push(3);
|
||||||
|
|
||||||
REQUIRE(buf.Count() == 3);
|
REQUIRE(buf.Count() == 3);
|
||||||
REQUIRE_FALSE(buf.HasFree());
|
REQUIRE_FALSE(buf.HasFree());
|
||||||
|
|
||||||
SECTION("PopFront/Back correctness") {
|
SECTION("PopFront/Back correctness") {
|
||||||
REQUIRE(buf.PopBack() == 1);
|
REQUIRE(buf.PopBack() == 1);
|
||||||
REQUIRE(buf.PopFront() == 3);
|
REQUIRE(buf.PopFront() == 3);
|
||||||
REQUIRE(buf.Count() == 1);
|
REQUIRE(buf.Count() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Clear empties the buffer") {
|
SECTION("Clear empties the buffer") {
|
||||||
buf.Clear();
|
buf.Clear();
|
||||||
REQUIRE(buf.IsEmpty());
|
REQUIRE(buf.IsEmpty());
|
||||||
REQUIRE(buf.Count() == 0);
|
REQUIRE(buf.Count() == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PushBack and PushFront Overwrite Logic", "[RingBuffer]") {
|
TEST_CASE("PushBack and PushFront Overwrite Logic", "[RingBuffer]") {
|
||||||
RingBuffer<int, 2> buf;
|
RingBuffer<int, 2> buf;
|
||||||
buf.Push(1);
|
buf.Push(1);
|
||||||
buf.Push(2);
|
buf.Push(2);
|
||||||
|
|
||||||
auto overwrittenFront = buf.PushFront(3);
|
auto overwrittenFront = buf.PushFront(3);
|
||||||
REQUIRE(overwrittenFront.has_value());
|
REQUIRE(overwrittenFront.has_value());
|
||||||
REQUIRE(overwrittenFront.value() == 1);
|
REQUIRE(overwrittenFront.value() == 1);
|
||||||
|
|
||||||
auto overwrittenBack = buf.PushBack(4);
|
auto overwrittenBack = buf.PushBack(4);
|
||||||
REQUIRE(overwrittenBack.has_value());
|
REQUIRE(overwrittenBack.has_value());
|
||||||
REQUIRE(overwrittenBack.value() == 2);
|
REQUIRE(overwrittenBack.value() == 2);
|
||||||
|
|
||||||
REQUIRE(buf.Front() == 3);
|
REQUIRE(buf.Front() == 3);
|
||||||
REQUIRE(buf.Back() == 4);
|
REQUIRE(buf.Back() == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("at() bounds checking", "[RingBuffer]") {
|
TEST_CASE("at() bounds checking", "[RingBuffer]") {
|
||||||
RingBuffer<int, 3> buf;
|
RingBuffer<int, 3> buf;
|
||||||
buf.Push(100);
|
buf.Push(100);
|
||||||
buf.Push(200);
|
buf.Push(200);
|
||||||
|
|
||||||
REQUIRE(buf.at(0) == 100);
|
REQUIRE(buf.at(0) == 100);
|
||||||
REQUIRE(buf.at(1) == 200);
|
REQUIRE(buf.at(1) == 200);
|
||||||
REQUIRE_THROWS_AS(buf.at(2), std::range_error);
|
REQUIRE_THROWS_AS(buf.at(2), std::range_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Index-based Access and Wraparound", "[RingBuffer]") {
|
TEST_CASE("Index-based Access and Wraparound", "[RingBuffer]") {
|
||||||
RingBuffer<int, 3> buf;
|
RingBuffer<int, 3> buf;
|
||||||
|
|
||||||
buf.Push(1);
|
buf.Push(1);
|
||||||
buf.Push(2);
|
buf.Push(2);
|
||||||
buf.Push(3);
|
buf.Push(3);
|
||||||
REQUIRE(buf[0] == 1);
|
REQUIRE(buf[0] == 1);
|
||||||
REQUIRE(buf[1] == 2);
|
REQUIRE(buf[1] == 2);
|
||||||
REQUIRE(buf[2] == 3);
|
REQUIRE(buf[2] == 3);
|
||||||
|
|
||||||
buf.PopBack(); // Remove 1
|
buf.PopBack();
|
||||||
buf.Push(4); // Overwrites oldest (2)
|
buf.Push(4);
|
||||||
|
|
||||||
REQUIRE(buf[0] == 2); // Wrap-around behavior depends on ring position
|
REQUIRE(buf[0] == 2);
|
||||||
|
REQUIRE(buf[1] == 3);
|
||||||
|
REQUIRE(buf[2] == 4);
|
||||||
|
|
||||||
|
// Test full wraparound
|
||||||
|
buf.Push(5);
|
||||||
|
buf.Push(6);
|
||||||
|
|
||||||
|
REQUIRE(buf[0] == 4);
|
||||||
|
REQUIRE(buf[1] == 5);
|
||||||
|
REQUIRE(buf[2] == 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Emplace and EmplaceBack/Front work correctly", "[RingBuffer]") {
|
TEST_CASE("Emplace and EmplaceBack/Front work correctly", "[RingBuffer]") {
|
||||||
RingBuffer<std::string, 2> buf;
|
RingBuffer<std::string, 2> buf;
|
||||||
|
|
||||||
buf.Emplace("first");
|
buf.Emplace("first");
|
||||||
buf.EmplaceBack("second");
|
buf.EmplaceBack("second");
|
||||||
|
|
||||||
REQUIRE(buf.Count() == 2);
|
REQUIRE(buf.Count() == 2);
|
||||||
REQUIRE(buf[1] == "first");
|
REQUIRE(buf[1] == "first");
|
||||||
REQUIRE(buf[0] == "second");
|
REQUIRE(buf[0] == "second");
|
||||||
|
|
||||||
auto overwritten = buf.EmplaceFront("new");
|
auto overwritten = buf.EmplaceFront("new");
|
||||||
REQUIRE(overwritten.has_value());
|
REQUIRE(overwritten.has_value());
|
||||||
REQUIRE(overwritten.value() == "second");
|
REQUIRE(overwritten.value() == "second");
|
||||||
REQUIRE(buf.Front() == "new");
|
REQUIRE(buf.Front() == "new");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Iterators forward and reverse", "[RingBuffer]") {
|
TEST_CASE("Iterators forward and reverse", "[RingBuffer]") {
|
||||||
RingBuffer<int, 4> buf;
|
RingBuffer<int, 4> buf;
|
||||||
buf.Push(10);
|
buf.Push(10);
|
||||||
buf.Push(20);
|
buf.Push(20);
|
||||||
buf.Push(30);
|
buf.Push(30);
|
||||||
|
|
||||||
std::vector<int> forward;
|
std::vector<int> forward;
|
||||||
for (int val : buf) forward.push_back(val);
|
for (int val : buf) forward.push_back(val);
|
||||||
REQUIRE(forward == std::vector<int>{10, 20, 30});
|
REQUIRE(forward == std::vector<int>{10, 20, 30});
|
||||||
|
|
||||||
std::vector<int> reverse;
|
std::vector<int> reverse;
|
||||||
for (auto it = buf.rbegin(); it != buf.rend(); ++it)
|
for (auto it = buf.rbegin(); it != buf.rend(); ++it)
|
||||||
reverse.push_back(*it);
|
reverse.push_back(*it);
|
||||||
REQUIRE(reverse == std::vector<int>{30, 20, 10});
|
REQUIRE(reverse == std::vector<int>{30, 20, 10});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Const correctness in iterators", "[RingBuffer][Const]") {
|
TEST_CASE("Const correctness in iterators", "[RingBuffer][Const]") {
|
||||||
RingBuffer<int, 3> buf;
|
RingBuffer<int, 3> buf;
|
||||||
buf.Push(5);
|
buf.Push(5);
|
||||||
buf.Push(6);
|
buf.Push(6);
|
||||||
|
|
||||||
const auto& constBuf = buf;
|
const auto& constBuf = buf;
|
||||||
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
for (auto it = constBuf.cbegin(); it != constBuf.cend(); ++it) {
|
for (auto it = constBuf.cbegin(); it != constBuf.cend(); ++it) {
|
||||||
oss << *it << " ";
|
oss << *it << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(oss.str() == "5 6 ");
|
REQUIRE(oss.str() == "5 6 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Dynamic RingBuffer behaves like static", "[RingBuffer][Dynamic]") {
|
TEST_CASE("Dynamic RingBuffer behaves like static", "[RingBuffer][Dynamic]") {
|
||||||
RingBuffer<int> buf(5);
|
RingBuffer<int> buf(5);
|
||||||
|
|
||||||
for (int i = 0; i < 5; ++i)
|
for (int i = 0; i < 5; ++i)
|
||||||
buf.Push(i * 10);
|
buf.Push(i * 10);
|
||||||
|
|
||||||
REQUIRE(buf.Count() == 5);
|
REQUIRE(buf.Count() == 5);
|
||||||
REQUIRE_FALSE(buf.HasFree());
|
REQUIRE_FALSE(buf.HasFree());
|
||||||
REQUIRE(buf.Front() == 40);
|
REQUIRE(buf.Front() == 40);
|
||||||
REQUIRE(buf.Back() == 0);
|
REQUIRE(buf.Back() == 0);
|
||||||
|
|
||||||
auto val = buf.PopBack();
|
auto val = buf.PopBack();
|
||||||
REQUIRE(val == 0);
|
REQUIRE(val == 0);
|
||||||
REQUIRE(buf.Count() == 4);
|
REQUIRE(buf.Count() == 4);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user