1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 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_multibuf/stream.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/array.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_multibuf/multibuf.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_multibuf_private/test_utils.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker namespace pw::multibuf {
24*61c4878aSAndroid Build Coastguard Worker namespace {
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard Worker using namespace pw::multibuf::test_utils;
27*61c4878aSAndroid Build Coastguard Worker
__anon9fdcf5f70202(size_t i) 28*61c4878aSAndroid Build Coastguard Worker constexpr auto kData64 = bytes::Initialized<64>([](size_t i) { return i; });
29*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Write_SingleChunkMultibuf_Succeeds)30*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Write_SingleChunkMultibuf_Succeeds) {
31*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
32*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
33*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 128, kPoisonByte));
34*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
35*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Write(kData64), OkStatus());
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Worker ExpectElementsEqual(buf, kData64);
38*61c4878aSAndroid Build Coastguard Worker buf.DiscardPrefix(kData64.size());
39*61c4878aSAndroid Build Coastguard Worker ExpectElementsAre(buf, std::byte{kPoisonByte});
40*61c4878aSAndroid Build Coastguard Worker }
41*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Write_SingleChunkMultibuf_ExactSize_Succeeds)42*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Write_SingleChunkMultibuf_ExactSize_Succeeds) {
43*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
44*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
45*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, kData64.size(), kPoisonByte));
46*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
47*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Write(kData64), OkStatus());
48*61c4878aSAndroid Build Coastguard Worker
49*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(buf.size(), kData64.size());
50*61c4878aSAndroid Build Coastguard Worker ExpectElementsEqual(buf, kData64);
51*61c4878aSAndroid Build Coastguard Worker }
52*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Write_MultiChunkMultibuf_Succeeds)53*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Write_MultiChunkMultibuf_Succeeds) {
54*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
55*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
56*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
57*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
58*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 24, kPoisonByte));
59*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 8, kPoisonByte));
60*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
61*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(writer.Write(kData64), OkStatus());
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard Worker ExpectElementsEqual(buf, kData64);
64*61c4878aSAndroid Build Coastguard Worker }
65*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Write_MultiChunkMultibuf_OutOfRange)66*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Write_MultiChunkMultibuf_OutOfRange) {
67*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
68*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
69*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
70*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 8, kPoisonByte));
71*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
72*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(writer.Write(kData64), Status::OutOfRange());
73*61c4878aSAndroid Build Coastguard Worker
74*61c4878aSAndroid Build Coastguard Worker ExpectElementsEqual(buf, span(kData64).first(24));
75*61c4878aSAndroid Build Coastguard Worker }
76*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Write_EmptyMultibuf_ReturnsOutOfRange)77*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Write_EmptyMultibuf_ReturnsOutOfRange) {
78*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
79*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
80*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Write(kData64), Status::OutOfRange());
81*61c4878aSAndroid Build Coastguard Worker }
82*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Seek_Empty)83*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Seek_Empty) {
84*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
85*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
86*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(0), Status::OutOfRange());
87*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(-100), Status::OutOfRange());
88*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(100), Status::OutOfRange());
89*61c4878aSAndroid Build Coastguard Worker }
90*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Seek_OutOfBounds)91*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Seek_OutOfBounds) {
92*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
93*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
94*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
95*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
96*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
97*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(-1), Status::OutOfRange());
98*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(buf.size()), Status::OutOfRange());
99*61c4878aSAndroid Build Coastguard Worker }
100*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Seek_SingleChunkMultibuf_Succeeds)101*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Seek_SingleChunkMultibuf_Succeeds) {
102*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
103*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
104*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 64, kPoisonByte));
105*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
106*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(32), OkStatus());
107*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Write(bytes::Initialized<8>(2)), OkStatus());
108*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(40), OkStatus());
109*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Write(bytes::Initialized<24>(1)), OkStatus());
110*61c4878aSAndroid Build Coastguard Worker
111*61c4878aSAndroid Build Coastguard Worker constexpr auto kExpected =
112*61c4878aSAndroid Build Coastguard Worker bytes::Concat(bytes::Initialized<32>(static_cast<uint8_t>(kPoisonByte)),
113*61c4878aSAndroid Build Coastguard Worker bytes::Initialized<8>(2),
114*61c4878aSAndroid Build Coastguard Worker bytes::Initialized<24>(1));
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard Worker ExpectElementsEqual(buf, kExpected);
117*61c4878aSAndroid Build Coastguard Worker }
118*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Seek_MultiChunkMultiBuf_Succeeds)119*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Seek_MultiChunkMultiBuf_Succeeds) {
120*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
121*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
122*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
123*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 8, kPoisonByte));
124*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
125*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 8, kPoisonByte));
126*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
127*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
128*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(32), OkStatus());
129*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Write(bytes::Initialized<8>(1)), OkStatus());
130*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(40), OkStatus());
131*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Write(bytes::Initialized<24>(2)), OkStatus());
132*61c4878aSAndroid Build Coastguard Worker
133*61c4878aSAndroid Build Coastguard Worker constexpr auto kExpected =
134*61c4878aSAndroid Build Coastguard Worker bytes::Concat(bytes::Initialized<32>(static_cast<uint8_t>(kPoisonByte)),
135*61c4878aSAndroid Build Coastguard Worker bytes::Initialized<8>(1),
136*61c4878aSAndroid Build Coastguard Worker bytes::Initialized<24>(2));
137*61c4878aSAndroid Build Coastguard Worker
138*61c4878aSAndroid Build Coastguard Worker ExpectElementsEqual(buf, kExpected);
139*61c4878aSAndroid Build Coastguard Worker }
140*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Seek_Backwards_ReturnsOutOfRange)141*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Seek_Backwards_ReturnsOutOfRange) {
142*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
143*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
144*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
145*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 8, kPoisonByte));
146*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
147*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 8, kPoisonByte));
148*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, kPoisonByte));
149*61c4878aSAndroid Build Coastguard Worker Stream writer(buf);
150*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(32), OkStatus());
151*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(30), Status::OutOfRange());
152*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(48), OkStatus());
153*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(-4, Stream::Whence::kCurrent), Status::OutOfRange());
154*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(60), OkStatus());
155*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(writer.Seek(64), Status::OutOfRange());
156*61c4878aSAndroid Build Coastguard Worker }
157*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Read_EmptyMultibuf_ReturnsOutOfRange)158*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Read_EmptyMultibuf_ReturnsOutOfRange) {
159*61c4878aSAndroid Build Coastguard Worker auto destination = bytes::Initialized<64>(static_cast<uint8_t>(kPoisonByte));
160*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
161*61c4878aSAndroid Build Coastguard Worker Stream reader(buf);
162*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(reader.Read(destination).status(), Status::OutOfRange());
163*61c4878aSAndroid Build Coastguard Worker ExpectElementsAre(destination, kPoisonByte);
164*61c4878aSAndroid Build Coastguard Worker }
165*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Read_SingleChunkMultiBuf_Succeeds)166*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Read_SingleChunkMultiBuf_Succeeds) {
167*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
168*61c4878aSAndroid Build Coastguard Worker auto destination = bytes::Initialized<64>(static_cast<uint8_t>(kPoisonByte));
169*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
170*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, std::byte{1}));
171*61c4878aSAndroid Build Coastguard Worker Stream reader(buf);
172*61c4878aSAndroid Build Coastguard Worker
173*61c4878aSAndroid Build Coastguard Worker Result<ByteSpan> result = reader.Read(destination);
174*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result.status(), OkStatus());
175*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result->size(), 16u);
176*61c4878aSAndroid Build Coastguard Worker ExpectElementsAre(*result, std::byte{1});
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard Worker result = reader.Read(destination);
179*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result.status(), Status::OutOfRange());
180*61c4878aSAndroid Build Coastguard Worker ExpectElementsAre(span(destination).first(16), std::byte{1});
181*61c4878aSAndroid Build Coastguard Worker ExpectElementsAre(span(destination).subspan(16), kPoisonByte);
182*61c4878aSAndroid Build Coastguard Worker }
183*61c4878aSAndroid Build Coastguard Worker
TEST(MultibufStream,Read_MultiChunkMultiBuf_Succeeds)184*61c4878aSAndroid Build Coastguard Worker TEST(MultibufStream, Read_MultiChunkMultiBuf_Succeeds) {
185*61c4878aSAndroid Build Coastguard Worker AllocatorForTest<kArbitraryAllocatorSize> allocator;
186*61c4878aSAndroid Build Coastguard Worker auto destination = bytes::Initialized<64>(static_cast<uint8_t>(kPoisonByte));
187*61c4878aSAndroid Build Coastguard Worker MultiBuf buf;
188*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 16, std::byte{2}));
189*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 8, std::byte{3}));
190*61c4878aSAndroid Build Coastguard Worker buf.PushFrontChunk(MakeChunk(allocator, 8, std::byte{4}));
191*61c4878aSAndroid Build Coastguard Worker Stream reader(buf);
192*61c4878aSAndroid Build Coastguard Worker
193*61c4878aSAndroid Build Coastguard Worker constexpr auto kExpected = bytes::Concat(bytes::Initialized<8>(4),
194*61c4878aSAndroid Build Coastguard Worker bytes::Initialized<8>(3),
195*61c4878aSAndroid Build Coastguard Worker bytes::Initialized<16>(2));
196*61c4878aSAndroid Build Coastguard Worker
197*61c4878aSAndroid Build Coastguard Worker Result<ByteSpan> result = reader.Read(destination);
198*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result.status(), OkStatus());
199*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result->size(), 32u);
200*61c4878aSAndroid Build Coastguard Worker ExpectElementsEqual(*result, kExpected);
201*61c4878aSAndroid Build Coastguard Worker
202*61c4878aSAndroid Build Coastguard Worker result = reader.Read(destination);
203*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result.status(), Status::OutOfRange());
204*61c4878aSAndroid Build Coastguard Worker ExpectElementsEqual(span(destination).first(32), kExpected);
205*61c4878aSAndroid Build Coastguard Worker ExpectElementsAre(span(destination).subspan(32), kPoisonByte);
206*61c4878aSAndroid Build Coastguard Worker }
207*61c4878aSAndroid Build Coastguard Worker
208*61c4878aSAndroid Build Coastguard Worker } // namespace
209*61c4878aSAndroid Build Coastguard Worker } // namespace pw::multibuf
210