blob: ed388f32d43375b3ab0baf3bd922c960a0c0ab48 [file] [log] [blame]
#include "aos/containers/ring_buffer.h"
#include <memory>
#include <ostream>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "gtest/gtest.h"
namespace aos::testing {
// A class which is implicitly convertible to and from int, and tracks object
// lifetimes.
struct TrackedInt {
enum class State { kNoValue, kAlive, kDestroyed };
static int instance_count;
int value;
State state;
TrackedInt(int new_value) : value(new_value), state(State::kAlive) {
++instance_count;
}
TrackedInt(const TrackedInt &other) = delete;
TrackedInt(TrackedInt &&other) : value(other.value), state(other.state) {
CHECK(other.state != State::kDestroyed);
other.state = State::kNoValue;
++instance_count;
}
~TrackedInt() {
CHECK(state != State::kDestroyed);
state = State::kDestroyed;
--instance_count;
CHECK_GE(instance_count, 0);
}
TrackedInt &operator=(const TrackedInt &other) = delete;
TrackedInt &operator=(TrackedInt &&other) {
CHECK(state != State::kDestroyed);
CHECK(other.state != State::kDestroyed);
state = other.state;
other.state = State::kNoValue;
value = other.value;
return *this;
}
operator int() const {
CHECK(state == State::kAlive);
return value;
}
};
int TrackedInt::instance_count;
struct TrackedIntTracker {
TrackedIntTracker() {
CHECK_EQ(0, TrackedInt::instance_count) << ": Instances alive before test";
}
~TrackedIntTracker() {
CHECK_EQ(0, TrackedInt::instance_count) << ": Instances alive after test";
}
};
class RingBufferTest : public ::testing::Test {
public:
RingBufferTest() {}
protected:
TrackedIntTracker tracked_int_tracker_;
RingBuffer<TrackedInt, 10> buffer_;
};
// Test if the RingBuffer is empty when initialized properly
TEST_F(RingBufferTest, DefaultIsEmpty) {
// The RingBuffer should have a size of 0, a capacity of 10 (note that it was
// initialized as 10), have no items, and not be full
ASSERT_EQ(0u, buffer_.size());
ASSERT_EQ(10u, buffer_.capacity());
ASSERT_TRUE(buffer_.empty());
ASSERT_FALSE(buffer_.full());
}
// Test that the RingBuffer can fill it's entire capacity and read back the data
TEST_F(RingBufferTest, CanAddData) {
ASSERT_TRUE(buffer_.empty());
// Add sequential numbers to the RingBuffer
// (the value of each item is it's index #)
for (size_t i = 0; i < buffer_.capacity(); ++i) {
// The buffer shouldn't be full yet, and it's size should be how many items
// we've added so far. Once that happens, we add another item
ASSERT_FALSE(buffer_.full());
ASSERT_EQ(i, buffer_.size());
buffer_.Push(i);
// The buffer shouldn't be empty and it's size should be 1 more since we
// just added an item. Also, the last item in the buffer should equal the
// one we just added
ASSERT_FALSE(buffer_.empty());
ASSERT_EQ(i + 1, buffer_.size());
ASSERT_EQ(i, buffer_[i]);
}
ASSERT_TRUE(buffer_.full());
}
// Tests that the RingBuffer properly loops back and starts overwriting from the
// first element after being filled up
TEST_F(RingBufferTest, OverfillData) {
// Add numbers 0-24 to the RingBuffer
for (int i = 0; i < 25; ++i) {
buffer_.Push(i);
}
// It should now be full
ASSERT_TRUE(buffer_.full());
// Since the buffer is a size of 10 and has been filled up 2.5 times, it
// should now contain the numbers 15-24
for (size_t i = 0; i < buffer_.size(); ++i) {
ASSERT_EQ(15 + i, buffer_[i]);
}
}
// Tests shifting from the front of the ringbuffer.
TEST_F(RingBufferTest, RingBufferShift) {
// Add numbers 0-24 to the RingBuffer
for (int i = 0; i < 25; ++i) {
buffer_.Push(i);
}
// It should now be full
ASSERT_TRUE(buffer_.full());
buffer_.Shift();
buffer_.Shift();
buffer_.Shift();
ASSERT_EQ(buffer_.size(), 7);
// The buffer should now contain the numbers 18-24
for (size_t i = 0; i < buffer_.size(); ++i) {
ASSERT_EQ(18 + i, buffer_[i]);
}
}
// Test that the buffer works after Reset.
TEST_F(RingBufferTest, ResetWorks) {
// Over fill it, and then clear it out.
ASSERT_TRUE(buffer_.empty());
for (size_t i = 0; i < 53; ++i) {
buffer_.Push(i);
}
ASSERT_TRUE(buffer_.full());
buffer_.Reset();
ASSERT_TRUE(buffer_.empty());
// Now, add numbers 0-9 to the RingBuffer.
for (int i = 0; i < 10; ++i) {
buffer_.Push(i);
}
// It should now be full.
ASSERT_TRUE(buffer_.full());
// The last 10 numbers were added 0-9, so verify that is what is in the
// buffer.
for (size_t i = 0; i < buffer_.size(); ++i) {
ASSERT_EQ(i, buffer_[i]);
}
}
// Test that an iterator over the buffer works.
TEST_F(RingBufferTest, Iterator) {
// Over fill it, and then clear it out.
ASSERT_TRUE(buffer_.empty());
for (int i = 0; i < 12; ++i) {
buffer_.Push(i);
}
int i = 0;
for (int element : buffer_) {
EXPECT_EQ(i + 2, element);
++i;
}
EXPECT_EQ(i, buffer_.size());
}
// Test that a const iterator over the buffer works.
TEST_F(RingBufferTest, CIterator) {
// Over fill it, and then clear it out.
ASSERT_TRUE(buffer_.empty());
for (int i = 0; i < 12; ++i) {
buffer_.Push(i);
}
const RingBuffer<TrackedInt, 10> &cbuffer = buffer_;
int i = 0;
for (const int element : cbuffer) {
EXPECT_EQ(i + 2, element);
++i;
}
EXPECT_EQ(i, buffer_.size());
}
} // namespace aos::testing