Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some tests for our ring_buffer implementation. #964

Merged
merged 1 commit into from
Jul 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ include(CompileGTest)

# The actual unit tests follow.
#
unit_test(toxav ring_buffer)
unit_test(toxav rtp)
unit_test(toxcore crypto_core)
unit_test(toxcore util)
Expand Down
9 changes: 9 additions & 0 deletions toxav/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ cc_library(
deps = ["//c-toxcore/toxcore:ccompat"],
)

cc_test(
name = "ring_buffer_test",
srcs = ["ring_buffer_test.cc"],
deps = [
":ring_buffer",
"@com_google_googletest//:gtest_main",
],
)

cc_library(
name = "bwcontroller",
srcs = ["bwcontroller.c"],
Expand Down
8 changes: 8 additions & 0 deletions toxav/ring_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include <stdbool.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Ring buffer */
typedef struct RingBuffer RingBuffer;
bool rb_full(const RingBuffer *b);
Expand All @@ -36,4 +40,8 @@ void rb_kill(RingBuffer *b);
uint16_t rb_size(const RingBuffer *b);
uint16_t rb_data(const RingBuffer *b, void **dest);

#ifdef __cplusplus
}
#endif

#endif /* RING_BUFFER_H */
196 changes: 196 additions & 0 deletions toxav/ring_buffer_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
#include "ring_buffer.h"

#include <algorithm>
#include <cassert>
#include <vector>

#include <gtest/gtest.h>

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