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