summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--toxav/BUILD.bazel9
-rw-r--r--toxav/ring_buffer.h8
-rw-r--r--toxav/ring_buffer_test.cc196
4 files changed, 214 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8cd26f43..7acc5c97 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -338,6 +338,7 @@ include(CompileGTest)
338 338
339# The actual unit tests follow. 339# The actual unit tests follow.
340# 340#
341unit_test(toxav ring_buffer)
341unit_test(toxav rtp) 342unit_test(toxav rtp)
342unit_test(toxcore crypto_core) 343unit_test(toxcore crypto_core)
343unit_test(toxcore util) 344unit_test(toxcore util)
diff --git a/toxav/BUILD.bazel b/toxav/BUILD.bazel
index a5d49e0d..dbe57b6c 100644
--- a/toxav/BUILD.bazel
+++ b/toxav/BUILD.bazel
@@ -18,6 +18,15 @@ cc_library(
18 deps = ["//c-toxcore/toxcore:ccompat"], 18 deps = ["//c-toxcore/toxcore:ccompat"],
19) 19)
20 20
21cc_test(
22 name = "ring_buffer_test",
23 srcs = ["ring_buffer_test.cc"],
24 deps = [
25 ":ring_buffer",
26 "@com_google_googletest//:gtest_main",
27 ],
28)
29
21cc_library( 30cc_library(
22 name = "bwcontroller", 31 name = "bwcontroller",
23 srcs = ["bwcontroller.c"], 32 srcs = ["bwcontroller.c"],
diff --git a/toxav/ring_buffer.h b/toxav/ring_buffer.h
index 036461c1..1b52cdf2 100644
--- a/toxav/ring_buffer.h
+++ b/toxav/ring_buffer.h
@@ -25,6 +25,10 @@
25#include <stdbool.h> 25#include <stdbool.h>
26#include <stdint.h> 26#include <stdint.h>
27 27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
28/* Ring buffer */ 32/* Ring buffer */
29typedef struct RingBuffer RingBuffer; 33typedef struct RingBuffer RingBuffer;
30bool rb_full(const RingBuffer *b); 34bool rb_full(const RingBuffer *b);
@@ -36,4 +40,8 @@ void rb_kill(RingBuffer *b);
36uint16_t rb_size(const RingBuffer *b); 40uint16_t rb_size(const RingBuffer *b);
37uint16_t rb_data(const RingBuffer *b, void **dest); 41uint16_t rb_data(const RingBuffer *b, void **dest);
38 42
43#ifdef __cplusplus
44}
45#endif
46
39#endif /* RING_BUFFER_H */ 47#endif /* RING_BUFFER_H */
diff --git a/toxav/ring_buffer_test.cc b/toxav/ring_buffer_test.cc
new file mode 100644
index 00000000..672ee2ce
--- /dev/null
+++ b/toxav/ring_buffer_test.cc
@@ -0,0 +1,196 @@
1#include "ring_buffer.h"
2
3#include <algorithm>
4#include <cassert>
5#include <vector>
6
7#include <gtest/gtest.h>
8
9namespace {
10
11template <typename T>
12class TypedRingBuffer;
13
14template <typename T>
15class TypedRingBuffer<T *> {
16 public:
17 explicit TypedRingBuffer(int size) : rb_(rb_new(size)) {}
18 ~TypedRingBuffer() { rb_kill(rb_); }
19 TypedRingBuffer(TypedRingBuffer const &) = delete;
20
21 bool full() const { return rb_full(rb_); }
22 bool empty() const { return rb_empty(rb_); }
23 T *write(T *p) { return static_cast<T *>(rb_write(rb_, p)); }
24 bool read(T **p) {
25 void *vp;
26 bool res = rb_read(rb_, &vp);
27 *p = static_cast<T *>(vp);
28 return res;
29 }
30
31 uint16_t size() const { return rb_size(rb_); }
32 uint16_t data(T **dest) const {
33 std::vector<void *> vdest(size());
34 uint16_t res = rb_data(rb_, vdest.data());
35 for (uint16_t i = 0; i < size(); i++) {
36 dest[i] = static_cast<T *>(vdest.at(i));
37 }
38 return res;
39 }
40
41 bool contains(T *p) const {
42 std::vector<T *> elts(size());
43 data(elts.data());
44 return std::find(elts.begin(), elts.end(), p) != elts.end();
45 }
46
47 bool ok() const { return rb_ != nullptr; }
48
49 private:
50 RingBuffer *rb_;
51};
52
53TEST(RingBuffer, EmptyBufferReportsEmpty) {
54 TypedRingBuffer<int *> rb(10);
55 ASSERT_TRUE(rb.ok());
56 EXPECT_TRUE(rb.empty());
57}
58
59TEST(RingBuffer, EmptyBufferReportsNotFull) {
60 TypedRingBuffer<int *> rb(10);
61 ASSERT_TRUE(rb.ok());
62 EXPECT_FALSE(rb.full());
63}
64
65TEST(RingBuffer, ZeroSizedRingBufferIsBothEmptyAndFull) {
66 TypedRingBuffer<int *> rb(0);
67 ASSERT_TRUE(rb.ok());
68 EXPECT_TRUE(rb.empty());
69 EXPECT_TRUE(rb.full());
70}
71
72TEST(RingBuffer, WritingMakesBufferNotEmpty) {
73 TypedRingBuffer<int *> rb(2);
74 ASSERT_TRUE(rb.ok());
75 int value0 = 123;
76 rb.write(&value0);
77 EXPECT_FALSE(rb.empty());
78}
79
80TEST(RingBuffer, WritingOneElementMakesBufferNotFull) {
81 TypedRingBuffer<int *> rb(2);
82 ASSERT_TRUE(rb.ok());
83 int value0 = 123;
84 rb.write(&value0);
85 EXPECT_FALSE(rb.full());
86}
87
88TEST(RingBuffer, WritingAllElementsMakesBufferFull) {
89 TypedRingBuffer<int *> rb(2);
90 ASSERT_TRUE(rb.ok());
91 int value0 = 123;
92 int value1 = 231;
93 rb.write(&value0);
94 rb.write(&value1);
95 EXPECT_TRUE(rb.full());
96}
97
98TEST(RingBuffer, ReadingElementFromFullBufferMakesItNotFull) {
99 TypedRingBuffer<int *> rb(2);
100 ASSERT_TRUE(rb.ok());
101 int value0 = 123;
102 int value1 = 231;
103 rb.write(&value0);
104 rb.write(&value1);
105 EXPECT_TRUE(rb.full());
106 int *retrieved;
107 // Reading deletes the element.
108 EXPECT_TRUE(rb.read(&retrieved));
109 EXPECT_FALSE(rb.full());
110}
111
112TEST(RingBuffer, ZeroSizeBufferCanBeWrittenToOnce) {
113 TypedRingBuffer<int *> rb(0);
114 ASSERT_TRUE(rb.ok());
115 int value0 = 123;
116 // Strange behaviour: we can write one element to a 0-size buffer.
117 EXPECT_EQ(nullptr, rb.write(&value0));
118 EXPECT_EQ(&value0, rb.write(&value0));
119 int *retrieved = nullptr;
120 // But then we can't read it.
121 EXPECT_FALSE(rb.read(&retrieved));
122 EXPECT_EQ(nullptr, retrieved);
123}
124
125TEST(RingBuffer, ReadingFromEmptyBufferFails) {
126 TypedRingBuffer<int *> rb(2);
127 ASSERT_TRUE(rb.ok());
128 int *retrieved;
129 EXPECT_FALSE(rb.read(&retrieved));
130}
131
132TEST(RingBuffer, WritingToBufferWhenFullOverwritesBeginning) {
133 TypedRingBuffer<int *> rb(2);
134 ASSERT_TRUE(rb.ok());
135 int value0 = 123;
136 int value1 = 231;
137 int value2 = 312;
138 int value3 = 432;
139 EXPECT_EQ(nullptr, rb.write(&value0));
140 EXPECT_EQ(nullptr, rb.write(&value1));
141 EXPECT_TRUE(rb.contains(&value0));
142 EXPECT_TRUE(rb.contains(&value1));
143
144 // Adding another element evicts the first element.
145 EXPECT_EQ(&value0, rb.write(&value2));
146 EXPECT_FALSE(rb.contains(&value0));
147 EXPECT_TRUE(rb.contains(&value2));
148
149 // Adding another evicts the second.
150 EXPECT_EQ(&value1, rb.write(&value3));
151 EXPECT_FALSE(rb.contains(&value1));
152 EXPECT_TRUE(rb.contains(&value3));
153}
154
155TEST(RingBuffer, SizeIsNumberOfElementsInBuffer) {
156 TypedRingBuffer<int *> rb(10);
157 ASSERT_TRUE(rb.ok());
158 int value0 = 123;
159 EXPECT_EQ(rb.size(), 0);
160 rb.write(&value0);
161 EXPECT_EQ(rb.size(), 1);
162 rb.write(&value0);
163 EXPECT_EQ(rb.size(), 2);
164 rb.write(&value0);
165 EXPECT_EQ(rb.size(), 3);
166 rb.write(&value0);
167 EXPECT_EQ(rb.size(), 4);
168
169 int *retrieved;
170 rb.read(&retrieved);
171 EXPECT_EQ(rb.size(), 3);
172 rb.read(&retrieved);
173 EXPECT_EQ(rb.size(), 2);
174 rb.read(&retrieved);
175 EXPECT_EQ(rb.size(), 1);
176 rb.read(&retrieved);
177 EXPECT_EQ(rb.size(), 0);
178}
179
180TEST(RingBuffer, SizeIsLimitedByMaxSize) {
181 TypedRingBuffer<int *> rb(4);
182 ASSERT_TRUE(rb.ok());
183 int value0 = 123;
184 rb.write(&value0);
185 rb.write(&value0);
186 rb.write(&value0);
187 rb.write(&value0);
188 EXPECT_EQ(rb.size(), 4);
189
190 // Add one more.
191 rb.write(&value0);
192 // Still size is 4.
193 EXPECT_EQ(rb.size(), 4);
194}
195
196} // namespace