1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/stream.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <limits>
18*61c4878aSAndroid Build Coastguard Worker
19*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/array.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/span.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_containers/to_array.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_span/span.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard Worker namespace pw::stream {
27*61c4878aSAndroid Build Coastguard Worker namespace {
28*61c4878aSAndroid Build Coastguard Worker
29*61c4878aSAndroid Build Coastguard Worker static_assert(sizeof(Stream) <= 2 * sizeof(void*),
30*61c4878aSAndroid Build Coastguard Worker "Stream should be no larger than two pointers (vtable pointer & "
31*61c4878aSAndroid Build Coastguard Worker "packed members)");
32*61c4878aSAndroid Build Coastguard Worker
33*61c4878aSAndroid Build Coastguard Worker class TestNonSeekableReader : public NonSeekableReader {
34*61c4878aSAndroid Build Coastguard Worker private:
DoRead(ByteSpan)35*61c4878aSAndroid Build Coastguard Worker StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
36*61c4878aSAndroid Build Coastguard Worker };
37*61c4878aSAndroid Build Coastguard Worker
38*61c4878aSAndroid Build Coastguard Worker class TestRelativeSeekableReader : public RelativeSeekableReader {
39*61c4878aSAndroid Build Coastguard Worker private:
DoRead(ByteSpan)40*61c4878aSAndroid Build Coastguard Worker StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoSeek(ptrdiff_t,Whence)41*61c4878aSAndroid Build Coastguard Worker Status DoSeek(ptrdiff_t, Whence) override { return Status(); }
42*61c4878aSAndroid Build Coastguard Worker };
43*61c4878aSAndroid Build Coastguard Worker
44*61c4878aSAndroid Build Coastguard Worker class TestSeekableReader : public SeekableReader {
45*61c4878aSAndroid Build Coastguard Worker private:
DoRead(ByteSpan)46*61c4878aSAndroid Build Coastguard Worker StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoSeek(ptrdiff_t,Whence)47*61c4878aSAndroid Build Coastguard Worker Status DoSeek(ptrdiff_t, Whence) override { return Status(); }
48*61c4878aSAndroid Build Coastguard Worker };
49*61c4878aSAndroid Build Coastguard Worker
50*61c4878aSAndroid Build Coastguard Worker class TestNonSeekableWriter : public NonSeekableWriter {
51*61c4878aSAndroid Build Coastguard Worker private:
DoWrite(ConstByteSpan)52*61c4878aSAndroid Build Coastguard Worker Status DoWrite(ConstByteSpan) override { return OkStatus(); }
53*61c4878aSAndroid Build Coastguard Worker };
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker class TestRelativeSeekableWriter : public RelativeSeekableWriter {
56*61c4878aSAndroid Build Coastguard Worker private:
DoWrite(ConstByteSpan)57*61c4878aSAndroid Build Coastguard Worker Status DoWrite(ConstByteSpan) override { return OkStatus(); }
DoSeek(ptrdiff_t,Whence)58*61c4878aSAndroid Build Coastguard Worker Status DoSeek(ptrdiff_t, Whence) override { return OkStatus(); }
59*61c4878aSAndroid Build Coastguard Worker };
60*61c4878aSAndroid Build Coastguard Worker
61*61c4878aSAndroid Build Coastguard Worker class TestSeekableWriter : public SeekableWriter {
62*61c4878aSAndroid Build Coastguard Worker private:
DoWrite(ConstByteSpan)63*61c4878aSAndroid Build Coastguard Worker Status DoWrite(ConstByteSpan) override { return OkStatus(); }
DoSeek(ptrdiff_t,Whence)64*61c4878aSAndroid Build Coastguard Worker Status DoSeek(ptrdiff_t, Whence) override { return OkStatus(); }
65*61c4878aSAndroid Build Coastguard Worker };
66*61c4878aSAndroid Build Coastguard Worker
67*61c4878aSAndroid Build Coastguard Worker class TestNonSeekableReaderWriter : public NonSeekableReaderWriter {
68*61c4878aSAndroid Build Coastguard Worker private:
DoRead(ByteSpan)69*61c4878aSAndroid Build Coastguard Worker StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoWrite(ConstByteSpan)70*61c4878aSAndroid Build Coastguard Worker Status DoWrite(ConstByteSpan) override { return OkStatus(); }
71*61c4878aSAndroid Build Coastguard Worker };
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker class TestRelativeSeekableReaderWriter : public RelativeSeekableReaderWriter {
74*61c4878aSAndroid Build Coastguard Worker private:
DoRead(ByteSpan)75*61c4878aSAndroid Build Coastguard Worker StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoWrite(ConstByteSpan)76*61c4878aSAndroid Build Coastguard Worker Status DoWrite(ConstByteSpan) override { return OkStatus(); }
DoSeek(ptrdiff_t,Whence)77*61c4878aSAndroid Build Coastguard Worker Status DoSeek(ptrdiff_t, Whence) override { return OkStatus(); }
78*61c4878aSAndroid Build Coastguard Worker };
79*61c4878aSAndroid Build Coastguard Worker
80*61c4878aSAndroid Build Coastguard Worker class TestSeekableReaderWriter : public SeekableReaderWriter {
81*61c4878aSAndroid Build Coastguard Worker private:
DoRead(ByteSpan)82*61c4878aSAndroid Build Coastguard Worker StatusWithSize DoRead(ByteSpan) override { return StatusWithSize(0); }
DoWrite(ConstByteSpan)83*61c4878aSAndroid Build Coastguard Worker Status DoWrite(ConstByteSpan) override { return OkStatus(); }
DoSeek(ptrdiff_t,Whence)84*61c4878aSAndroid Build Coastguard Worker Status DoSeek(ptrdiff_t, Whence) override { return OkStatus(); }
85*61c4878aSAndroid Build Coastguard Worker };
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard Worker // Test ReaderWriter conversions to Reader/Writer.
88*61c4878aSAndroid Build Coastguard Worker // clang-format off
89*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestNonSeekableReaderWriter, Reader&>());
90*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestNonSeekableReaderWriter, Writer&>());
91*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_convertible<TestNonSeekableReaderWriter, RelativeSeekableReader&>());
92*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_convertible<TestNonSeekableReaderWriter, RelativeSeekableWriter&>());
93*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_convertible<TestNonSeekableReaderWriter, SeekableWriter&>());
94*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_convertible<TestNonSeekableReaderWriter, SeekableReader&>());
95*61c4878aSAndroid Build Coastguard Worker
96*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestRelativeSeekableReaderWriter, Reader&>());
97*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestRelativeSeekableReaderWriter, Writer&>());
98*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestRelativeSeekableReaderWriter, RelativeSeekableReader&>());
99*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestRelativeSeekableReaderWriter, RelativeSeekableWriter&>());
100*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_convertible<TestRelativeSeekableReaderWriter, SeekableWriter&>());
101*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_convertible<TestRelativeSeekableReaderWriter, SeekableReader&>());
102*61c4878aSAndroid Build Coastguard Worker
103*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestSeekableReaderWriter, Reader&>());
104*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestSeekableReaderWriter, Writer&>());
105*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestSeekableReaderWriter, RelativeSeekableReader&>());
106*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestSeekableReaderWriter, RelativeSeekableWriter&>());
107*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestSeekableReaderWriter, SeekableWriter&>());
108*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_convertible<TestSeekableReaderWriter, SeekableReader&>());
109*61c4878aSAndroid Build Coastguard Worker // clang-format on
110*61c4878aSAndroid Build Coastguard Worker
111*61c4878aSAndroid Build Coastguard Worker constexpr uint8_t kSeekable =
112*61c4878aSAndroid Build Coastguard Worker Stream::kBeginning | Stream::kCurrent | Stream::kEnd;
113*61c4878aSAndroid Build Coastguard Worker constexpr uint8_t kRelativeSeekable = Stream::kCurrent;
114*61c4878aSAndroid Build Coastguard Worker constexpr uint8_t kNonSeekable = 0;
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard Worker enum Readable : bool { kNonReadable = false, kReadable = true };
117*61c4878aSAndroid Build Coastguard Worker enum Writable : bool { kNonWritable = false, kWritable = true };
118*61c4878aSAndroid Build Coastguard Worker
119*61c4878aSAndroid Build Coastguard Worker template <typename T, Readable readable, Writable writable, uint8_t seekable>
TestStreamImpl()120*61c4878aSAndroid Build Coastguard Worker void TestStreamImpl() {
121*61c4878aSAndroid Build Coastguard Worker T derived_stream;
122*61c4878aSAndroid Build Coastguard Worker Stream& stream = derived_stream;
123*61c4878aSAndroid Build Coastguard Worker
124*61c4878aSAndroid Build Coastguard Worker // Check stream properties
125*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(writable, stream.writable());
126*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(readable, stream.readable());
127*61c4878aSAndroid Build Coastguard Worker
128*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ((seekable & Stream::kBeginning) != 0,
129*61c4878aSAndroid Build Coastguard Worker stream.seekable(Stream::kBeginning));
130*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ((seekable & Stream::kCurrent) != 0,
131*61c4878aSAndroid Build Coastguard Worker stream.seekable(Stream::kCurrent));
132*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ((seekable & Stream::kEnd) != 0, stream.seekable(Stream::kEnd));
133*61c4878aSAndroid Build Coastguard Worker
134*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(seekable != kNonSeekable, stream.seekable());
135*61c4878aSAndroid Build Coastguard Worker
136*61c4878aSAndroid Build Coastguard Worker // Check Read()/Write()/Seek()
137*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(readable ? OkStatus() : Status::Unimplemented(),
138*61c4878aSAndroid Build Coastguard Worker stream.Read({}).status());
139*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(writable ? OkStatus() : Status::Unimplemented(), stream.Write({}));
140*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(seekable ? OkStatus() : Status::Unimplemented(), stream.Seek(0));
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker // Check ConservativeLimits()
143*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(readable ? Stream::kUnlimited : 0, stream.ConservativeReadLimit());
144*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(writable ? Stream::kUnlimited : 0, stream.ConservativeWriteLimit());
145*61c4878aSAndroid Build Coastguard Worker }
146*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,NonSeekableReader)147*61c4878aSAndroid Build Coastguard Worker TEST(Stream, NonSeekableReader) {
148*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestNonSeekableReader,
149*61c4878aSAndroid Build Coastguard Worker kReadable,
150*61c4878aSAndroid Build Coastguard Worker kNonWritable,
151*61c4878aSAndroid Build Coastguard Worker kNonSeekable>();
152*61c4878aSAndroid Build Coastguard Worker }
153*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,RelativeSeekableReader)154*61c4878aSAndroid Build Coastguard Worker TEST(Stream, RelativeSeekableReader) {
155*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestRelativeSeekableReader,
156*61c4878aSAndroid Build Coastguard Worker kReadable,
157*61c4878aSAndroid Build Coastguard Worker kNonWritable,
158*61c4878aSAndroid Build Coastguard Worker kRelativeSeekable>();
159*61c4878aSAndroid Build Coastguard Worker }
160*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,SeekableReader)161*61c4878aSAndroid Build Coastguard Worker TEST(Stream, SeekableReader) {
162*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestSeekableReader, kReadable, kNonWritable, kSeekable>();
163*61c4878aSAndroid Build Coastguard Worker }
164*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,NonSeekableWriter)165*61c4878aSAndroid Build Coastguard Worker TEST(Stream, NonSeekableWriter) {
166*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestNonSeekableWriter,
167*61c4878aSAndroid Build Coastguard Worker kNonReadable,
168*61c4878aSAndroid Build Coastguard Worker kWritable,
169*61c4878aSAndroid Build Coastguard Worker kNonSeekable>();
170*61c4878aSAndroid Build Coastguard Worker }
171*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,RelativeSeekableWriter)172*61c4878aSAndroid Build Coastguard Worker TEST(Stream, RelativeSeekableWriter) {
173*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestRelativeSeekableWriter,
174*61c4878aSAndroid Build Coastguard Worker kNonReadable,
175*61c4878aSAndroid Build Coastguard Worker kWritable,
176*61c4878aSAndroid Build Coastguard Worker kRelativeSeekable>();
177*61c4878aSAndroid Build Coastguard Worker }
178*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,SeekableWriter)179*61c4878aSAndroid Build Coastguard Worker TEST(Stream, SeekableWriter) {
180*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestSeekableWriter, kNonReadable, kWritable, kSeekable>();
181*61c4878aSAndroid Build Coastguard Worker }
182*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,NonSeekableReaderWriter)183*61c4878aSAndroid Build Coastguard Worker TEST(Stream, NonSeekableReaderWriter) {
184*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestNonSeekableReaderWriter,
185*61c4878aSAndroid Build Coastguard Worker kReadable,
186*61c4878aSAndroid Build Coastguard Worker kWritable,
187*61c4878aSAndroid Build Coastguard Worker kNonSeekable>();
188*61c4878aSAndroid Build Coastguard Worker }
189*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,RelativeSeekableReaderWriter)190*61c4878aSAndroid Build Coastguard Worker TEST(Stream, RelativeSeekableReaderWriter) {
191*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestRelativeSeekableReaderWriter,
192*61c4878aSAndroid Build Coastguard Worker kReadable,
193*61c4878aSAndroid Build Coastguard Worker kWritable,
194*61c4878aSAndroid Build Coastguard Worker kRelativeSeekable>();
195*61c4878aSAndroid Build Coastguard Worker }
196*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,SeekableReaderWriter)197*61c4878aSAndroid Build Coastguard Worker TEST(Stream, SeekableReaderWriter) {
198*61c4878aSAndroid Build Coastguard Worker TestStreamImpl<TestSeekableReaderWriter, kReadable, kWritable, kSeekable>();
199*61c4878aSAndroid Build Coastguard Worker }
200*61c4878aSAndroid Build Coastguard Worker
201*61c4878aSAndroid Build Coastguard Worker class TestFragmentedReader : public NonSeekableReader {
202*61c4878aSAndroid Build Coastguard Worker public:
TestFragmentedReader(ConstByteSpan data,span<StatusWithSize> frags)203*61c4878aSAndroid Build Coastguard Worker TestFragmentedReader(ConstByteSpan data, span<StatusWithSize> frags)
204*61c4878aSAndroid Build Coastguard Worker : data_(data), frags_(frags), current_frag_(frags.begin()) {
205*61c4878aSAndroid Build Coastguard Worker size_t frags_sum = 0;
206*61c4878aSAndroid Build Coastguard Worker for (const auto& frag : frags) {
207*61c4878aSAndroid Build Coastguard Worker frags_sum += frag.size();
208*61c4878aSAndroid Build Coastguard Worker }
209*61c4878aSAndroid Build Coastguard Worker PW_CHECK_UINT_LE(frags_sum, data.size());
210*61c4878aSAndroid Build Coastguard Worker }
211*61c4878aSAndroid Build Coastguard Worker
212*61c4878aSAndroid Build Coastguard Worker private:
DoRead(ByteSpan dest)213*61c4878aSAndroid Build Coastguard Worker StatusWithSize DoRead(ByteSpan dest) override {
214*61c4878aSAndroid Build Coastguard Worker // Each fragment is consumed entirely on each read.
215*61c4878aSAndroid Build Coastguard Worker PW_CHECK_UINT_GE(dest.size(), current_frag_->size());
216*61c4878aSAndroid Build Coastguard Worker PW_CHECK(current_frag_ != frags_.end());
217*61c4878aSAndroid Build Coastguard Worker
218*61c4878aSAndroid Build Coastguard Worker auto frag = current_frag_++;
219*61c4878aSAndroid Build Coastguard Worker auto source = data_.subspan(data_offset_, frag->size());
220*61c4878aSAndroid Build Coastguard Worker data_offset_ += frag->size();
221*61c4878aSAndroid Build Coastguard Worker
222*61c4878aSAndroid Build Coastguard Worker std::copy(source.begin(), source.end(), dest.begin());
223*61c4878aSAndroid Build Coastguard Worker return *frag;
224*61c4878aSAndroid Build Coastguard Worker }
225*61c4878aSAndroid Build Coastguard Worker
226*61c4878aSAndroid Build Coastguard Worker ConstByteSpan data_;
227*61c4878aSAndroid Build Coastguard Worker span<StatusWithSize> frags_;
228*61c4878aSAndroid Build Coastguard Worker decltype(frags_)::iterator current_frag_;
229*61c4878aSAndroid Build Coastguard Worker size_t data_offset_ = 0;
230*61c4878aSAndroid Build Coastguard Worker };
231*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,ReadExact_Works)232*61c4878aSAndroid Build Coastguard Worker TEST(Stream, ReadExact_Works) {
233*61c4878aSAndroid Build Coastguard Worker constexpr auto kData = bytes::
234*61c4878aSAndroid Build Coastguard Worker Array<0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A>();
235*61c4878aSAndroid Build Coastguard Worker
236*61c4878aSAndroid Build Coastguard Worker auto frags = containers::to_array<StatusWithSize>({
237*61c4878aSAndroid Build Coastguard Worker StatusWithSize(3), // 0x00, 0x01, 0x02
238*61c4878aSAndroid Build Coastguard Worker StatusWithSize(5), // 0x03, 0x04, 0x05, 0x06, 0x07
239*61c4878aSAndroid Build Coastguard Worker StatusWithSize(1), // 0x08
240*61c4878aSAndroid Build Coastguard Worker StatusWithSize(2), // 0x09, 0x0A
241*61c4878aSAndroid Build Coastguard Worker });
242*61c4878aSAndroid Build Coastguard Worker
243*61c4878aSAndroid Build Coastguard Worker TestFragmentedReader reader(kData, frags);
244*61c4878aSAndroid Build Coastguard Worker
245*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kData.size()> dest;
246*61c4878aSAndroid Build Coastguard Worker auto result = reader.ReadExact(dest);
247*61c4878aSAndroid Build Coastguard Worker
248*61c4878aSAndroid Build Coastguard Worker PW_TEST_ASSERT_OK(result);
249*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result->data(), dest.data());
250*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result->size(), dest.size());
251*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(std::equal(result->begin(), result->end(), kData.begin()));
252*61c4878aSAndroid Build Coastguard Worker }
253*61c4878aSAndroid Build Coastguard Worker
TEST(Stream,ReadExact_HandlesError)254*61c4878aSAndroid Build Coastguard Worker TEST(Stream, ReadExact_HandlesError) {
255*61c4878aSAndroid Build Coastguard Worker constexpr auto kData = bytes::
256*61c4878aSAndroid Build Coastguard Worker Array<0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A>();
257*61c4878aSAndroid Build Coastguard Worker
258*61c4878aSAndroid Build Coastguard Worker auto frags = containers::to_array<StatusWithSize>({
259*61c4878aSAndroid Build Coastguard Worker StatusWithSize(3), // 0x00, 0x01, 0x02
260*61c4878aSAndroid Build Coastguard Worker StatusWithSize(5), // 0x03, 0x04, 0x05, 0x06, 0x07
261*61c4878aSAndroid Build Coastguard Worker StatusWithSize::Internal(1), // 0x08
262*61c4878aSAndroid Build Coastguard Worker StatusWithSize(2), // 0x09, 0x0A
263*61c4878aSAndroid Build Coastguard Worker });
264*61c4878aSAndroid Build Coastguard Worker
265*61c4878aSAndroid Build Coastguard Worker TestFragmentedReader reader(kData, frags);
266*61c4878aSAndroid Build Coastguard Worker
267*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kData.size()> dest;
268*61c4878aSAndroid Build Coastguard Worker auto result = reader.ReadExact(dest);
269*61c4878aSAndroid Build Coastguard Worker
270*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result.status(), Status::Internal());
271*61c4878aSAndroid Build Coastguard Worker }
272*61c4878aSAndroid Build Coastguard Worker
273*61c4878aSAndroid Build Coastguard Worker } // namespace
274*61c4878aSAndroid Build Coastguard Worker } // namespace pw::stream
275