pw_multisink: Unsafe iteration dump utilities

Addds a crash-time helper to dump a MultiSink used for proto encoded
logs.

Change-Id: I5b8efb3f2d3c86f403896fca9cdd4ddde5e6cc39
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/63282
Pigweed-Auto-Submit: Armando Montanez <amontanez@google.com>
Commit-Queue: Armando Montanez <amontanez@google.com>
Reviewed-by: Ewout van Bekkum <ewout@google.com>
diff --git a/pw_multisink/multisink_test.cc b/pw_multisink/multisink_test.cc
index 56c0f10..4a6dc6b 100644
--- a/pw_multisink/multisink_test.cc
+++ b/pw_multisink/multisink_test.cc
@@ -17,8 +17,10 @@
 #include <array>
 #include <cstdint>
 #include <optional>
+#include <string_view>
 
 #include "gtest/gtest.h"
+#include "pw_function/function.h"
 #include "pw_status/status.h"
 
 namespace pw::multisink {
@@ -349,4 +351,66 @@
   VerifyPeekResult(peek_other_drain_unchanged, drop_count, kMessage, 0);
 }
 
+TEST(UnsafeIteration, NoLimit) {
+  constexpr std::array<std::string_view, 5> kExpectedEntries{
+      "one", "two", "three", "four", "five"};
+  std::array<std::byte, 32> buffer;
+  MultiSink multisink(buffer);
+
+  for (std::string_view entry : kExpectedEntries) {
+    multisink.HandleEntry(std::as_bytes(std::span(entry)));
+  }
+
+  size_t entry_count = 0;
+  struct {
+    size_t& entry_count;
+    std::span<const std::string_view> expected_results;
+  } ctx{entry_count, kExpectedEntries};
+  auto cb = [&ctx](ConstByteSpan data) {
+    std::string_view expected_entry = ctx.expected_results[ctx.entry_count];
+    EXPECT_EQ(data.size(), expected_entry.size());
+    const int result =
+        memcmp(data.data(), expected_entry.data(), expected_entry.size());
+    EXPECT_EQ(0, result);
+    ctx.entry_count++;
+  };
+
+  EXPECT_EQ(OkStatus(), multisink.UnsafeForEachEntry(cb));
+  EXPECT_EQ(kExpectedEntries.size(), entry_count);
+}
+
+TEST(UnsafeIteration, Subset) {
+  constexpr std::array<std::string_view, 5> kExpectedEntries{
+      "one", "two", "three", "four", "five"};
+  constexpr size_t kStartOffset = 3;
+  constexpr size_t kExpectedEntriesMaxEntries =
+      kExpectedEntries.size() - kStartOffset;
+  std::array<std::byte, 32> buffer;
+  MultiSink multisink(buffer);
+
+  for (std::string_view entry : kExpectedEntries) {
+    multisink.HandleEntry(std::as_bytes(std::span(entry)));
+  }
+
+  size_t entry_count = 0;
+  struct {
+    size_t& entry_count;
+    std::span<const std::string_view> expected_results;
+  } ctx{entry_count, kExpectedEntries};
+  auto cb = [&ctx](ConstByteSpan data) {
+    std::string_view expected_entry =
+        ctx.expected_results[ctx.entry_count + kStartOffset];
+    EXPECT_EQ(data.size(), expected_entry.size());
+    const int result =
+        memcmp(data.data(), expected_entry.data(), expected_entry.size());
+    EXPECT_EQ(0, result);
+    ctx.entry_count++;
+  };
+
+  EXPECT_EQ(
+      OkStatus(),
+      multisink.UnsafeForEachEntry(cb, kExpectedEntries.size() - kStartOffset));
+  EXPECT_EQ(kExpectedEntriesMaxEntries, entry_count);
+}
+
 }  // namespace pw::multisink