tomato-testing/toxav/ring_buffer_test.cc
Green Sky 227425b90e Squashed 'external/toxcore/c-toxcore/' content from commit 67badf69
git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: 67badf69416a74e74f6d7eb51dd96f37282b8455
2023-07-25 11:53:09 +02:00

215 lines
4.9 KiB
C++

#include "ring_buffer.h"
#include <gtest/gtest.h>
#include <algorithm>
#include <cassert>
#include <vector>
namespace {
template <typename T>
class TypedRingBuffer;
template <typename T>
class TypedRingBuffer<T *> {
public:
explicit TypedRingBuffer(int size)
: rb_(rb_new(size))
{
}
~TypedRingBuffer() { rb_kill(rb_); }
TypedRingBuffer(TypedRingBuffer const &) = delete;
bool full() const { return rb_full(rb_); }
bool empty() const { return rb_empty(rb_); }
T *write(T *p) { return static_cast<T *>(rb_write(rb_, p)); }
bool read(T **p)
{
void *vp;
bool res = rb_read(rb_, &vp);
*p = static_cast<T *>(vp);
return res;
}
uint16_t size() const { return rb_size(rb_); }
uint16_t data(T **dest) const
{
std::vector<void *> vdest(size());
uint16_t res = rb_data(rb_, vdest.data());
for (uint16_t i = 0; i < size(); i++) {
dest[i] = static_cast<T *>(vdest.at(i));
}
return res;
}
bool contains(T *p) const
{
std::vector<T *> elts(size());
data(elts.data());
return std::find(elts.begin(), elts.end(), p) != elts.end();
}
bool ok() const { return rb_ != nullptr; }
private:
RingBuffer *rb_;
};
TEST(RingBuffer, EmptyBufferReportsEmpty)
{
TypedRingBuffer<int *> rb(10);
ASSERT_TRUE(rb.ok());
EXPECT_TRUE(rb.empty());
}
TEST(RingBuffer, EmptyBufferReportsNotFull)
{
TypedRingBuffer<int *> rb(10);
ASSERT_TRUE(rb.ok());
EXPECT_FALSE(rb.full());
}
TEST(RingBuffer, ZeroSizedRingBufferIsBothEmptyAndFull)
{
TypedRingBuffer<int *> rb(0);
ASSERT_TRUE(rb.ok());
EXPECT_TRUE(rb.empty());
EXPECT_TRUE(rb.full());
}
TEST(RingBuffer, WritingMakesBufferNotEmpty)
{
TypedRingBuffer<int *> rb(2);
ASSERT_TRUE(rb.ok());
int value0 = 123;
rb.write(&value0);
EXPECT_FALSE(rb.empty());
}
TEST(RingBuffer, WritingOneElementMakesBufferNotFull)
{
TypedRingBuffer<int *> rb(2);
ASSERT_TRUE(rb.ok());
int value0 = 123;
rb.write(&value0);
EXPECT_FALSE(rb.full());
}
TEST(RingBuffer, WritingAllElementsMakesBufferFull)
{
TypedRingBuffer<int *> rb(2);
ASSERT_TRUE(rb.ok());
int value0 = 123;
int value1 = 231;
rb.write(&value0);
rb.write(&value1);
EXPECT_TRUE(rb.full());
}
TEST(RingBuffer, ReadingElementFromFullBufferMakesItNotFull)
{
TypedRingBuffer<int *> rb(2);
ASSERT_TRUE(rb.ok());
int value0 = 123;
int value1 = 231;
rb.write(&value0);
rb.write(&value1);
EXPECT_TRUE(rb.full());
int *retrieved;
// Reading deletes the element.
EXPECT_TRUE(rb.read(&retrieved));
EXPECT_FALSE(rb.full());
}
TEST(RingBuffer, ZeroSizeBufferCanBeWrittenToOnce)
{
TypedRingBuffer<int *> rb(0);
ASSERT_TRUE(rb.ok());
int value0 = 123;
// Strange behaviour: we can write one element to a 0-size buffer.
EXPECT_EQ(nullptr, rb.write(&value0));
EXPECT_EQ(&value0, rb.write(&value0));
int *retrieved = nullptr;
// But then we can't read it.
EXPECT_FALSE(rb.read(&retrieved));
EXPECT_EQ(nullptr, retrieved);
}
TEST(RingBuffer, ReadingFromEmptyBufferFails)
{
TypedRingBuffer<int *> rb(2);
ASSERT_TRUE(rb.ok());
int *retrieved;
EXPECT_FALSE(rb.read(&retrieved));
}
TEST(RingBuffer, WritingToBufferWhenFullOverwritesBeginning)
{
TypedRingBuffer<int *> rb(2);
ASSERT_TRUE(rb.ok());
int value0 = 123;
int value1 = 231;
int value2 = 312;
int value3 = 432;
EXPECT_EQ(nullptr, rb.write(&value0));
EXPECT_EQ(nullptr, rb.write(&value1));
EXPECT_TRUE(rb.contains(&value0));
EXPECT_TRUE(rb.contains(&value1));
// Adding another element evicts the first element.
EXPECT_EQ(&value0, rb.write(&value2));
EXPECT_FALSE(rb.contains(&value0));
EXPECT_TRUE(rb.contains(&value2));
// Adding another evicts the second.
EXPECT_EQ(&value1, rb.write(&value3));
EXPECT_FALSE(rb.contains(&value1));
EXPECT_TRUE(rb.contains(&value3));
}
TEST(RingBuffer, SizeIsNumberOfElementsInBuffer)
{
TypedRingBuffer<int *> rb(10);
ASSERT_TRUE(rb.ok());
int value0 = 123;
EXPECT_EQ(rb.size(), 0);
rb.write(&value0);
EXPECT_EQ(rb.size(), 1);
rb.write(&value0);
EXPECT_EQ(rb.size(), 2);
rb.write(&value0);
EXPECT_EQ(rb.size(), 3);
rb.write(&value0);
EXPECT_EQ(rb.size(), 4);
int *retrieved;
rb.read(&retrieved);
EXPECT_EQ(rb.size(), 3);
rb.read(&retrieved);
EXPECT_EQ(rb.size(), 2);
rb.read(&retrieved);
EXPECT_EQ(rb.size(), 1);
rb.read(&retrieved);
EXPECT_EQ(rb.size(), 0);
}
TEST(RingBuffer, SizeIsLimitedByMaxSize)
{
TypedRingBuffer<int *> rb(4);
ASSERT_TRUE(rb.ok());
int value0 = 123;
rb.write(&value0);
rb.write(&value0);
rb.write(&value0);
rb.write(&value0);
EXPECT_EQ(rb.size(), 4);
// Add one more.
rb.write(&value0);
// Still size is 4.
EXPECT_EQ(rb.size(), 4);
}
} // namespace