blob: 3076aea77ed88be91c022900063298ebca12bcb8 [file] [log] [blame]
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -08001// Copyright 2021 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_multisink/multisink.h"
16
Carlos Chinchilla64021a82021-08-06 00:18:41 -070017#include <array>
18#include <cstdint>
Prashanth Swaminathan3eb97d42021-07-13 10:14:38 -070019#include <optional>
Ewout van Bekkum6937a092022-03-04 08:13:37 -080020#include <span>
Armando Montanezfb7b4782021-09-30 21:38:20 -070021#include <string_view>
Prashanth Swaminathan3eb97d42021-07-13 10:14:38 -070022
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -080023#include "gtest/gtest.h"
Armando Montanezfb7b4782021-09-30 21:38:20 -070024#include "pw_function/function.h"
Carlos Chinchilla64021a82021-08-06 00:18:41 -070025#include "pw_status/status.h"
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -080026
27namespace pw::multisink {
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -070028using Drain = MultiSink::Drain;
29using Listener = MultiSink::Listener;
30
31class CountingListener : public Listener {
32 public:
33 void OnNewEntryAvailable() override { notification_count_++; }
34
35 size_t GetNotificationCount() { return notification_count_; }
36
37 void ResetNotificationCount() { notification_count_ = 0; }
38
39 private:
40 size_t notification_count_ = 0;
41};
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -080042
43class MultiSinkTest : public ::testing::Test {
44 protected:
45 static constexpr std::byte kMessage[] = {
46 (std::byte)0xDE, (std::byte)0xAD, (std::byte)0xBE, (std::byte)0xEF};
Carlos Chinchilla64021a82021-08-06 00:18:41 -070047 static constexpr std::byte kMessageOther[] = {
48 (std::byte)0x12, (std::byte)0x34, (std::byte)0x56, (std::byte)0x78};
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -080049 static constexpr size_t kMaxDrains = 3;
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -070050 static constexpr size_t kMaxListeners = 3;
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -080051 static constexpr size_t kEntryBufferSize = 1024;
52 static constexpr size_t kBufferSize = 5 * kEntryBufferSize;
53
54 MultiSinkTest() : multisink_(buffer_) {}
55
Carlos Chinchilla64021a82021-08-06 00:18:41 -070056 // Expects the peeked or popped message to equal the provided non-empty
57 // message, and the drop count to match. If `expected_message` is empty, the
58 // Pop call status expected is OUT_OF_RANGE.
59 void ExpectMessageAndDropCount(Result<ConstByteSpan>& result,
60 uint32_t result_drop_count,
Prashanth Swaminathan3eb97d42021-07-13 10:14:38 -070061 std::optional<ConstByteSpan> expected_message,
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -080062 uint32_t expected_drop_count) {
Prashanth Swaminathan3eb97d42021-07-13 10:14:38 -070063 if (!expected_message.has_value()) {
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -080064 EXPECT_EQ(Status::OutOfRange(), result.status());
65 } else {
Carlos Chinchilla64021a82021-08-06 00:18:41 -070066 ASSERT_EQ(result.status(), OkStatus());
Prashanth Swaminathan3eb97d42021-07-13 10:14:38 -070067 if (!expected_message.value().empty()) {
Carlos Chinchilla64021a82021-08-06 00:18:41 -070068 ASSERT_FALSE(result.value().empty());
69 ASSERT_EQ(result.value().size_bytes(),
70 expected_message.value().size_bytes());
Prashanth Swaminathan3eb97d42021-07-13 10:14:38 -070071 EXPECT_EQ(memcmp(result.value().data(),
72 expected_message.value().data(),
73 expected_message.value().size_bytes()),
74 0);
75 }
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -080076 }
Carlos Chinchilla64021a82021-08-06 00:18:41 -070077 EXPECT_EQ(result_drop_count, expected_drop_count);
78 }
79
80 void VerifyPopEntry(Drain& drain,
81 std::optional<ConstByteSpan> expected_message,
82 uint32_t expected_drop_count) {
83 uint32_t drop_count = 0;
84 Result<ConstByteSpan> result = drain.PopEntry(entry_buffer_, drop_count);
85 ExpectMessageAndDropCount(
86 result, drop_count, expected_message, expected_drop_count);
87 }
88
89 void VerifyPeekResult(const Result<Drain::PeekedEntry>& peek_result,
90 uint32_t result_drop_count,
91 std::optional<ConstByteSpan> expected_message,
92 uint32_t expected_drop_count) {
93 if (peek_result.ok()) {
94 ASSERT_FALSE(peek_result.value().entry().empty());
95 Result<ConstByteSpan> verify_result(peek_result.value().entry());
96 ExpectMessageAndDropCount(verify_result,
97 result_drop_count,
98 expected_message,
99 expected_drop_count);
100 return;
101 }
102 if (expected_message.has_value()) {
103 // Fail since we expected OkStatus.
104 ASSERT_EQ(peek_result.status(), OkStatus());
105 }
106 EXPECT_EQ(Status::OutOfRange(), peek_result.status());
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800107 }
108
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700109 void ExpectNotificationCount(CountingListener& listener,
110 size_t expected_notification_count) {
111 EXPECT_EQ(listener.GetNotificationCount(), expected_notification_count);
112 listener.ResetNotificationCount();
113 }
114
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800115 std::byte buffer_[kBufferSize];
116 std::byte entry_buffer_[kEntryBufferSize];
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700117 CountingListener listeners_[kMaxListeners];
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800118 Drain drains_[kMaxDrains];
119 MultiSink multisink_;
120};
121
122TEST_F(MultiSinkTest, SingleDrain) {
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700123 multisink_.AttachDrain(drains_[0]);
124 multisink_.AttachListener(listeners_[0]);
Max Koopman696d6862021-09-29 10:48:29 -0700125 ExpectNotificationCount(listeners_[0], 1u);
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700126 multisink_.HandleEntry(kMessage);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800127
128 // Single entry push and pop.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700129 ExpectNotificationCount(listeners_[0], 1u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700130 VerifyPopEntry(drains_[0], kMessage, 0u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800131
Prashanth Swaminathan3eb97d42021-07-13 10:14:38 -0700132 // Single empty entry push and pop.
133 multisink_.HandleEntry(ConstByteSpan());
134 ExpectNotificationCount(listeners_[0], 1u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700135 VerifyPopEntry(drains_[0], ConstByteSpan(), 0u);
Prashanth Swaminathan3eb97d42021-07-13 10:14:38 -0700136
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800137 // Multiple entries with intermittent drops.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700138 multisink_.HandleEntry(kMessage);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800139 multisink_.HandleDropped();
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700140 multisink_.HandleEntry(kMessage);
141 ExpectNotificationCount(listeners_[0], 3u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700142 VerifyPopEntry(drains_[0], kMessage, 0u);
143 VerifyPopEntry(drains_[0], kMessage, 1u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800144
145 // Send drops only.
146 multisink_.HandleDropped();
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700147 ExpectNotificationCount(listeners_[0], 1u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700148 VerifyPopEntry(drains_[0], std::nullopt, 1u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800149
150 // Confirm out-of-range if no entries are expected.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700151 ExpectNotificationCount(listeners_[0], 0u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700152 VerifyPopEntry(drains_[0], std::nullopt, 0u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800153}
154
155TEST_F(MultiSinkTest, MultipleDrain) {
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700156 multisink_.AttachDrain(drains_[0]);
157 multisink_.AttachDrain(drains_[1]);
158 multisink_.AttachListener(listeners_[0]);
159 multisink_.AttachListener(listeners_[1]);
Max Koopman696d6862021-09-29 10:48:29 -0700160 ExpectNotificationCount(listeners_[0], 1u);
161 ExpectNotificationCount(listeners_[1], 1u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800162
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700163 multisink_.HandleEntry(kMessage);
164 multisink_.HandleEntry(kMessage);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800165 multisink_.HandleDropped();
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700166 multisink_.HandleEntry(kMessage);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800167 multisink_.HandleDropped();
168
169 // Drain one drain entirely.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700170 ExpectNotificationCount(listeners_[0], 5u);
171 ExpectNotificationCount(listeners_[1], 5u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700172 VerifyPopEntry(drains_[0], kMessage, 0u);
173 VerifyPopEntry(drains_[0], kMessage, 0u);
174 VerifyPopEntry(drains_[0], kMessage, 1u);
175 VerifyPopEntry(drains_[0], std::nullopt, 1u);
176 VerifyPopEntry(drains_[0], std::nullopt, 0u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800177
178 // Confirm the other drain can be drained separately.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700179 ExpectNotificationCount(listeners_[0], 0u);
180 ExpectNotificationCount(listeners_[1], 0u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700181 VerifyPopEntry(drains_[1], kMessage, 0u);
182 VerifyPopEntry(drains_[1], kMessage, 0u);
183 VerifyPopEntry(drains_[1], kMessage, 1u);
184 VerifyPopEntry(drains_[1], std::nullopt, 1u);
185 VerifyPopEntry(drains_[1], std::nullopt, 0u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800186}
187
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700188TEST_F(MultiSinkTest, LateDrainRegistration) {
Prashanth Swaminathan099f7162021-07-15 13:42:20 -0700189 // Drains attached after entries are pushed should still observe those entries
190 // if they have not been evicted from the ring buffer.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700191 multisink_.HandleEntry(kMessage);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800192
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700193 multisink_.AttachDrain(drains_[0]);
194 multisink_.AttachListener(listeners_[0]);
Max Koopman696d6862021-09-29 10:48:29 -0700195 ExpectNotificationCount(listeners_[0], 1u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700196 VerifyPopEntry(drains_[0], kMessage, 0u);
197 VerifyPopEntry(drains_[0], std::nullopt, 0u);
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700198
199 multisink_.HandleEntry(kMessage);
200 ExpectNotificationCount(listeners_[0], 1u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700201 VerifyPopEntry(drains_[0], kMessage, 0u);
202 VerifyPopEntry(drains_[0], std::nullopt, 0u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800203}
204
205TEST_F(MultiSinkTest, DynamicDrainRegistration) {
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700206 multisink_.AttachDrain(drains_[0]);
207 multisink_.AttachListener(listeners_[0]);
Max Koopman696d6862021-09-29 10:48:29 -0700208 ExpectNotificationCount(listeners_[0], 1u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800209
210 multisink_.HandleDropped();
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700211 multisink_.HandleEntry(kMessage);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800212 multisink_.HandleDropped();
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700213 multisink_.HandleEntry(kMessage);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800214
215 // Drain out one message and detach it.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700216 ExpectNotificationCount(listeners_[0], 4u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700217 VerifyPopEntry(drains_[0], kMessage, 1u);
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700218 multisink_.DetachDrain(drains_[0]);
219 multisink_.DetachListener(listeners_[0]);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800220
Prashanth Swaminathan099f7162021-07-15 13:42:20 -0700221 // Re-attaching the drain should reproduce the last observed message. Note
222 // that notifications are not expected, nor are drops observed before the
223 // first valid message in the buffer.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700224 multisink_.AttachDrain(drains_[0]);
225 multisink_.AttachListener(listeners_[0]);
Max Koopman696d6862021-09-29 10:48:29 -0700226 ExpectNotificationCount(listeners_[0], 1u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700227 VerifyPopEntry(drains_[0], kMessage, 1u);
228 VerifyPopEntry(drains_[0], kMessage, 1u);
229 VerifyPopEntry(drains_[0], std::nullopt, 0u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800230
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700231 multisink_.HandleEntry(kMessage);
232 ExpectNotificationCount(listeners_[0], 1u);
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700233 VerifyPopEntry(drains_[0], kMessage, 0u);
234 VerifyPopEntry(drains_[0], std::nullopt, 0u);
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800235}
236
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700237TEST_F(MultiSinkTest, TooSmallBuffer) {
238 multisink_.AttachDrain(drains_[0]);
239
240 // Insert an entry and a drop, then try to read into an insufficient buffer.
241 uint32_t drop_count = 0;
242 multisink_.HandleDropped();
243 multisink_.HandleEntry(kMessage);
244
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700245 // Attempting to acquire an entry with a small buffer should result in
246 // RESOURCE_EXHAUSTED and remove it.
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700247 Result<ConstByteSpan> result =
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700248 drains_[0].PopEntry(std::span(entry_buffer_, 1), drop_count);
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700249 EXPECT_EQ(result.status(), Status::ResourceExhausted());
250
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700251 VerifyPopEntry(drains_[0], std::nullopt, 2u);
Prashanth Swaminathan3b1536d2021-05-18 14:21:30 -0700252}
253
Prashanth Swaminathan16541e72021-06-21 09:22:25 -0700254TEST_F(MultiSinkTest, Iterator) {
255 multisink_.AttachDrain(drains_[0]);
256
257 // Insert entries and consume them all.
258 multisink_.HandleEntry(kMessage);
259 multisink_.HandleEntry(kMessage);
260 multisink_.HandleEntry(kMessage);
261
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700262 VerifyPopEntry(drains_[0], kMessage, 0u);
263 VerifyPopEntry(drains_[0], kMessage, 0u);
264 VerifyPopEntry(drains_[0], kMessage, 0u);
Prashanth Swaminathan16541e72021-06-21 09:22:25 -0700265
266 // Confirm that the iterator still observes the messages in the ring buffer.
267 size_t iterated_entries = 0;
268 for (ConstByteSpan entry : multisink_.UnsafeIteration()) {
269 EXPECT_EQ(memcmp(entry.data(), kMessage, sizeof(kMessage)), 0);
270 iterated_entries++;
271 }
272 EXPECT_EQ(iterated_entries, 3u);
273}
274
275TEST_F(MultiSinkTest, IteratorNoDrains) {
276 // Insert entries with no drains attached. Even though there are no consumers,
277 // iterators should still walk from the oldest entry.
278 multisink_.HandleEntry(kMessage);
279 multisink_.HandleEntry(kMessage);
280 multisink_.HandleEntry(kMessage);
281
282 // Confirm that the iterator still observes the messages in the ring buffer.
283 size_t iterated_entries = 0;
284 for (ConstByteSpan entry : multisink_.UnsafeIteration()) {
285 EXPECT_EQ(memcmp(entry.data(), kMessage, sizeof(kMessage)), 0);
286 iterated_entries++;
287 }
288 EXPECT_EQ(iterated_entries, 3u);
289}
290
291TEST_F(MultiSinkTest, IteratorNoEntries) {
292 // Attach a drain, but don't add any entries.
293 multisink_.AttachDrain(drains_[0]);
294 // Confirm that the iterator has no entries.
295 MultiSink::UnsafeIterationWrapper unsafe_iterator =
296 multisink_.UnsafeIteration();
297 EXPECT_EQ(unsafe_iterator.begin(), unsafe_iterator.end());
298}
299
Carlos Chinchilla64021a82021-08-06 00:18:41 -0700300TEST_F(MultiSinkTest, PeekEntryNoEntries) {
301 multisink_.AttachDrain(drains_[0]);
302
303 // Peek empty multisink.
304 uint32_t drop_count = 0;
305 auto peek_result = drains_[0].PeekEntry(entry_buffer_, drop_count);
306 VerifyPeekResult(peek_result, drop_count, std::nullopt, 0);
307}
308
309TEST_F(MultiSinkTest, PeekAndPop) {
310 multisink_.AttachDrain(drains_[0]);
311 multisink_.AttachDrain(drains_[1]);
312
313 // Peek entry after multisink has some entries.
314 multisink_.HandleEntry(kMessage);
315 multisink_.HandleEntry(kMessageOther);
316 uint32_t drop_count = 0;
317 auto first_peek_result = drains_[0].PeekEntry(entry_buffer_, drop_count);
318 VerifyPeekResult(first_peek_result, drop_count, kMessage, 0);
319
320 // Multiple peeks must return the front message.
321 auto peek_duplicate = drains_[0].PeekEntry(entry_buffer_, drop_count);
322 VerifyPeekResult(peek_duplicate, drop_count, kMessage, 0);
323 // A second drain must peek the front message.
324 auto peek_other_drain = drains_[1].PeekEntry(entry_buffer_, drop_count);
325 VerifyPeekResult(peek_other_drain, drop_count, kMessage, 0);
326
327 // After a drain pops a peeked entry, the next peek call must return the next
328 // message.
329 ASSERT_EQ(drains_[0].PopEntry(first_peek_result.value()), OkStatus());
330 auto second_peek_result = drains_[0].PeekEntry(entry_buffer_, drop_count);
331 VerifyPeekResult(second_peek_result, drop_count, kMessageOther, 0);
332 // Slower readers must be unchanged.
333 auto peek_other_drain_duplicate =
334 drains_[1].PeekEntry(entry_buffer_, drop_count);
335 VerifyPeekResult(peek_other_drain_duplicate, drop_count, kMessage, 0);
336
337 // PopEntry prior to popping the previously peeked entry.
338 VerifyPopEntry(drains_[0], kMessageOther, 0);
339 // Popping an entry already handled must not trigger errors.
340 ASSERT_EQ(drains_[0].PopEntry(second_peek_result.value()), OkStatus());
341 // Popping with an old peek context must not trigger errors.
342 ASSERT_EQ(drains_[0].PopEntry(first_peek_result.value()), OkStatus());
343
344 // Multisink is empty, pops and peeks should trigger OUT_OF_RANGE.
345 VerifyPopEntry(drains_[0], std::nullopt, 0);
346 auto empty_peek_result = drains_[0].PeekEntry(entry_buffer_, drop_count);
347 VerifyPeekResult(empty_peek_result, drop_count, std::nullopt, 0);
348
349 // // Slower readers must be unchanged.
350 auto peek_other_drain_unchanged =
351 drains_[1].PeekEntry(entry_buffer_, drop_count);
352 VerifyPeekResult(peek_other_drain_unchanged, drop_count, kMessage, 0);
353}
354
Armando Montanezfb7b4782021-09-30 21:38:20 -0700355TEST(UnsafeIteration, NoLimit) {
356 constexpr std::array<std::string_view, 5> kExpectedEntries{
357 "one", "two", "three", "four", "five"};
358 std::array<std::byte, 32> buffer;
359 MultiSink multisink(buffer);
360
361 for (std::string_view entry : kExpectedEntries) {
362 multisink.HandleEntry(std::as_bytes(std::span(entry)));
363 }
364
365 size_t entry_count = 0;
366 struct {
367 size_t& entry_count;
368 std::span<const std::string_view> expected_results;
369 } ctx{entry_count, kExpectedEntries};
370 auto cb = [&ctx](ConstByteSpan data) {
371 std::string_view expected_entry = ctx.expected_results[ctx.entry_count];
372 EXPECT_EQ(data.size(), expected_entry.size());
373 const int result =
374 memcmp(data.data(), expected_entry.data(), expected_entry.size());
375 EXPECT_EQ(0, result);
376 ctx.entry_count++;
377 };
378
379 EXPECT_EQ(OkStatus(), multisink.UnsafeForEachEntry(cb));
380 EXPECT_EQ(kExpectedEntries.size(), entry_count);
381}
382
383TEST(UnsafeIteration, Subset) {
384 constexpr std::array<std::string_view, 5> kExpectedEntries{
385 "one", "two", "three", "four", "five"};
386 constexpr size_t kStartOffset = 3;
387 constexpr size_t kExpectedEntriesMaxEntries =
388 kExpectedEntries.size() - kStartOffset;
389 std::array<std::byte, 32> buffer;
390 MultiSink multisink(buffer);
391
392 for (std::string_view entry : kExpectedEntries) {
393 multisink.HandleEntry(std::as_bytes(std::span(entry)));
394 }
395
396 size_t entry_count = 0;
397 struct {
398 size_t& entry_count;
399 std::span<const std::string_view> expected_results;
400 } ctx{entry_count, kExpectedEntries};
401 auto cb = [&ctx](ConstByteSpan data) {
402 std::string_view expected_entry =
403 ctx.expected_results[ctx.entry_count + kStartOffset];
404 EXPECT_EQ(data.size(), expected_entry.size());
405 const int result =
406 memcmp(data.data(), expected_entry.data(), expected_entry.size());
407 EXPECT_EQ(0, result);
408 ctx.entry_count++;
409 };
410
411 EXPECT_EQ(
412 OkStatus(),
413 multisink.UnsafeForEachEntry(cb, kExpectedEntries.size() - kStartOffset));
414 EXPECT_EQ(kExpectedEntriesMaxEntries, entry_count);
415}
416
Prashanth Swaminathanf36832a2021-01-27 16:20:32 -0800417} // namespace pw::multisink