1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_ring_buffer/prefixed_entry_ring_buffer.h"
16
17 #include <cstddef>
18 #include <cstdint>
19
20 #include "pw_assert/assert.h"
21 #include "pw_containers/vector.h"
22 #include "pw_unit_test/framework.h"
23
24 using std::byte;
25
26 namespace pw {
27 namespace ring_buffer {
28 namespace {
29
TEST(PrefixedEntryRingBuffer,NoBuffer)30 TEST(PrefixedEntryRingBuffer, NoBuffer) {
31 PrefixedEntryRingBuffer ring(false);
32
33 byte buf[32];
34 size_t count;
35
36 EXPECT_EQ(ring.EntryCount(), 0u);
37 EXPECT_EQ(ring.SetBuffer(std::span<byte>(nullptr, 10u)),
38 Status::InvalidArgument());
39 EXPECT_EQ(ring.SetBuffer(std::span(buf, 0u)), Status::InvalidArgument());
40 EXPECT_EQ(ring.FrontEntryDataSizeBytes(), 0u);
41
42 EXPECT_EQ(ring.PushBack(buf), Status::FailedPrecondition());
43 EXPECT_EQ(ring.EntryCount(), 0u);
44 EXPECT_EQ(ring.PeekFront(buf, &count), Status::FailedPrecondition());
45 EXPECT_EQ(count, 0u);
46 EXPECT_EQ(ring.EntryCount(), 0u);
47 EXPECT_EQ(ring.PeekFrontWithPreamble(buf, &count),
48 Status::FailedPrecondition());
49 EXPECT_EQ(count, 0u);
50 EXPECT_EQ(ring.EntryCount(), 0u);
51 EXPECT_EQ(ring.PopFront(), Status::FailedPrecondition());
52 EXPECT_EQ(ring.EntryCount(), 0u);
53 }
54
55 // Single entry to write/read/pop over and over again.
56 constexpr byte single_entry_data[] = {byte(1),
57 byte(2),
58 byte(3),
59 byte(4),
60 byte(5),
61 byte(6),
62 byte(7),
63 byte(8),
64 byte(9)};
65 constexpr size_t single_entry_total_size = sizeof(single_entry_data) + 1;
66 constexpr size_t single_entry_test_buffer_size =
67 (single_entry_total_size * 7) / 2;
68
69 // Make sure the single_entry_size is even so single_entry_buffer_Size gets the
70 // proper wrap/even behavior when getting to the end of the buffer.
71 static_assert((single_entry_total_size % 2) == 0u);
72 constexpr size_t kSingleEntryCycles = 300u;
73
74 // Repeatedly write the same data, read it, and pop it, done over and over
75 // again.
SingleEntryWriteReadTest(bool user_data)76 void SingleEntryWriteReadTest(bool user_data) {
77 PrefixedEntryRingBuffer ring(user_data);
78 byte test_buffer[single_entry_test_buffer_size];
79
80 byte read_buffer[single_entry_total_size];
81
82 // Set read_size to an unexpected value to make sure result checks don't luck
83 // out and happen to see a previous value.
84 size_t read_size = 500U;
85 uint32_t user_preamble = 0U;
86
87 EXPECT_EQ(ring.SetBuffer(test_buffer), OkStatus());
88
89 EXPECT_EQ(ring.EntryCount(), 0u);
90 EXPECT_EQ(ring.PopFront(), Status::OutOfRange());
91 EXPECT_EQ(ring.EntryCount(), 0u);
92 EXPECT_EQ(ring.PushBack(std::span(single_entry_data, 0u)),
93 Status::InvalidArgument());
94 EXPECT_EQ(ring.EntryCount(), 0u);
95 EXPECT_EQ(
96 ring.PushBack(std::span(single_entry_data, sizeof(test_buffer) + 5)),
97 Status::OutOfRange());
98 EXPECT_EQ(ring.EntryCount(), 0u);
99 EXPECT_EQ(ring.PeekFront(read_buffer, &read_size), Status::OutOfRange());
100 EXPECT_EQ(read_size, 0u);
101 read_size = 500U;
102 EXPECT_EQ(ring.PeekFrontWithPreamble(read_buffer, &read_size),
103 Status::OutOfRange());
104 EXPECT_EQ(read_size, 0u);
105
106 size_t user_preamble_bytes = (user_data ? 1 : 0);
107 size_t data_size = sizeof(single_entry_data) - user_preamble_bytes;
108 size_t data_offset = single_entry_total_size - data_size;
109
110 byte expect_buffer[single_entry_total_size] = {};
111 expect_buffer[user_preamble_bytes] = byte(data_size);
112 memcpy(expect_buffer + data_offset, single_entry_data, data_size);
113
114 for (size_t i = 0; i < kSingleEntryCycles; i++) {
115 ASSERT_EQ(ring.FrontEntryDataSizeBytes(), 0u);
116 ASSERT_EQ(ring.FrontEntryTotalSizeBytes(), 0u);
117
118 // Limit the value of the preamble to a single byte, to ensure that we
119 // retain a static `single_entry_buffer_size` during the test. Single
120 // bytes are varint-encoded to the same value.
121 uint32_t preamble_byte = i % 128;
122 ASSERT_EQ(
123 ring.PushBack(std::span(single_entry_data, data_size), preamble_byte),
124 OkStatus());
125 ASSERT_EQ(ring.FrontEntryDataSizeBytes(), data_size);
126 ASSERT_EQ(ring.FrontEntryTotalSizeBytes(), single_entry_total_size);
127
128 read_size = 500U;
129 ASSERT_EQ(ring.PeekFront(read_buffer, &read_size), OkStatus());
130 ASSERT_EQ(read_size, data_size);
131
132 // ASSERT_THAT(std::span(expect_buffer).last(data_size),
133 // testing::ElementsAreArray(std::span(read_buffer, data_size)));
134 ASSERT_EQ(memcmp(std::span(expect_buffer).last(data_size).data(),
135 read_buffer,
136 data_size),
137 0);
138
139 read_size = 500U;
140 ASSERT_EQ(ring.PeekFrontWithPreamble(read_buffer, &read_size), OkStatus());
141 ASSERT_EQ(read_size, single_entry_total_size);
142
143 if (user_data) {
144 expect_buffer[0] = byte(preamble_byte);
145 }
146
147 // ASSERT_THAT(std::span(expect_buffer),
148 // testing::ElementsAreArray(std::span(read_buffer)));
149 ASSERT_EQ(memcmp(expect_buffer, read_buffer, single_entry_total_size), 0);
150
151 if (user_data) {
152 user_preamble = 0U;
153 ASSERT_EQ(
154 ring.PeekFrontWithPreamble(read_buffer, user_preamble, read_size),
155 OkStatus());
156 ASSERT_EQ(read_size, data_size);
157 ASSERT_EQ(user_preamble, preamble_byte);
158 ASSERT_EQ(memcmp(std::span(expect_buffer).last(data_size).data(),
159 read_buffer,
160 data_size),
161 0);
162 }
163
164 ASSERT_EQ(ring.PopFront(), OkStatus());
165 }
166 }
167
TEST(PrefixedEntryRingBuffer,SingleEntryWriteReadNoUserData)168 TEST(PrefixedEntryRingBuffer, SingleEntryWriteReadNoUserData) {
169 SingleEntryWriteReadTest(false);
170 }
171
TEST(PrefixedEntryRingBuffer,SingleEntryWriteReadYesUserData)172 TEST(PrefixedEntryRingBuffer, SingleEntryWriteReadYesUserData) {
173 SingleEntryWriteReadTest(true);
174 }
175
176 // TODO(pwbug/196): Increase this to 5000 once we have a way to detect targets
177 // with more computation and memory oomph.
178 constexpr size_t kOuterCycles = 50u;
179 constexpr size_t kCountingUpMaxExpectedEntries =
180 single_entry_test_buffer_size / single_entry_total_size;
181
182 // Write data that is filled with a byte value that increments each write. Write
183 // many times without read/pop and then check to make sure correct contents are
184 // in the ring buffer.
185 template <bool kUserData>
CountingUpWriteReadTest()186 void CountingUpWriteReadTest() {
187 PrefixedEntryRingBuffer ring(kUserData);
188 byte test_buffer[single_entry_test_buffer_size];
189
190 EXPECT_EQ(ring.SetBuffer(test_buffer), OkStatus());
191 EXPECT_EQ(ring.EntryCount(), 0u);
192
193 constexpr size_t kDataSize = sizeof(single_entry_data) - (kUserData ? 1 : 0);
194
195 for (size_t i = 0; i < kOuterCycles; i++) {
196 size_t seed = i;
197
198 byte write_buffer[kDataSize];
199
200 size_t j;
201 for (j = 0; j < kSingleEntryCycles; j++) {
202 memset(write_buffer, j + seed, sizeof(write_buffer));
203
204 ASSERT_EQ(ring.PushBack(write_buffer), OkStatus());
205
206 size_t expected_count = (j < kCountingUpMaxExpectedEntries)
207 ? j + 1
208 : kCountingUpMaxExpectedEntries;
209 ASSERT_EQ(ring.EntryCount(), expected_count);
210 }
211 size_t final_write_j = j;
212 size_t fill_val = seed + final_write_j - kCountingUpMaxExpectedEntries;
213
214 for (j = 0; j < kCountingUpMaxExpectedEntries; j++) {
215 byte read_buffer[sizeof(write_buffer)];
216 size_t read_size;
217 memset(write_buffer, fill_val + j, sizeof(write_buffer));
218 ASSERT_EQ(ring.PeekFront(read_buffer, &read_size), OkStatus());
219
220 ASSERT_EQ(memcmp(write_buffer, read_buffer, kDataSize), 0);
221
222 ASSERT_EQ(ring.PopFront(), OkStatus());
223 }
224 }
225 }
226
TEST(PrefixedEntryRingBuffer,CountingUpWriteReadNoUserData)227 TEST(PrefixedEntryRingBuffer, CountingUpWriteReadNoUserData) {
228 CountingUpWriteReadTest<false>();
229 }
230
TEST(PrefixedEntryRingBuffer,CountingUpWriteReadYesUserData)231 TEST(PrefixedEntryRingBuffer, CountingUpWriteReadYesUserData) {
232 CountingUpWriteReadTest<true>();
233 }
234
235 // Create statically to prevent allocating a capture in the lambda below.
236 static pw::Vector<byte, single_entry_total_size> read_buffer;
237
238 // Repeatedly write the same data, read it, and pop it, done over and over
239 // again.
SingleEntryWriteReadWithSectionWriterTest(bool user_data)240 void SingleEntryWriteReadWithSectionWriterTest(bool user_data) {
241 PrefixedEntryRingBuffer ring(user_data);
242 byte test_buffer[single_entry_test_buffer_size];
243
244 EXPECT_EQ(ring.SetBuffer(test_buffer), OkStatus());
245
246 auto output = [](std::span<const byte> src) -> Status {
247 for (byte b : src) {
248 read_buffer.push_back(b);
249 }
250 return OkStatus();
251 };
252
253 size_t user_preamble_bytes = (user_data ? 1 : 0);
254 size_t data_size = sizeof(single_entry_data) - user_preamble_bytes;
255 size_t data_offset = single_entry_total_size - data_size;
256
257 byte expect_buffer[single_entry_total_size] = {};
258 expect_buffer[user_preamble_bytes] = byte(data_size);
259 memcpy(expect_buffer + data_offset, single_entry_data, data_size);
260
261 for (size_t i = 0; i < kSingleEntryCycles; i++) {
262 ASSERT_EQ(ring.FrontEntryDataSizeBytes(), 0u);
263 ASSERT_EQ(ring.FrontEntryTotalSizeBytes(), 0u);
264
265 // Limit the value of the preamble to a single byte, to ensure that we
266 // retain a static `single_entry_buffer_size` during the test. Single
267 // bytes are varint-encoded to the same value.
268 uint32_t preamble_byte = i % 128;
269 ASSERT_EQ(
270 ring.PushBack(std::span(single_entry_data, data_size), preamble_byte),
271 OkStatus());
272 ASSERT_EQ(ring.FrontEntryDataSizeBytes(), data_size);
273 ASSERT_EQ(ring.FrontEntryTotalSizeBytes(), single_entry_total_size);
274
275 read_buffer.clear();
276 ASSERT_EQ(ring.PeekFront(output), OkStatus());
277 ASSERT_EQ(read_buffer.size(), data_size);
278
279 ASSERT_EQ(memcmp(std::span(expect_buffer).last(data_size).data(),
280 read_buffer.data(),
281 data_size),
282 0);
283
284 read_buffer.clear();
285 ASSERT_EQ(ring.PeekFrontWithPreamble(output), OkStatus());
286 ASSERT_EQ(read_buffer.size(), single_entry_total_size);
287 ASSERT_EQ(ring.PopFront(), OkStatus());
288
289 if (user_data) {
290 expect_buffer[0] = byte(preamble_byte);
291 }
292
293 ASSERT_EQ(
294 memcmp(expect_buffer, read_buffer.data(), single_entry_total_size), 0);
295 }
296 }
297
TEST(PrefixedEntryRingBuffer,SingleEntryWriteReadWithSectionWriterNoUserData)298 TEST(PrefixedEntryRingBuffer, SingleEntryWriteReadWithSectionWriterNoUserData) {
299 SingleEntryWriteReadWithSectionWriterTest(false);
300 }
301
TEST(PrefixedEntryRingBuffer,SingleEntryWriteReadWithSectionWriterYesUserData)302 TEST(PrefixedEntryRingBuffer,
303 SingleEntryWriteReadWithSectionWriterYesUserData) {
304 SingleEntryWriteReadWithSectionWriterTest(true);
305 }
306
307 constexpr size_t kEntrySizeBytes = 8u;
308 constexpr size_t kTotalEntryCount = 20u;
309 constexpr size_t kBufferExtraBytes = 5u;
310 constexpr size_t kTestBufferSize =
311 (kEntrySizeBytes * kTotalEntryCount) + kBufferExtraBytes;
312
313 // Create statically to prevent allocating a capture in the lambda below.
314 static pw::Vector<byte, kTestBufferSize> actual_result;
315
DeringTest(bool preload)316 void DeringTest(bool preload) {
317 PrefixedEntryRingBuffer ring;
318
319 byte test_buffer[kTestBufferSize];
320 EXPECT_EQ(ring.SetBuffer(test_buffer), OkStatus());
321
322 // Entry data is entry size - preamble (single byte in this case).
323 byte single_entry_buffer[kEntrySizeBytes - 1u];
324 auto entry_data = std::span(single_entry_buffer);
325 size_t i;
326
327 // TODO(pwbug/196): Increase this to 500 once we have a way to detect targets
328 // with more computation and memory oomph.
329 size_t loop_goal = preload ? 50 : 1;
330
331 for (size_t main_loop_count = 0; main_loop_count < loop_goal;
332 main_loop_count++) {
333 if (preload) {
334 // Prime the ringbuffer with some junk data to get the buffer
335 // wrapped.
336 for (i = 0; i < (kTotalEntryCount * (main_loop_count % 64u)); i++) {
337 memset(single_entry_buffer, i, sizeof(single_entry_buffer));
338 ring.PushBack(single_entry_buffer);
339 }
340 }
341
342 // Build up the expected buffer and fill the ring buffer with the test data.
343 pw::Vector<byte, kTestBufferSize> expected_result;
344 for (i = 0; i < kTotalEntryCount; i++) {
345 // First component of the entry: the varint size.
346 static_assert(sizeof(single_entry_buffer) < 127);
347 expected_result.push_back(byte(sizeof(single_entry_buffer)));
348
349 // Second component of the entry: the raw data.
350 memset(single_entry_buffer, 'a' + i, sizeof(single_entry_buffer));
351 for (byte b : entry_data) {
352 expected_result.push_back(b);
353 }
354
355 // The ring buffer internally pushes the varint size byte.
356 ring.PushBack(single_entry_buffer);
357 }
358
359 // Check values before doing the dering.
360 EXPECT_EQ(ring.EntryCount(), kTotalEntryCount);
361 EXPECT_EQ(expected_result.size(), ring.TotalUsedBytes());
362
363 ASSERT_EQ(ring.Dering(), OkStatus());
364
365 // Check values after doing the dering.
366 EXPECT_EQ(ring.EntryCount(), kTotalEntryCount);
367 EXPECT_EQ(expected_result.size(), ring.TotalUsedBytes());
368
369 // Read out the entries of the ring buffer.
370 actual_result.clear();
371 auto output = [](std::span<const byte> src) -> Status {
372 for (byte b : src) {
373 actual_result.push_back(b);
374 }
375 return OkStatus();
376 };
377 while (ring.EntryCount()) {
378 ASSERT_EQ(ring.PeekFrontWithPreamble(output), OkStatus());
379 ASSERT_EQ(ring.PopFront(), OkStatus());
380 }
381
382 // Ensure the actual result out of the ring buffer matches our manually
383 // computed result.
384 EXPECT_EQ(expected_result.size(), actual_result.size());
385 ASSERT_EQ(memcmp(test_buffer, actual_result.data(), actual_result.size()),
386 0);
387 ASSERT_EQ(
388 memcmp(
389 expected_result.data(), actual_result.data(), actual_result.size()),
390 0);
391 }
392 }
393
TEST(PrefixedEntryRingBuffer,Dering)394 TEST(PrefixedEntryRingBuffer, Dering) { DeringTest(true); }
TEST(PrefixedEntryRingBuffer,DeringNoPreload)395 TEST(PrefixedEntryRingBuffer, DeringNoPreload) { DeringTest(false); }
396
397 template <typename T>
PushBack(PrefixedEntryRingBufferMulti & ring,T element)398 Status PushBack(PrefixedEntryRingBufferMulti& ring, T element) {
399 union {
400 std::array<byte, sizeof(element)> buffer;
401 T item;
402 } aliased;
403 aliased.item = element;
404 return ring.PushBack(aliased.buffer);
405 }
406
407 template <typename T>
TryPushBack(PrefixedEntryRingBufferMulti & ring,T element)408 Status TryPushBack(PrefixedEntryRingBufferMulti& ring, T element) {
409 union {
410 std::array<byte, sizeof(element)> buffer;
411 T item;
412 } aliased;
413 aliased.item = element;
414 return ring.TryPushBack(aliased.buffer);
415 }
416
417 template <typename T>
PeekFront(PrefixedEntryRingBufferMulti::Reader & reader)418 T PeekFront(PrefixedEntryRingBufferMulti::Reader& reader) {
419 union {
420 std::array<byte, sizeof(T)> buffer;
421 T item;
422 } aliased;
423 size_t bytes_read = 0;
424 PW_CHECK_OK(reader.PeekFront(aliased.buffer, &bytes_read));
425 PW_CHECK_INT_EQ(bytes_read, sizeof(T));
426 return aliased.item;
427 }
428
TEST(PrefixedEntryRingBuffer,TryPushBack)429 TEST(PrefixedEntryRingBuffer, TryPushBack) {
430 PrefixedEntryRingBuffer ring;
431 byte test_buffer[kTestBufferSize];
432 EXPECT_EQ(ring.SetBuffer(test_buffer), OkStatus());
433
434 // Fill up the ring buffer with a constant.
435 int total_items = 0;
436 while (true) {
437 Status status = TryPushBack<int>(ring, 5);
438 if (status.ok()) {
439 total_items++;
440 } else {
441 EXPECT_EQ(status, Status::ResourceExhausted());
442 break;
443 }
444 }
445 EXPECT_EQ(PeekFront<int>(ring), 5);
446
447 // Should be unable to push more items.
448 for (int i = 0; i < total_items; ++i) {
449 EXPECT_EQ(TryPushBack<int>(ring, 100), Status::ResourceExhausted());
450 EXPECT_EQ(PeekFront<int>(ring), 5);
451 }
452
453 // Fill up the ring buffer with a constant.
454 for (int i = 0; i < total_items; ++i) {
455 EXPECT_EQ(PushBack<int>(ring, 100), OkStatus());
456 }
457 EXPECT_EQ(PeekFront<int>(ring), 100);
458 }
459
TEST(PrefixedEntryRingBufferMulti,TryPushBack)460 TEST(PrefixedEntryRingBufferMulti, TryPushBack) {
461 PrefixedEntryRingBufferMulti ring;
462 byte test_buffer[kTestBufferSize];
463 EXPECT_EQ(ring.SetBuffer(test_buffer), OkStatus());
464
465 PrefixedEntryRingBufferMulti::Reader fast_reader;
466 PrefixedEntryRingBufferMulti::Reader slow_reader;
467
468 EXPECT_EQ(ring.AttachReader(fast_reader), OkStatus());
469 EXPECT_EQ(ring.AttachReader(slow_reader), OkStatus());
470
471 // Fill up the ring buffer with an increasing count.
472 int total_items = 0;
473 while (true) {
474 Status status = TryPushBack<int>(ring, total_items);
475 if (status.ok()) {
476 total_items++;
477 } else {
478 EXPECT_EQ(status, Status::ResourceExhausted());
479 break;
480 }
481 }
482
483 // Run fast reader twice as fast as the slow reader.
484 for (int i = 0; i < total_items; ++i) {
485 if (i % 2 == 0) {
486 EXPECT_EQ(PeekFront<int>(slow_reader), i / 2);
487 EXPECT_EQ(slow_reader.PopFront(), OkStatus());
488 }
489 EXPECT_EQ(PeekFront<int>(fast_reader), i);
490 EXPECT_EQ(fast_reader.PopFront(), OkStatus());
491 }
492 EXPECT_EQ(fast_reader.PopFront(), Status::OutOfRange());
493
494 // Fill the buffer again, expect that the fast reader
495 // only sees half the entries as the slow reader.
496 size_t max_items = total_items;
497 while (true) {
498 Status status = TryPushBack<int>(ring, total_items);
499 if (status.ok()) {
500 total_items++;
501 } else {
502 EXPECT_EQ(status, Status::ResourceExhausted());
503 break;
504 }
505 }
506 EXPECT_EQ(slow_reader.EntryCount(), max_items);
507 EXPECT_EQ(fast_reader.EntryCount(), total_items - max_items);
508
509 for (int i = total_items - max_items; i < total_items; ++i) {
510 EXPECT_EQ(PeekFront<int>(slow_reader), i);
511 EXPECT_EQ(slow_reader.PopFront(), OkStatus());
512 if (static_cast<size_t>(i) >= max_items) {
513 EXPECT_EQ(PeekFront<int>(fast_reader), i);
514 EXPECT_EQ(fast_reader.PopFront(), OkStatus());
515 }
516 }
517 EXPECT_EQ(slow_reader.PopFront(), Status::OutOfRange());
518 EXPECT_EQ(fast_reader.PopFront(), Status::OutOfRange());
519 }
520
TEST(PrefixedEntryRingBufferMulti,PushBack)521 TEST(PrefixedEntryRingBufferMulti, PushBack) {
522 PrefixedEntryRingBufferMulti ring;
523 byte test_buffer[kTestBufferSize];
524 EXPECT_EQ(ring.SetBuffer(test_buffer), OkStatus());
525
526 PrefixedEntryRingBufferMulti::Reader fast_reader;
527 PrefixedEntryRingBufferMulti::Reader slow_reader;
528
529 EXPECT_EQ(ring.AttachReader(fast_reader), OkStatus());
530 EXPECT_EQ(ring.AttachReader(slow_reader), OkStatus());
531
532 // Fill up the ring buffer with an increasing count.
533 size_t total_items = 0;
534 while (true) {
535 Status status = TryPushBack<uint32_t>(ring, total_items);
536 if (status.ok()) {
537 total_items++;
538 } else {
539 EXPECT_EQ(status, Status::ResourceExhausted());
540 break;
541 }
542 }
543 EXPECT_EQ(slow_reader.EntryCount(), total_items);
544
545 // The following test:
546 // - Moves the fast reader forward by one entry.
547 // - Writes a single entry that is guaranteed to be larger than the size of a
548 // single entry in the buffer (uint64_t entry > uint32_t entry).
549 // - Checks to see that both readers were moved forward.
550 EXPECT_EQ(fast_reader.PopFront(), OkStatus());
551 EXPECT_EQ(PushBack<uint64_t>(ring, 5u), OkStatus());
552 // The readers have moved past values 0 and 1.
553 EXPECT_EQ(PeekFront<uint32_t>(slow_reader), 2u);
554 EXPECT_EQ(PeekFront<uint32_t>(fast_reader), 2u);
555 // The readers have lost two entries, but gained an entry.
556 EXPECT_EQ(slow_reader.EntryCount(), total_items - 1);
557 EXPECT_EQ(fast_reader.EntryCount(), total_items - 1);
558 }
559
TEST(PrefixedEntryRingBufferMulti,ReaderAddRemove)560 TEST(PrefixedEntryRingBufferMulti, ReaderAddRemove) {
561 PrefixedEntryRingBufferMulti ring;
562 byte test_buffer[kTestBufferSize];
563 EXPECT_EQ(ring.SetBuffer(test_buffer), OkStatus());
564
565 PrefixedEntryRingBufferMulti::Reader reader;
566 PrefixedEntryRingBufferMulti::Reader transient_reader;
567
568 EXPECT_EQ(ring.AttachReader(reader), OkStatus());
569
570 // Fill up the ring buffer with a constant value.
571 int total_items = 0;
572 while (true) {
573 Status status = TryPushBack<int>(ring, 5);
574 if (status.ok()) {
575 total_items++;
576 } else {
577 EXPECT_EQ(status, Status::ResourceExhausted());
578 break;
579 }
580 }
581 EXPECT_EQ(reader.EntryCount(), static_cast<size_t>(total_items));
582
583 // Add new reader after filling the buffer.
584 EXPECT_EQ(ring.AttachReader(transient_reader), OkStatus());
585 EXPECT_EQ(transient_reader.EntryCount(), 0u);
586
587 // Push a value into the buffer and confirm the transient reader
588 // sees that value, and only that value.
589 EXPECT_EQ(PushBack<int>(ring, 1), OkStatus());
590 EXPECT_EQ(PeekFront<int>(transient_reader), 1);
591 EXPECT_EQ(transient_reader.EntryCount(), 1u);
592
593 // Confirm that detaching and attaching a reader resets its state.
594 EXPECT_EQ(ring.DetachReader(transient_reader), OkStatus());
595 EXPECT_EQ(ring.AttachReader(transient_reader), OkStatus());
596 EXPECT_EQ(transient_reader.EntryCount(), 0u);
597 }
598
TEST(PrefixedEntryRingBufferMulti,SingleBufferPerReader)599 TEST(PrefixedEntryRingBufferMulti, SingleBufferPerReader) {
600 PrefixedEntryRingBufferMulti ring_one;
601 PrefixedEntryRingBufferMulti ring_two;
602 byte test_buffer[kTestBufferSize];
603 EXPECT_EQ(ring_one.SetBuffer(test_buffer), OkStatus());
604
605 PrefixedEntryRingBufferMulti::Reader reader;
606 EXPECT_EQ(ring_one.AttachReader(reader), OkStatus());
607 EXPECT_EQ(ring_two.AttachReader(reader), Status::InvalidArgument());
608
609 EXPECT_EQ(ring_one.DetachReader(reader), OkStatus());
610 EXPECT_EQ(ring_two.AttachReader(reader), OkStatus());
611 EXPECT_EQ(ring_one.AttachReader(reader), Status::InvalidArgument());
612 }
613
614 } // namespace
615 } // namespace ring_buffer
616 } // namespace pw
617