1//===- llvm/unittest/Support/BinaryStreamTest.cpp -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Support/Allocator.h"
10#include "llvm/Support/BinaryByteStream.h"
11#include "llvm/Support/BinaryItemStream.h"
12#include "llvm/Support/BinaryStreamArray.h"
13#include "llvm/Support/BinaryStreamReader.h"
14#include "llvm/Support/BinaryStreamRef.h"
15#include "llvm/Support/BinaryStreamWriter.h"
16#include "llvm/Testing/Support/Error.h"
17
18#include "gtest/gtest.h"
19
20
21using namespace llvm;
22using namespace llvm::support;
23
24namespace {
25
26class BrokenStream : public WritableBinaryStream {
27public:
28 BrokenStream(MutableArrayRef<uint8_t> Data, endianness Endian, uint32_t Align)
29 : Data(Data), PartitionIndex(alignDown(Value: Data.size() / 2, Align)),
30 Endian(Endian) {}
31
32 endianness getEndian() const override { return Endian; }
33
34 Error readBytes(uint64_t Offset, uint64_t Size,
35 ArrayRef<uint8_t> &Buffer) override {
36 if (auto EC = checkOffsetForRead(Offset, DataSize: Size))
37 return EC;
38 uint64_t S = startIndex(Offset);
39 auto Ref = Data.drop_front(N: S);
40 if (Ref.size() >= Size) {
41 Buffer = Ref.take_front(N: Size);
42 return Error::success();
43 }
44
45 uint64_t BytesLeft = Size - Ref.size();
46 uint8_t *Ptr = Allocator.Allocate<uint8_t>(Num: Size);
47 ::memcpy(dest: Ptr, src: Ref.data(), n: Ref.size());
48 ::memcpy(dest: Ptr + Ref.size(), src: Data.data(), n: BytesLeft);
49 Buffer = ArrayRef<uint8_t>(Ptr, Size);
50 return Error::success();
51 }
52
53 Error readLongestContiguousChunk(uint64_t Offset,
54 ArrayRef<uint8_t> &Buffer) override {
55 if (auto EC = checkOffsetForRead(Offset, DataSize: 1))
56 return EC;
57 uint64_t S = startIndex(Offset);
58 Buffer = Data.drop_front(N: S);
59 return Error::success();
60 }
61
62 uint64_t getLength() override { return Data.size(); }
63
64 Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> SrcData) override {
65 if (auto EC = checkOffsetForWrite(Offset, DataSize: SrcData.size()))
66 return EC;
67 if (SrcData.empty())
68 return Error::success();
69
70 uint64_t S = startIndex(Offset);
71 MutableArrayRef<uint8_t> Ref(Data);
72 Ref = Ref.drop_front(N: S);
73 if (Ref.size() >= SrcData.size()) {
74 ::memcpy(dest: Ref.data(), src: SrcData.data(), n: SrcData.size());
75 return Error::success();
76 }
77
78 uint64_t BytesLeft = SrcData.size() - Ref.size();
79 ::memcpy(dest: Ref.data(), src: SrcData.data(), n: Ref.size());
80 ::memcpy(dest: &Data[0], src: SrcData.data() + Ref.size(), n: BytesLeft);
81 return Error::success();
82 }
83 Error commit() override { return Error::success(); }
84
85private:
86 uint64_t startIndex(uint64_t Offset) const {
87 return (Offset + PartitionIndex) % Data.size();
88 }
89
90 uint64_t endIndex(uint64_t Offset, uint64_t Size) const {
91 return (startIndex(Offset) + Size - 1) % Data.size();
92 }
93
94 // Buffer is organized like this:
95 // -------------------------------------------------
96 // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N/2-1 |
97 // -------------------------------------------------
98 // So reads from the beginning actually come from the middle.
99 MutableArrayRef<uint8_t> Data;
100 uint32_t PartitionIndex = 0;
101 endianness Endian;
102 BumpPtrAllocator Allocator;
103};
104
105constexpr llvm::endianness Endians[] = {
106 llvm::endianness::big, llvm::endianness::little, llvm::endianness::native};
107constexpr uint32_t NumEndians = std::size(Endians);
108constexpr uint32_t NumStreams = 2 * NumEndians;
109
110class BinaryStreamTest : public testing::Test {
111
112public:
113 BinaryStreamTest() {}
114
115 void SetUp() override {
116 Streams.clear();
117 Streams.resize(new_size: NumStreams);
118 for (uint32_t I = 0; I < NumStreams; ++I)
119 Streams[I].IsContiguous = (I % 2 == 0);
120
121 InputData.clear();
122 OutputData.clear();
123 }
124
125protected:
126 struct StreamPair {
127 bool IsContiguous;
128 std::unique_ptr<BinaryStream> Input;
129 std::unique_ptr<WritableBinaryStream> Output;
130 };
131
132 void initializeInput(ArrayRef<uint8_t> Input, uint32_t Align) {
133 InputData = Input;
134
135 BrokenInputData.resize(new_size: InputData.size());
136 if (!Input.empty()) {
137 uint64_t PartitionIndex = alignDown(Value: InputData.size() / 2, Align);
138 uint64_t RightBytes = InputData.size() - PartitionIndex;
139 uint64_t LeftBytes = PartitionIndex;
140 if (RightBytes > 0)
141 ::memcpy(dest: &BrokenInputData[PartitionIndex], src: Input.data(), n: RightBytes);
142 if (LeftBytes > 0)
143 ::memcpy(dest: &BrokenInputData[0], src: Input.data() + RightBytes, n: LeftBytes);
144 }
145
146 for (uint32_t I = 0; I < NumEndians; ++I) {
147 auto InByteStream =
148 std::make_unique<BinaryByteStream>(args&: InputData, args: Endians[I]);
149 auto InBrokenStream = std::make_unique<BrokenStream>(
150 args&: BrokenInputData, args: Endians[I], args&: Align);
151
152 Streams[I * 2].Input = std::move(InByteStream);
153 Streams[I * 2 + 1].Input = std::move(InBrokenStream);
154 }
155 }
156
157 void initializeOutput(uint64_t Size, uint32_t Align) {
158 OutputData.resize(new_size: Size);
159 BrokenOutputData.resize(new_size: Size);
160
161 for (uint32_t I = 0; I < NumEndians; ++I) {
162 Streams[I * 2].Output =
163 std::make_unique<MutableBinaryByteStream>(args&: OutputData, args: Endians[I]);
164 Streams[I * 2 + 1].Output = std::make_unique<BrokenStream>(
165 args&: BrokenOutputData, args: Endians[I], args&: Align);
166 }
167 }
168
169 void initializeOutputFromInput(uint32_t Align) {
170 for (uint32_t I = 0; I < NumEndians; ++I) {
171 Streams[I * 2].Output =
172 std::make_unique<MutableBinaryByteStream>(args&: InputData, args: Endians[I]);
173 Streams[I * 2 + 1].Output = std::make_unique<BrokenStream>(
174 args&: BrokenInputData, args: Endians[I], args&: Align);
175 }
176 }
177
178 void initializeInputFromOutput(uint32_t Align) {
179 for (uint32_t I = 0; I < NumEndians; ++I) {
180 Streams[I * 2].Input =
181 std::make_unique<BinaryByteStream>(args&: OutputData, args: Endians[I]);
182 Streams[I * 2 + 1].Input = std::make_unique<BrokenStream>(
183 args&: BrokenOutputData, args: Endians[I], args&: Align);
184 }
185 }
186
187 std::vector<uint8_t> InputData;
188 std::vector<uint8_t> BrokenInputData;
189
190 std::vector<uint8_t> OutputData;
191 std::vector<uint8_t> BrokenOutputData;
192
193 std::vector<StreamPair> Streams;
194};
195
196// Tests that a we can read from a BinaryByteStream without a StreamReader.
197TEST_F(BinaryStreamTest, BinaryByteStreamBounds) {
198 std::vector<uint8_t> InputData = {1, 2, 3, 4, 5};
199 initializeInput(Input: InputData, Align: 1);
200
201 for (auto &Stream : Streams) {
202 ArrayRef<uint8_t> Buffer;
203
204 // 1. If the read fits it should work.
205 ASSERT_EQ(InputData.size(), Stream.Input->getLength());
206 ASSERT_THAT_ERROR(Stream.Input->readBytes(2, 1, Buffer), Succeeded());
207 EXPECT_EQ(ArrayRef(InputData).slice(2, 1), Buffer);
208 ASSERT_THAT_ERROR(Stream.Input->readBytes(0, 4, Buffer), Succeeded());
209 EXPECT_EQ(ArrayRef(InputData).slice(0, 4), Buffer);
210
211 // 2. Reading past the bounds of the input should fail.
212 EXPECT_THAT_ERROR(Stream.Input->readBytes(4, 2, Buffer), Failed());
213 }
214}
215
216TEST_F(BinaryStreamTest, StreamRefBounds) {
217 std::vector<uint8_t> InputData = {1, 2, 3, 4, 5};
218 initializeInput(Input: InputData, Align: 1);
219
220 for (const auto &Stream : Streams) {
221 ArrayRef<uint8_t> Buffer;
222 BinaryStreamRef Ref(*Stream.Input);
223
224 // Read 1 byte from offset 2 should work
225 ASSERT_EQ(InputData.size(), Ref.getLength());
226 ASSERT_THAT_ERROR(Ref.readBytes(2, 1, Buffer), Succeeded());
227 EXPECT_EQ(ArrayRef(InputData).slice(2, 1), Buffer);
228
229 // Reading everything from offset 2 on.
230 ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded());
231 if (Stream.IsContiguous)
232 EXPECT_EQ(ArrayRef(InputData).slice(2), Buffer);
233 else
234 EXPECT_FALSE(Buffer.empty());
235
236 // Reading 6 bytes from offset 0 is too big.
237 EXPECT_THAT_ERROR(Ref.readBytes(0, 6, Buffer), Failed());
238 EXPECT_THAT_ERROR(Ref.readLongestContiguousChunk(6, Buffer), Failed());
239
240 // Reading 1 byte from offset 2 after dropping 1 byte is the same as reading
241 // 1 byte from offset 3.
242 Ref = Ref.drop_front(N: 1);
243 ASSERT_THAT_ERROR(Ref.readBytes(2, 1, Buffer), Succeeded());
244 if (Stream.IsContiguous)
245 EXPECT_EQ(ArrayRef(InputData).slice(3, 1), Buffer);
246 else
247 EXPECT_FALSE(Buffer.empty());
248
249 // Reading everything from offset 2 on after dropping 1 byte.
250 ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded());
251 if (Stream.IsContiguous)
252 EXPECT_EQ(ArrayRef(InputData).slice(3), Buffer);
253 else
254 EXPECT_FALSE(Buffer.empty());
255
256 // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as
257 // reading 2 bytes from offset 4, and should fail.
258 Ref = Ref.drop_front(N: 1);
259 EXPECT_THAT_ERROR(Ref.readBytes(2, 2, Buffer), Failed());
260
261 // But if we read the longest contiguous chunk instead, we should still
262 // get the 1 byte at the end.
263 ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded());
264 EXPECT_EQ(ArrayRef(InputData).take_back(), Buffer);
265 }
266}
267
268TEST_F(BinaryStreamTest, StreamRefDynamicSize) {
269 StringRef Strings[] = {"1", "2", "3", "4"};
270 AppendingBinaryByteStream Stream(llvm::endianness::little);
271
272 BinaryStreamWriter Writer(Stream);
273 BinaryStreamReader Reader(Stream);
274 const uint8_t *Byte;
275 StringRef Str;
276
277 // When the stream is empty, it should report a 0 length and we should get an
278 // error trying to read even 1 byte from it.
279 BinaryStreamRef ConstRef(Stream);
280 EXPECT_EQ(0U, ConstRef.getLength());
281 EXPECT_THAT_ERROR(Reader.readObject(Byte), Failed());
282
283 // But if we write to it, its size should increase and we should be able to
284 // read not just a byte, but the string that was written.
285 EXPECT_THAT_ERROR(Writer.writeCString(Strings[0]), Succeeded());
286 EXPECT_EQ(2U, ConstRef.getLength());
287 EXPECT_THAT_ERROR(Reader.readObject(Byte), Succeeded());
288
289 Reader.setOffset(0);
290 EXPECT_THAT_ERROR(Reader.readCString(Str), Succeeded());
291 EXPECT_EQ(Str, Strings[0]);
292
293 // If we drop some bytes from the front, we should still track the length as
294 // the
295 // underlying stream grows.
296 BinaryStreamRef Dropped = ConstRef.drop_front(N: 1);
297 EXPECT_EQ(1U, Dropped.getLength());
298
299 EXPECT_THAT_ERROR(Writer.writeCString(Strings[1]), Succeeded());
300 EXPECT_EQ(4U, ConstRef.getLength());
301 EXPECT_EQ(3U, Dropped.getLength());
302
303 // If we drop zero bytes from the back, we should continue tracking the
304 // length.
305 Dropped = Dropped.drop_back(N: 0);
306 EXPECT_THAT_ERROR(Writer.writeCString(Strings[2]), Succeeded());
307 EXPECT_EQ(6U, ConstRef.getLength());
308 EXPECT_EQ(5U, Dropped.getLength());
309
310 // If we drop non-zero bytes from the back, we should stop tracking the
311 // length.
312 Dropped = Dropped.drop_back(N: 1);
313 EXPECT_THAT_ERROR(Writer.writeCString(Strings[3]), Succeeded());
314 EXPECT_EQ(8U, ConstRef.getLength());
315 EXPECT_EQ(4U, Dropped.getLength());
316}
317
318TEST_F(BinaryStreamTest, DropOperations) {
319 std::vector<uint8_t> InputData = {1, 2, 3, 4, 5, 4, 3, 2, 1};
320 auto RefData = ArrayRef(InputData);
321 initializeInput(Input: InputData, Align: 1);
322
323 ArrayRef<uint8_t> Result;
324 BinaryStreamRef Original(InputData, llvm::endianness::little);
325 ASSERT_EQ(InputData.size(), Original.getLength());
326
327 EXPECT_THAT_ERROR(Original.readBytes(0, InputData.size(), Result),
328 Succeeded());
329 EXPECT_EQ(RefData, Result);
330
331 auto Dropped = Original.drop_front(N: 2);
332 EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
333 Succeeded());
334 EXPECT_EQ(RefData.drop_front(2), Result);
335
336 Dropped = Original.drop_back(N: 2);
337 EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
338 Succeeded());
339 EXPECT_EQ(RefData.drop_back(2), Result);
340
341 Dropped = Original.keep_front(N: 2);
342 EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
343 Succeeded());
344 EXPECT_EQ(RefData.take_front(2), Result);
345
346 Dropped = Original.keep_back(N: 2);
347 EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
348 Succeeded());
349 EXPECT_EQ(RefData.take_back(2), Result);
350
351 Dropped = Original.drop_symmetric(N: 2);
352 EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
353 Succeeded());
354 EXPECT_EQ(RefData.drop_front(2).drop_back(2), Result);
355}
356
357// Test that we can write to a BinaryStream without a StreamWriter.
358TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) {
359 std::vector<uint8_t> InputData = {'T', 'e', 's', 't', '\0'};
360 initializeInput(Input: InputData, Align: 1);
361 initializeOutput(Size: InputData.size(), Align: 1);
362
363 // For every combination of input stream and output stream.
364 for (auto &Stream : Streams) {
365 ASSERT_EQ(InputData.size(), Stream.Input->getLength());
366
367 // 1. Try two reads that are supposed to work. One from offset 0, and one
368 // from the middle.
369 uint32_t Offsets[] = {0, 3};
370 for (auto Offset : Offsets) {
371 uint64_t ExpectedSize = Stream.Input->getLength() - Offset;
372
373 // Read everything from Offset until the end of the input data.
374 ArrayRef<uint8_t> Data;
375 ASSERT_THAT_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data),
376 Succeeded());
377 ASSERT_EQ(ExpectedSize, Data.size());
378
379 // Then write it to the destination.
380 ASSERT_THAT_ERROR(Stream.Output->writeBytes(0, Data), Succeeded());
381
382 // Then we read back what we wrote, it should match the corresponding
383 // slice of the original input data.
384 ArrayRef<uint8_t> Data2;
385 ASSERT_THAT_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2),
386 Succeeded());
387 EXPECT_EQ(ArrayRef(InputData).drop_front(Offset), Data2);
388 }
389
390 std::vector<uint8_t> BigData = {0, 1, 2, 3, 4};
391 // 2. If the write is too big, it should fail.
392 EXPECT_THAT_ERROR(Stream.Output->writeBytes(3, BigData), Failed());
393 }
394}
395
396TEST_F(BinaryStreamTest, AppendingStream) {
397 AppendingBinaryByteStream Stream(llvm::endianness::little);
398 EXPECT_EQ(0U, Stream.getLength());
399
400 std::vector<uint8_t> InputData = {'T', 'e', 's', 't', 'T', 'e', 's', 't'};
401 auto Test = ArrayRef(InputData).take_front(N: 4);
402 // Writing past the end of the stream is an error.
403 EXPECT_THAT_ERROR(Stream.writeBytes(4, Test), Failed());
404
405 // Writing exactly at the end of the stream is ok.
406 EXPECT_THAT_ERROR(Stream.writeBytes(0, Test), Succeeded());
407 EXPECT_EQ(Test, Stream.data());
408
409 // And now that the end of the stream is where we couldn't write before, now
410 // we can write.
411 EXPECT_THAT_ERROR(Stream.writeBytes(4, Test), Succeeded());
412 EXPECT_EQ(MutableArrayRef<uint8_t>(InputData), Stream.data());
413}
414
415// Test that FixedStreamArray works correctly.
416TEST_F(BinaryStreamTest, FixedStreamArray) {
417 std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823};
418 ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(Ints.data()),
419 Ints.size() * sizeof(uint32_t));
420
421 initializeInput(Input: IntBytes, Align: alignof(uint32_t));
422
423 for (auto &Stream : Streams) {
424 ASSERT_EQ(InputData.size(), Stream.Input->getLength());
425
426 FixedStreamArray<uint32_t> Array(*Stream.Input);
427 auto Iter = Array.begin();
428 ASSERT_EQ(Ints[0], *Iter++);
429 ASSERT_EQ(Ints[1], *Iter++);
430 ASSERT_EQ(Ints[2], *Iter++);
431 ASSERT_EQ(Ints[3], *Iter++);
432 ASSERT_EQ(Array.end(), Iter);
433 }
434}
435
436// Ensure FixedStreamArrayIterator::operator-> works.
437// Added for coverage of r302257.
438TEST_F(BinaryStreamTest, FixedStreamArrayIteratorArrow) {
439 std::vector<std::pair<uint32_t, uint32_t>> Pairs = {{867, 5309}, {555, 1212}};
440 ArrayRef<uint8_t> PairBytes(reinterpret_cast<uint8_t *>(Pairs.data()),
441 Pairs.size() * sizeof(Pairs[0]));
442
443 initializeInput(Input: PairBytes, Align: alignof(uint32_t));
444
445 for (auto &Stream : Streams) {
446 ASSERT_EQ(InputData.size(), Stream.Input->getLength());
447
448 const FixedStreamArray<std::pair<uint32_t, uint32_t>> Array(*Stream.Input);
449 auto Iter = Array.begin();
450 ASSERT_EQ(Pairs[0].first, Iter->first);
451 ASSERT_EQ(Pairs[0].second, Iter->second);
452 ++Iter;
453 ASSERT_EQ(Pairs[1].first, Iter->first);
454 ASSERT_EQ(Pairs[1].second, Iter->second);
455 ++Iter;
456 ASSERT_EQ(Array.end(), Iter);
457 }
458}
459
460// Test that VarStreamArray works correctly.
461TEST_F(BinaryStreamTest, VarStreamArray) {
462 StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super "
463 "Extra Longest Test Of All");
464 ArrayRef<uint8_t> StringBytes(
465 reinterpret_cast<const uint8_t *>(Strings.data()), Strings.size());
466 initializeInput(Input: StringBytes, Align: 1);
467
468 struct StringExtractor {
469 public:
470 Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) {
471 if (Index == 0)
472 Len = strlen(s: "1. Test");
473 else if (Index == 1)
474 Len = strlen(s: "2. Longer Test");
475 else if (Index == 2)
476 Len = strlen(s: "3. Really Long Test");
477 else
478 Len = strlen(s: "4. Super Extra Longest Test Of All");
479 ArrayRef<uint8_t> Bytes;
480 if (auto EC = Stream.readBytes(Offset: 0, Size: Len, Buffer&: Bytes))
481 return EC;
482 Item =
483 StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
484 ++Index;
485 return Error::success();
486 }
487
488 uint32_t Index = 0;
489 };
490
491 for (auto &Stream : Streams) {
492 VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input);
493 auto Iter = Array.begin();
494 ASSERT_EQ("1. Test", *Iter++);
495 ASSERT_EQ("2. Longer Test", *Iter++);
496 ASSERT_EQ("3. Really Long Test", *Iter++);
497 ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++);
498 ASSERT_EQ(Array.end(), Iter);
499 }
500}
501
502TEST_F(BinaryStreamTest, StreamReaderBounds) {
503 std::vector<uint8_t> Bytes;
504
505 initializeInput(Input: Bytes, Align: 1);
506 for (auto &Stream : Streams) {
507 StringRef S;
508 BinaryStreamReader Reader(*Stream.Input);
509 EXPECT_EQ(0U, Reader.bytesRemaining());
510 EXPECT_THAT_ERROR(Reader.readFixedString(S, 1), Failed());
511 }
512
513 Bytes.resize(new_size: 5);
514 initializeInput(Input: Bytes, Align: 1);
515 for (auto &Stream : Streams) {
516 StringRef S;
517 BinaryStreamReader Reader(*Stream.Input);
518 EXPECT_EQ(Bytes.size(), Reader.bytesRemaining());
519 EXPECT_THAT_ERROR(Reader.readFixedString(S, 5), Succeeded());
520 EXPECT_THAT_ERROR(Reader.readFixedString(S, 6), Failed());
521 }
522}
523
524TEST_F(BinaryStreamTest, StreamReaderIntegers) {
525 support::ulittle64_t Little{908234};
526 support::ubig32_t Big{28907823};
527 short NS = 2897;
528 int NI = -89723;
529 unsigned long NUL = 902309023UL;
530 constexpr uint32_t Size =
531 sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL);
532
533 initializeOutput(Size, Align: alignof(support::ulittle64_t));
534 initializeInputFromOutput(Align: alignof(support::ulittle64_t));
535
536 for (auto &Stream : Streams) {
537 BinaryStreamWriter Writer(*Stream.Output);
538 ASSERT_THAT_ERROR(Writer.writeObject(Little), Succeeded());
539 ASSERT_THAT_ERROR(Writer.writeObject(Big), Succeeded());
540 ASSERT_THAT_ERROR(Writer.writeInteger(NS), Succeeded());
541 ASSERT_THAT_ERROR(Writer.writeInteger(NI), Succeeded());
542 ASSERT_THAT_ERROR(Writer.writeInteger(NUL), Succeeded());
543
544 const support::ulittle64_t *Little2;
545 const support::ubig32_t *Big2;
546 short NS2;
547 int NI2;
548 unsigned long NUL2;
549
550 // 1. Reading fields individually.
551 BinaryStreamReader Reader(*Stream.Input);
552 ASSERT_THAT_ERROR(Reader.readObject(Little2), Succeeded());
553 ASSERT_THAT_ERROR(Reader.readObject(Big2), Succeeded());
554 ASSERT_THAT_ERROR(Reader.readInteger(NS2), Succeeded());
555 ASSERT_THAT_ERROR(Reader.readInteger(NI2), Succeeded());
556 ASSERT_THAT_ERROR(Reader.readInteger(NUL2), Succeeded());
557 ASSERT_EQ(0U, Reader.bytesRemaining());
558
559 EXPECT_EQ(Little, *Little2);
560 EXPECT_EQ(Big, *Big2);
561 EXPECT_EQ(NS, NS2);
562 EXPECT_EQ(NI, NI2);
563 EXPECT_EQ(NUL, NUL2);
564 }
565}
566
567TEST_F(BinaryStreamTest, StreamReaderIntegerArray) {
568 // 1. Arrays of integers
569 std::vector<int> Ints = {1, 2, 3, 4, 5};
570 ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]),
571 Ints.size() * sizeof(int));
572
573 initializeInput(Input: IntBytes, Align: alignof(int));
574 for (auto &Stream : Streams) {
575 BinaryStreamReader Reader(*Stream.Input);
576 ArrayRef<int> IntsRef;
577 ASSERT_THAT_ERROR(Reader.readArray(IntsRef, Ints.size()), Succeeded());
578 ASSERT_EQ(0U, Reader.bytesRemaining());
579 EXPECT_EQ(ArrayRef(Ints), IntsRef);
580
581 Reader.setOffset(0);
582 FixedStreamArray<int> FixedIntsRef;
583 ASSERT_THAT_ERROR(Reader.readArray(FixedIntsRef, Ints.size()), Succeeded());
584 ASSERT_EQ(0U, Reader.bytesRemaining());
585 ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end()));
586 }
587}
588
589TEST_F(BinaryStreamTest, StreamReaderEnum) {
590 enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 };
591
592 std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo};
593
594 initializeOutput(Size: Enums.size() * sizeof(MyEnum), Align: alignof(MyEnum));
595 initializeInputFromOutput(Align: alignof(MyEnum));
596 for (auto &Stream : Streams) {
597 BinaryStreamWriter Writer(*Stream.Output);
598 for (auto Value : Enums)
599 ASSERT_THAT_ERROR(Writer.writeEnum(Value), Succeeded());
600
601 BinaryStreamReader Reader(*Stream.Input);
602
603 FixedStreamArray<MyEnum> FSA;
604
605 for (size_t I = 0; I < Enums.size(); ++I) {
606 MyEnum Value;
607 ASSERT_THAT_ERROR(Reader.readEnum(Value), Succeeded());
608 EXPECT_EQ(Enums[I], Value);
609 }
610 ASSERT_EQ(0U, Reader.bytesRemaining());
611 }
612}
613
614TEST_F(BinaryStreamTest, StreamReaderULEB128) {
615 std::vector<uint64_t> TestValues = {
616 0, // Zero
617 0x7F, // One byte
618 0xFF, // One byte, all-ones
619 0xAAAA, // Two bytes
620 0xAAAAAAAA, // Four bytes
621 0xAAAAAAAAAAAAAAAA, // Eight bytes
622 0xffffffffffffffff // Eight bytess, all-ones
623 };
624
625 // Conservatively assume a 10-byte encoding for each of our LEB128s, with no
626 // alignment requirement.
627 initializeOutput(Size: 10 * TestValues.size(), Align: 1);
628 initializeInputFromOutput(Align: 1);
629
630 for (auto &Stream : Streams) {
631 // Write fields.
632 BinaryStreamWriter Writer(*Stream.Output);
633 for (const auto &Value : TestValues)
634 ASSERT_THAT_ERROR(Writer.writeULEB128(Value), Succeeded());
635
636 // Read fields.
637 BinaryStreamReader Reader(*Stream.Input);
638 std::vector<uint64_t> Results;
639 Results.resize(new_size: TestValues.size());
640 for (unsigned I = 0; I != TestValues.size(); ++I)
641 ASSERT_THAT_ERROR(Reader.readULEB128(Results[I]), Succeeded());
642
643 for (unsigned I = 0; I != TestValues.size(); ++I)
644 EXPECT_EQ(TestValues[I], Results[I]);
645 }
646}
647
648TEST_F(BinaryStreamTest, StreamReaderSLEB128) {
649 std::vector<int64_t> TestValues = {
650 0, // Zero
651 0x7F, // One byte
652 -0x7F, // One byte, negative
653 0xFF, // One byte, all-ones
654 0xAAAA, // Two bytes
655 -0xAAAA, // Two bytes, negative
656 0xAAAAAAAA, // Four bytes
657 -0xAAAAAAAA, // Four bytes, negative
658 0x2AAAAAAAAAAAAAAA, // Eight bytes
659 -0x7ffffffffffffff // Eight bytess, negative
660 };
661
662 // Conservatively assume a 10-byte encoding for each of our LEB128s, with no
663 // alignment requirement.
664 initializeOutput(Size: 10 * TestValues.size(), Align: 1);
665 initializeInputFromOutput(Align: 1);
666
667 for (auto &Stream : Streams) {
668 // Write fields.
669 BinaryStreamWriter Writer(*Stream.Output);
670 for (const auto &Value : TestValues)
671 ASSERT_THAT_ERROR(Writer.writeSLEB128(Value), Succeeded());
672
673 // Read fields.
674 BinaryStreamReader Reader(*Stream.Input);
675 std::vector<int64_t> Results;
676 Results.resize(new_size: TestValues.size());
677 for (unsigned I = 0; I != TestValues.size(); ++I)
678 ASSERT_THAT_ERROR(Reader.readSLEB128(Results[I]), Succeeded());
679
680 for (unsigned I = 0; I != TestValues.size(); ++I)
681 EXPECT_EQ(TestValues[I], Results[I]);
682 }
683}
684
685TEST_F(BinaryStreamTest, StreamReaderObject) {
686 struct Foo {
687 int X;
688 double Y;
689 char Z;
690
691 bool operator==(const Foo &Other) const {
692 return X == Other.X && Y == Other.Y && Z == Other.Z;
693 }
694 };
695
696 std::vector<Foo> Foos;
697 Foos.push_back(x: {.X: -42, .Y: 42.42, .Z: 42});
698 Foos.push_back(x: {.X: 100, .Y: 3.1415, .Z: static_cast<char>(-89)});
699 Foos.push_back(x: {.X: 200, .Y: 2.718, .Z: static_cast<char>(-12) });
700
701 const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]);
702
703 initializeInput(Input: ArrayRef(Bytes, 3 * sizeof(Foo)), Align: alignof(Foo));
704
705 for (auto &Stream : Streams) {
706 // 1. Reading object pointers.
707 BinaryStreamReader Reader(*Stream.Input);
708 const Foo *FPtrOut = nullptr;
709 const Foo *GPtrOut = nullptr;
710 const Foo *HPtrOut = nullptr;
711 ASSERT_THAT_ERROR(Reader.readObject(FPtrOut), Succeeded());
712 ASSERT_THAT_ERROR(Reader.readObject(GPtrOut), Succeeded());
713 ASSERT_THAT_ERROR(Reader.readObject(HPtrOut), Succeeded());
714 EXPECT_EQ(0U, Reader.bytesRemaining());
715 EXPECT_EQ(Foos[0], *FPtrOut);
716 EXPECT_EQ(Foos[1], *GPtrOut);
717 EXPECT_EQ(Foos[2], *HPtrOut);
718 }
719}
720
721TEST_F(BinaryStreamTest, StreamReaderStrings) {
722 std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o',
723 '\0', 'T', 'h', 'r', 'e', 'e', '\0',
724 'F', 'o', 'u', 'r', '\0'};
725 initializeInput(Input: Bytes, Align: 1);
726
727 for (auto &Stream : Streams) {
728 BinaryStreamReader Reader(*Stream.Input);
729
730 StringRef S1;
731 StringRef S2;
732 StringRef S3;
733 StringRef S4;
734 ASSERT_THAT_ERROR(Reader.readCString(S1), Succeeded());
735 ASSERT_THAT_ERROR(Reader.readCString(S2), Succeeded());
736 ASSERT_THAT_ERROR(Reader.readCString(S3), Succeeded());
737 ASSERT_THAT_ERROR(Reader.readCString(S4), Succeeded());
738 ASSERT_EQ(0U, Reader.bytesRemaining());
739
740 EXPECT_EQ("One", S1);
741 EXPECT_EQ("Two", S2);
742 EXPECT_EQ("Three", S3);
743 EXPECT_EQ("Four", S4);
744
745 S1 = S2 = S3 = S4 = "";
746 Reader.setOffset(0);
747 ASSERT_THAT_ERROR(Reader.readFixedString(S1, 3), Succeeded());
748 ASSERT_THAT_ERROR(Reader.skip(1), Succeeded());
749 ASSERT_THAT_ERROR(Reader.readFixedString(S2, 3), Succeeded());
750 ASSERT_THAT_ERROR(Reader.skip(1), Succeeded());
751 ASSERT_THAT_ERROR(Reader.readFixedString(S3, 5), Succeeded());
752 ASSERT_THAT_ERROR(Reader.skip(1), Succeeded());
753 ASSERT_THAT_ERROR(Reader.readFixedString(S4, 4), Succeeded());
754 ASSERT_THAT_ERROR(Reader.skip(1), Succeeded());
755 ASSERT_EQ(0U, Reader.bytesRemaining());
756
757 EXPECT_EQ("One", S1);
758 EXPECT_EQ("Two", S2);
759 EXPECT_EQ("Three", S3);
760 EXPECT_EQ("Four", S4);
761 }
762}
763
764TEST_F(BinaryStreamTest, StreamWriterBounds) {
765 initializeOutput(Size: 5, Align: 1);
766
767 for (auto &Stream : Streams) {
768 BinaryStreamWriter Writer(*Stream.Output);
769
770 // 1. Can write a string that exactly fills the buffer.
771 EXPECT_EQ(5U, Writer.bytesRemaining());
772 EXPECT_THAT_ERROR(Writer.writeFixedString("abcde"), Succeeded());
773 EXPECT_EQ(0U, Writer.bytesRemaining());
774
775 // 2. Can write an empty string even when you're full
776 EXPECT_THAT_ERROR(Writer.writeFixedString(""), Succeeded());
777 EXPECT_THAT_ERROR(Writer.writeFixedString("a"), Failed());
778
779 // 3. Can't write a string that is one character too long.
780 Writer.setOffset(0);
781 EXPECT_THAT_ERROR(Writer.writeFixedString("abcdef"), Failed());
782 }
783}
784
785TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) {
786 // 3. Arrays of integers
787 std::vector<int> SourceInts = {1, 2, 3, 4, 5};
788 ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]),
789 SourceInts.size() * sizeof(int));
790
791 initializeInput(Input: SourceBytes, Align: alignof(int));
792 initializeOutputFromInput(Align: alignof(int));
793
794 for (auto &Stream : Streams) {
795 BinaryStreamReader Reader(*Stream.Input);
796 BinaryStreamWriter Writer(*Stream.Output);
797 ArrayRef<int> Ints;
798 ArrayRef<int> Ints2;
799 // First read them, then write them, then read them back.
800 ASSERT_THAT_ERROR(Reader.readArray(Ints, SourceInts.size()), Succeeded());
801 ASSERT_THAT_ERROR(Writer.writeArray(Ints), Succeeded());
802
803 BinaryStreamReader ReaderBacker(*Stream.Output);
804 ASSERT_THAT_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size()),
805 Succeeded());
806
807 EXPECT_EQ(ArrayRef(SourceInts), Ints2);
808 }
809}
810
811TEST_F(BinaryStreamTest, StreamWriterStrings) {
812 StringRef Strings[] = {"First", "Second", "Third", "Fourth"};
813
814 size_t Length = 0;
815 for (auto S : Strings)
816 Length += S.size() + 1;
817 initializeOutput(Size: Length, Align: 1);
818 initializeInputFromOutput(Align: 1);
819
820 for (auto &Stream : Streams) {
821 BinaryStreamWriter Writer(*Stream.Output);
822 for (auto S : Strings)
823 ASSERT_THAT_ERROR(Writer.writeCString(S), Succeeded());
824 std::vector<StringRef> InStrings;
825 BinaryStreamReader Reader(*Stream.Input);
826 while (!Reader.empty()) {
827 StringRef S;
828 ASSERT_THAT_ERROR(Reader.readCString(S), Succeeded());
829 InStrings.push_back(x: S);
830 }
831 EXPECT_EQ(ArrayRef(Strings), ArrayRef(InStrings));
832 }
833}
834
835TEST_F(BinaryStreamTest, StreamWriterPadToAlignment) {
836 // This test may seem excessive but it is checking for past bugs and corner
837 // cases by making sure that the stream is allowed to grow and that
838 // both multiple pad chunks and single chunk extensions work.
839 AppendingBinaryByteStream Stream(llvm::endianness::little);
840 BinaryStreamWriter Writer(Stream);
841
842 // Offset 0: '0'
843 EXPECT_THAT_ERROR(Writer.writeInteger('0'), Succeeded());
844 // Offset 1..110: 0
845 EXPECT_THAT_ERROR(Writer.padToAlignment(111), Succeeded());
846 // Offset 111: '*'
847 EXPECT_THAT_ERROR(Writer.writeInteger('*'), Succeeded());
848 // Offset 112..120: 0
849 EXPECT_THAT_ERROR(Writer.padToAlignment(11), Succeeded());
850
851 BinaryStreamReader Reader(Stream);
852 char c;
853 // Offset 0
854 EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded());
855 EXPECT_EQ('0', c);
856 // Offset 1..110
857 for (int i = 0; i < 110; ++i) {
858 char c;
859 EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded());
860 EXPECT_EQ('\0', c);
861 }
862 // Offset 111
863 EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded());
864 EXPECT_EQ('*', c);
865 // Offset 112..120
866 for (int i = 0; i < 9; ++i) {
867 char c;
868 EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded());
869 EXPECT_EQ('\0', c);
870 }
871
872 // EOF.
873 EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Failed());
874}
875
876TEST_F(BinaryStreamTest, StreamWriterAppend) {
877 StringRef Strings[] = {"First", "Second", "Third", "Fourth"};
878 AppendingBinaryByteStream Stream(llvm::endianness::little);
879 BinaryStreamWriter Writer(Stream);
880
881 for (auto &Str : Strings) {
882 EXPECT_THAT_ERROR(Writer.writeCString(Str), Succeeded());
883 }
884
885 BinaryStreamReader Reader(Stream);
886 for (auto &Str : Strings) {
887 StringRef S;
888 EXPECT_THAT_ERROR(Reader.readCString(S), Succeeded());
889 EXPECT_EQ(Str, S);
890 }
891}
892}
893
894namespace {
895struct BinaryItemStreamObject {
896 explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {}
897
898 ArrayRef<uint8_t> Bytes;
899};
900}
901
902namespace llvm {
903template <> struct BinaryItemTraits<BinaryItemStreamObject> {
904 static size_t length(const BinaryItemStreamObject &Item) {
905 return Item.Bytes.size();
906 }
907
908 static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) {
909 return Item.Bytes;
910 }
911};
912}
913
914namespace {
915
916TEST_F(BinaryStreamTest, BinaryItemStream) {
917 std::vector<BinaryItemStreamObject> Objects;
918
919 struct Foo {
920 int X;
921 double Y;
922 };
923 std::vector<Foo> Foos = {{.X: 1, .Y: 1.0}, {.X: 2, .Y: 2.0}, {.X: 3, .Y: 3.0}};
924 BumpPtrAllocator Allocator;
925 for (const auto &F : Foos) {
926 uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(Size: sizeof(Foo),
927 Alignment: alignof(Foo)));
928 MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo));
929 MutableBinaryByteStream Stream(Buffer, llvm::endianness::big);
930 BinaryStreamWriter Writer(Stream);
931 ASSERT_THAT_ERROR(Writer.writeObject(F), Succeeded());
932 Objects.push_back(x: BinaryItemStreamObject(Buffer));
933 }
934
935 BinaryItemStream<BinaryItemStreamObject> ItemStream(llvm::endianness::big);
936 ItemStream.setItems(Objects);
937 BinaryStreamReader Reader(ItemStream);
938
939 for (const auto &F : Foos) {
940 const Foo *F2;
941 ASSERT_THAT_ERROR(Reader.readObject(F2), Succeeded());
942
943 EXPECT_EQ(F.X, F2->X);
944 EXPECT_DOUBLE_EQ(F.Y, F2->Y);
945 }
946}
947
948} // end anonymous namespace
949

source code of llvm/unittests/Support/BinaryStreamTest.cpp