1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/containers/span_writer.h"
6
7 #include <array>
8 #include <memory>
9
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 namespace base {
14 namespace {
15
16 using testing::ElementsAre;
17 using testing::Optional;
18 using testing::Pointee;
19
TEST(SpanWriterTest,Construct)20 TEST(SpanWriterTest, Construct) {
21 std::array<int, 5u> kArray = {1, 2, 3, 4, 5};
22
23 auto r = SpanWriter(span(kArray));
24 EXPECT_EQ(r.remaining(), 5u);
25 EXPECT_EQ(r.remaining_span().data(), &kArray[0u]);
26 EXPECT_EQ(r.remaining_span().size(), 5u);
27 }
28
TEST(SpanWriterTest,WriteSpan)29 TEST(SpanWriterTest, WriteSpan) {
30 // Dynamic size.
31 {
32 std::array<int, 5u> kArray = {1, 2, 3, 4, 5};
33 auto r = SpanWriter(span(kArray));
34 EXPECT_EQ(r.num_written(), 0u);
35
36 EXPECT_TRUE(r.Write(span<const int>({9, 8}).subspan(0u)));
37 EXPECT_EQ(r.remaining(), 3u);
38 EXPECT_EQ(r.num_written(), 2u);
39 EXPECT_EQ(kArray, span<const int>({9, 8, 3, 4, 5}));
40
41 EXPECT_TRUE(r.Write(span<int>()));
42 EXPECT_EQ(r.remaining(), 3u);
43 EXPECT_EQ(r.num_written(), 2u);
44 EXPECT_EQ(kArray, span<const int>({9, 8, 3, 4, 5}));
45
46 EXPECT_FALSE(r.Write(span<const int>({7, 6, -1, -1}).subspan(0u)));
47 EXPECT_EQ(r.remaining(), 3u);
48 EXPECT_EQ(r.num_written(), 2u);
49 EXPECT_EQ(kArray, span<const int>({9, 8, 3, 4, 5}));
50
51 EXPECT_TRUE(r.Write(span<const int>({7, 6, -1}).subspan(0u)));
52 EXPECT_EQ(r.remaining(), 0u);
53 EXPECT_EQ(r.num_written(), 5u);
54 EXPECT_EQ(kArray, span<const int>({9, 8, 7, 6, -1}));
55
56 EXPECT_TRUE(r.Write(span<int>()));
57 EXPECT_EQ(r.remaining(), 0u);
58 EXPECT_EQ(r.num_written(), 5u);
59 EXPECT_EQ(kArray, span<const int>({9, 8, 7, 6, -1}));
60 }
61
62 // Fixed size with mutable input.
63 {
64 std::array<int, 5u> kArray = {1, 2, 3, 4, 5};
65 auto r = SpanWriter(span(kArray));
66 EXPECT_EQ(r.num_written(), 0u);
67
68 EXPECT_TRUE(r.Write(span<const int>({9, 8})));
69 EXPECT_EQ(r.remaining(), 3u);
70 EXPECT_EQ(r.num_written(), 2u);
71 EXPECT_EQ(kArray, span<const int>({9, 8, 3, 4, 5}));
72
73 EXPECT_TRUE(r.Write(span<int, 0u>()));
74 EXPECT_EQ(r.remaining(), 3u);
75 EXPECT_EQ(r.num_written(), 2u);
76 EXPECT_EQ(kArray, span<const int>({9, 8, 3, 4, 5}));
77
78 EXPECT_FALSE(r.Write(span<const int>({7, 6, -1, -1})));
79 EXPECT_EQ(r.remaining(), 3u);
80 EXPECT_EQ(r.num_written(), 2u);
81 EXPECT_EQ(kArray, span<const int>({9, 8, 3, 4, 5}));
82
83 EXPECT_TRUE(r.Write(span<const int>({7, 6, -1})));
84 EXPECT_EQ(r.remaining(), 0u);
85 EXPECT_EQ(r.num_written(), 5u);
86 EXPECT_EQ(kArray, span<const int>({9, 8, 7, 6, -1}));
87
88 EXPECT_TRUE(r.Write(span<int, 0u>()));
89 EXPECT_EQ(r.remaining(), 0u);
90 EXPECT_EQ(r.num_written(), 5u);
91 EXPECT_EQ(kArray, span<const int>({9, 8, 7, 6, -1}));
92 }
93
94 // Fixed size with const input.
95 {
96 std::array<int, 5u> kArray = {1, 2, 3, 4, 5};
97 auto r = SpanWriter(span(kArray));
98 EXPECT_EQ(r.num_written(), 0u);
99
100 std::array<const int, 2u> kConstArray = {9, 8};
101 EXPECT_TRUE(r.Write(span(kConstArray)));
102 EXPECT_EQ(r.remaining(), 3u);
103 EXPECT_EQ(r.num_written(), 2u);
104 EXPECT_EQ(kArray, span<const int>({9, 8, 3, 4, 5}));
105 }
106 }
107
TEST(SpanWriterTest,WriteValue)108 TEST(SpanWriterTest, WriteValue) {
109 auto array = std::to_array<int>({1, 2});
110
111 auto r = SpanWriter(span(array));
112 EXPECT_TRUE(r.Write(10));
113 EXPECT_TRUE(r.Write(20));
114 EXPECT_THAT(array, ElementsAre(10, 20));
115 }
116
TEST(SpanWriterTest,WriteValueMoveOnly)117 TEST(SpanWriterTest, WriteValueMoveOnly) {
118 std::array<std::unique_ptr<int>, 2> array;
119
120 auto r = SpanWriter(span(array));
121 EXPECT_TRUE(r.Write(std::make_unique<int>(23)));
122 EXPECT_TRUE(r.Write(std::make_unique<int>(88)));
123 EXPECT_THAT(array, ElementsAre(testing::Pointee(23), testing::Pointee(88)));
124 }
125
TEST(SpanWriterTest,Skip)126 TEST(SpanWriterTest, Skip) {
127 std::array<int, 5u> kArray = {1, 2, 3, 4, 5};
128
129 auto r = SpanWriter(span(kArray));
130 auto s = r.Skip(2u);
131 static_assert(std::same_as<decltype(s), std::optional<span<int>>>);
132 EXPECT_THAT(s, Optional(span(kArray).first<2u>()));
133 EXPECT_EQ(r.remaining(), 3u);
134 EXPECT_EQ(r.remaining_span(), span<const int>({3, 4, 5}));
135
136 EXPECT_FALSE(r.Skip(12u));
137 EXPECT_EQ(r.remaining(), 3u);
138 EXPECT_EQ(r.remaining_span(), span<const int>({3, 4, 5}));
139 }
140
TEST(SpanWriterTest,SkipFixed)141 TEST(SpanWriterTest, SkipFixed) {
142 std::array<int, 5u> kArray = {1, 2, 3, 4, 5};
143
144 auto r = SpanWriter(span(kArray));
145 auto s = r.Skip<2u>();
146 static_assert(std::same_as<decltype(s), std::optional<span<int, 2>>>);
147 EXPECT_THAT(s, Optional(span(kArray).first<2u>()));
148 EXPECT_EQ(r.remaining(), 3u);
149 EXPECT_EQ(r.remaining_span(), span<const int>({3, 4, 5}));
150
151 EXPECT_FALSE(r.Skip<12u>());
152 EXPECT_EQ(r.remaining(), 3u);
153 EXPECT_EQ(r.remaining_span(), span<const int>({3, 4, 5}));
154 }
155
TEST(SpanWriterTest,WriteNativeEndian_Unsigned)156 TEST(SpanWriterTest, WriteNativeEndian_Unsigned) {
157 std::array<uint8_t, 5u> kArray = {1, 2, 3, 4, 5};
158 std::array<uint8_t, 9u> kBigArray = {1, 1, 1, 1, 1, 1, 1, 1, 1};
159
160 {
161 auto r = SpanWriter(span(kArray));
162 EXPECT_TRUE(r.Skip(1u));
163 EXPECT_TRUE(r.WriteU8NativeEndian(0x09));
164 EXPECT_EQ(r.remaining(), 3u);
165 EXPECT_EQ(kArray, span<const uint8_t>({1, 9, 3, 4, 5}));
166 }
167 {
168 auto r = SpanWriter(span(kArray));
169 EXPECT_TRUE(r.Skip(1u));
170 EXPECT_TRUE(r.WriteU16NativeEndian(0x0809));
171 EXPECT_EQ(r.remaining(), 2u);
172 EXPECT_EQ(kArray, span<const uint8_t>({1, 9, 8, 4, 5}));
173 }
174 {
175 auto r = SpanWriter(span(kArray));
176 EXPECT_TRUE(r.Skip(1u));
177 EXPECT_TRUE(r.WriteU32NativeEndian(0x06070809u));
178 EXPECT_EQ(r.remaining(), 0u);
179 EXPECT_EQ(kArray, span<const uint8_t>({1, 9, 8, 7, 6}));
180 }
181 {
182 auto r = SpanWriter(span(kBigArray));
183 EXPECT_TRUE(r.Skip(1u));
184 EXPECT_TRUE(r.WriteU64NativeEndian(0x0203040506070809lu));
185 EXPECT_EQ(r.remaining(), 0u);
186 EXPECT_EQ(kBigArray, span<const uint8_t>({1, 9, 8, 7, 6, 5, 4, 3, 2}));
187 }
188 }
189
TEST(SpanWriterTest,WriteNativeEndian_Signed)190 TEST(SpanWriterTest, WriteNativeEndian_Signed) {
191 std::array<uint8_t, 5u> kArray = {1, 2, 3, 4, 5};
192 std::array<uint8_t, 9u> kBigArray = {1, 1, 1, 1, 1, 1, 1, 1, 1};
193
194 {
195 auto r = SpanWriter(span(kArray));
196 EXPECT_TRUE(r.Skip(1u));
197 EXPECT_TRUE(r.WriteI8NativeEndian(-0x09));
198 EXPECT_EQ(r.remaining(), 3u);
199 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf7, 3, 4, 5}));
200 }
201 {
202 auto r = SpanWriter(span(kArray));
203 EXPECT_TRUE(r.Skip(1u));
204 EXPECT_TRUE(r.WriteI16NativeEndian(-0x0809));
205 EXPECT_EQ(r.remaining(), 2u);
206 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf7, 0xf7, 4, 5}));
207 }
208 {
209 auto r = SpanWriter(span(kArray));
210 EXPECT_TRUE(r.Skip(1u));
211 EXPECT_TRUE(r.WriteI32NativeEndian(-0x06070809));
212 EXPECT_EQ(r.remaining(), 0u);
213 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf7, 0xf7, 0xf8, 0xf9}));
214 }
215 {
216 auto r = SpanWriter(span(kBigArray));
217 EXPECT_TRUE(r.Skip(1u));
218 EXPECT_TRUE(r.WriteI64NativeEndian(-0x0203040506070809l));
219 EXPECT_EQ(r.remaining(), 0u);
220 EXPECT_EQ(kBigArray, span<const uint8_t>({1, 0xf7, 0xf7, 0xf8, 0xf9, 0xfa,
221 0xfb, 0xfc, 0xfd}));
222 }
223 }
224
TEST(SpanWriterTest,WriteLittleEndian_Unsigned)225 TEST(SpanWriterTest, WriteLittleEndian_Unsigned) {
226 std::array<uint8_t, 5u> kArray = {1, 2, 3, 4, 5};
227 std::array<uint8_t, 9u> kBigArray = {1, 1, 1, 1, 1, 1, 1, 1, 1};
228
229 {
230 auto r = SpanWriter(span(kArray));
231 EXPECT_TRUE(r.Skip(1u));
232 EXPECT_TRUE(r.WriteU8LittleEndian(0x09));
233 EXPECT_EQ(r.remaining(), 3u);
234 EXPECT_EQ(kArray, span<const uint8_t>({1, 9, 3, 4, 5}));
235 }
236 {
237 auto r = SpanWriter(span(kArray));
238 EXPECT_TRUE(r.Skip(1u));
239 EXPECT_TRUE(r.WriteU16LittleEndian(0x0809));
240 EXPECT_EQ(r.remaining(), 2u);
241 EXPECT_EQ(kArray, span<const uint8_t>({1, 9, 8, 4, 5}));
242 }
243 {
244 auto r = SpanWriter(span(kArray));
245 EXPECT_TRUE(r.Skip(1u));
246 EXPECT_TRUE(r.WriteU32LittleEndian(0x06070809u));
247 EXPECT_EQ(r.remaining(), 0u);
248 EXPECT_EQ(kArray, span<const uint8_t>({1, 9, 8, 7, 6}));
249 }
250 {
251 auto r = SpanWriter(span(kBigArray));
252 EXPECT_TRUE(r.Skip(1u));
253 EXPECT_TRUE(r.WriteU64LittleEndian(0x0203040506070809lu));
254 EXPECT_EQ(r.remaining(), 0u);
255 EXPECT_EQ(kBigArray, span<const uint8_t>({1, 9, 8, 7, 6, 5, 4, 3, 2}));
256 }
257 }
258
TEST(SpanWriterTest,WriteLittleEndian_Signed)259 TEST(SpanWriterTest, WriteLittleEndian_Signed) {
260 std::array<uint8_t, 5u> kArray = {1, 2, 3, 4, 5};
261 std::array<uint8_t, 9u> kBigArray = {1, 1, 1, 1, 1, 1, 1, 1, 1};
262
263 {
264 auto r = SpanWriter(span(kArray));
265 EXPECT_TRUE(r.Skip(1u));
266 EXPECT_TRUE(r.WriteI8LittleEndian(-0x09));
267 EXPECT_EQ(r.remaining(), 3u);
268 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf7, 3, 4, 5}));
269 }
270 {
271 auto r = SpanWriter(span(kArray));
272 EXPECT_TRUE(r.Skip(1u));
273 EXPECT_TRUE(r.WriteI16LittleEndian(-0x0809));
274 EXPECT_EQ(r.remaining(), 2u);
275 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf7, 0xf7, 4, 5}));
276 }
277 {
278 auto r = SpanWriter(span(kArray));
279 EXPECT_TRUE(r.Skip(1u));
280 EXPECT_TRUE(r.WriteI32LittleEndian(-0x06070809));
281 EXPECT_EQ(r.remaining(), 0u);
282 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf7, 0xf7, 0xf8, 0xf9}));
283 }
284 {
285 auto r = SpanWriter(span(kBigArray));
286 EXPECT_TRUE(r.Skip(1u));
287 EXPECT_TRUE(r.WriteI64LittleEndian(-0x0203040506070809l));
288 EXPECT_EQ(r.remaining(), 0u);
289 EXPECT_EQ(kBigArray, span<const uint8_t>({1, 0xf7, 0xf7, 0xf8, 0xf9, 0xfa,
290 0xfb, 0xfc, 0xfd}));
291 }
292 }
293
TEST(SpanWriterTest,WriteBigEndian_Unsigned)294 TEST(SpanWriterTest, WriteBigEndian_Unsigned) {
295 std::array<uint8_t, 5u> kArray = {1, 2, 3, 4, 5};
296 std::array<uint8_t, 9u> kBigArray = {1, 1, 1, 1, 1, 1, 1, 1, 1};
297
298 {
299 auto r = SpanWriter(span(kArray));
300 EXPECT_TRUE(r.Skip(1u));
301 EXPECT_TRUE(r.WriteU8BigEndian(0x09));
302 EXPECT_EQ(r.remaining(), 3u);
303 EXPECT_EQ(kArray, span<const uint8_t>({1, 9, 3, 4, 5}));
304 }
305 {
306 auto r = SpanWriter(span(kArray));
307 EXPECT_TRUE(r.Skip(1u));
308 EXPECT_TRUE(r.WriteU16BigEndian(0x0809));
309 EXPECT_EQ(r.remaining(), 2u);
310 EXPECT_EQ(kArray, span<const uint8_t>({1, 8, 9, 4, 5}));
311 }
312 {
313 auto r = SpanWriter(span(kArray));
314 EXPECT_TRUE(r.Skip(1u));
315 EXPECT_TRUE(r.WriteU32BigEndian(0x06070809u));
316 EXPECT_EQ(r.remaining(), 0u);
317 EXPECT_EQ(kArray, span<const uint8_t>({1, 6, 7, 8, 9}));
318 }
319 {
320 auto r = SpanWriter(span(kBigArray));
321 EXPECT_TRUE(r.Skip(1u));
322 EXPECT_TRUE(r.WriteU64BigEndian(0x0203040506070809lu));
323 EXPECT_EQ(r.remaining(), 0u);
324 EXPECT_EQ(kBigArray, span<const uint8_t>({1, 2, 3, 4, 5, 6, 7, 8, 9}));
325 }
326 }
327
TEST(SpanWriterTest,WriteBigEndian_Signed)328 TEST(SpanWriterTest, WriteBigEndian_Signed) {
329 std::array<uint8_t, 5u> kArray = {1, 2, 3, 4, 5};
330 std::array<uint8_t, 9u> kBigArray = {1, 1, 1, 1, 1, 1, 1, 1, 1};
331
332 {
333 auto r = SpanWriter(span(kArray));
334 EXPECT_TRUE(r.Skip(1u));
335 EXPECT_TRUE(r.WriteI8BigEndian(-0x09));
336 EXPECT_EQ(r.remaining(), 3u);
337 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf7, 3, 4, 5}));
338 }
339 {
340 auto r = SpanWriter(span(kArray));
341 EXPECT_TRUE(r.Skip(1u));
342 EXPECT_TRUE(r.WriteI16BigEndian(-0x0809));
343 EXPECT_EQ(r.remaining(), 2u);
344 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf7, 0xf7, 4, 5}));
345 }
346 {
347 auto r = SpanWriter(span(kArray));
348 EXPECT_TRUE(r.Skip(1u));
349 EXPECT_TRUE(r.WriteI32BigEndian(-0x06070809));
350 EXPECT_EQ(r.remaining(), 0u);
351 EXPECT_EQ(kArray, span<const uint8_t>({1, 0xf9, 0xf8, 0xf7, 0xf7}));
352 }
353 {
354 auto r = SpanWriter(span(kBigArray));
355 EXPECT_TRUE(r.Skip(1u));
356 EXPECT_TRUE(r.WriteI64BigEndian(-0x0203040506070809l));
357 EXPECT_EQ(r.remaining(), 0u);
358 EXPECT_EQ(kBigArray, span<const uint8_t>({1, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9,
359 0xf8, 0xf7, 0xf7}));
360 }
361 }
362
TEST(SpanWriterTest,Chars)363 TEST(SpanWriterTest, Chars) {
364 std::array<char, 5u> kArray = {'a', 'b', 'c', 'd', 'e'};
365
366 auto r = SpanWriter(span(kArray));
367 EXPECT_TRUE(r.Skip(1u));
368 EXPECT_TRUE(r.Write(span<const char>({'f', 'g'})));
369 EXPECT_EQ(r.remaining(), 2u);
370 EXPECT_EQ(kArray, span<const char>({'a', 'f', 'g', 'd', 'e'}));
371 }
372
373 } // namespace
374 } // namespace base
375