diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | toxav/BUILD.bazel | 9 | ||||
-rw-r--r-- | toxav/ring_buffer.h | 8 | ||||
-rw-r--r-- | toxav/ring_buffer_test.cc | 196 |
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 | # |
341 | unit_test(toxav ring_buffer) | ||
341 | unit_test(toxav rtp) | 342 | unit_test(toxav rtp) |
342 | unit_test(toxcore crypto_core) | 343 | unit_test(toxcore crypto_core) |
343 | unit_test(toxcore util) | 344 | unit_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 | ||
21 | cc_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 | |||
21 | cc_library( | 30 | cc_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 | ||
29 | extern "C" { | ||
30 | #endif | ||
31 | |||
28 | /* Ring buffer */ | 32 | /* Ring buffer */ |
29 | typedef struct RingBuffer RingBuffer; | 33 | typedef struct RingBuffer RingBuffer; |
30 | bool rb_full(const RingBuffer *b); | 34 | bool rb_full(const RingBuffer *b); |
@@ -36,4 +40,8 @@ void rb_kill(RingBuffer *b); | |||
36 | uint16_t rb_size(const RingBuffer *b); | 40 | uint16_t rb_size(const RingBuffer *b); |
37 | uint16_t rb_data(const RingBuffer *b, void **dest); | 41 | uint16_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 | |||
9 | namespace { | ||
10 | |||
11 | template <typename T> | ||
12 | class TypedRingBuffer; | ||
13 | |||
14 | template <typename T> | ||
15 | class 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 | |||
53 | TEST(RingBuffer, EmptyBufferReportsEmpty) { | ||
54 | TypedRingBuffer<int *> rb(10); | ||
55 | ASSERT_TRUE(rb.ok()); | ||
56 | EXPECT_TRUE(rb.empty()); | ||
57 | } | ||
58 | |||
59 | TEST(RingBuffer, EmptyBufferReportsNotFull) { | ||
60 | TypedRingBuffer<int *> rb(10); | ||
61 | ASSERT_TRUE(rb.ok()); | ||
62 | EXPECT_FALSE(rb.full()); | ||
63 | } | ||
64 | |||
65 | TEST(RingBuffer, ZeroSizedRingBufferIsBothEmptyAndFull) { | ||
66 | TypedRingBuffer<int *> rb(0); | ||
67 | ASSERT_TRUE(rb.ok()); | ||
68 | EXPECT_TRUE(rb.empty()); | ||
69 | EXPECT_TRUE(rb.full()); | ||
70 | } | ||
71 | |||
72 | TEST(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 | |||
80 | TEST(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 | |||
88 | TEST(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 | |||
98 | TEST(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 | |||
112 | TEST(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 | |||
125 | TEST(RingBuffer, ReadingFromEmptyBufferFails) { | ||
126 | TypedRingBuffer<int *> rb(2); | ||
127 | ASSERT_TRUE(rb.ok()); | ||
128 | int *retrieved; | ||
129 | EXPECT_FALSE(rb.read(&retrieved)); | ||
130 | } | ||
131 | |||
132 | TEST(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 | |||
155 | TEST(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 | |||
180 | TEST(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 | ||