949 lines · cpp
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-exception6//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(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, Size))37 return EC;38 uint64_t S = startIndex(Offset);39 auto Ref = Data.drop_front(S);40 if (Ref.size() >= Size) {41 Buffer = Ref.take_front(Size);42 return Error::success();43 }44 45 uint64_t BytesLeft = Size - Ref.size();46 uint8_t *Ptr = Allocator.Allocate<uint8_t>(Size);47 ::memcpy(Ptr, Ref.data(), Ref.size());48 ::memcpy(Ptr + Ref.size(), Data.data(), 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, 1))56 return EC;57 uint64_t S = startIndex(Offset);58 Buffer = Data.drop_front(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, 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(S);73 if (Ref.size() >= SrcData.size()) {74 ::memcpy(Ref.data(), SrcData.data(), SrcData.size());75 return Error::success();76 }77 78 uint64_t BytesLeft = SrcData.size() - Ref.size();79 ::memcpy(Ref.data(), SrcData.data(), Ref.size());80 ::memcpy(&Data[0], SrcData.data() + Ref.size(), 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() = default;114 115 void SetUp() override {116 Streams.clear();117 Streams.resize(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(InputData.size());136 if (!Input.empty()) {137 uint64_t PartitionIndex = alignDown(InputData.size() / 2, Align);138 uint64_t RightBytes = InputData.size() - PartitionIndex;139 uint64_t LeftBytes = PartitionIndex;140 if (RightBytes > 0)141 ::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes);142 if (LeftBytes > 0)143 ::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes);144 }145 146 for (uint32_t I = 0; I < NumEndians; ++I) {147 auto InByteStream =148 std::make_unique<BinaryByteStream>(InputData, Endians[I]);149 auto InBrokenStream = std::make_unique<BrokenStream>(150 BrokenInputData, Endians[I], 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(Size);159 BrokenOutputData.resize(Size);160 161 for (uint32_t I = 0; I < NumEndians; ++I) {162 Streams[I * 2].Output =163 std::make_unique<MutableBinaryByteStream>(OutputData, Endians[I]);164 Streams[I * 2 + 1].Output = std::make_unique<BrokenStream>(165 BrokenOutputData, Endians[I], 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>(InputData, Endians[I]);173 Streams[I * 2 + 1].Output = std::make_unique<BrokenStream>(174 BrokenInputData, Endians[I], 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>(OutputData, Endians[I]);182 Streams[I * 2 + 1].Input = std::make_unique<BrokenStream>(183 BrokenOutputData, Endians[I], 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(InputData, 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(InputData, 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 work225 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 else234 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 reading241 // 1 byte from offset 3.242 Ref = Ref.drop_front(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 else247 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 else254 EXPECT_FALSE(Buffer.empty());255 256 // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as257 // reading 2 bytes from offset 4, and should fail.258 Ref = Ref.drop_front(1);259 EXPECT_THAT_ERROR(Ref.readBytes(2, 2, Buffer), Failed());260 261 // But if we read the longest contiguous chunk instead, we should still262 // 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 an278 // 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 to284 // 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 as294 // the295 // underlying stream grows.296 BinaryStreamRef Dropped = ConstRef.drop_front(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 the304 // length.305 Dropped = Dropped.drop_back(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 the311 // length.312 Dropped = Dropped.drop_back(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(InputData, 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(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(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(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(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(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(InputData, 1);361 initializeOutput(InputData.size(), 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 one368 // 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 corresponding383 // 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(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, now410 // 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(IntBytes, 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(PairBytes, 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(StringBytes, 1);467 468 struct StringExtractor {469 public:470 Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) {471 if (Index == 0)472 Len = strlen("1. Test");473 else if (Index == 1)474 Len = strlen("2. Longer Test");475 else if (Index == 2)476 Len = strlen("3. Really Long Test");477 else478 Len = strlen("4. Super Extra Longest Test Of All");479 ArrayRef<uint8_t> Bytes;480 if (auto EC = Stream.readBytes(0, Len, 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(Bytes, 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(5);514 initializeInput(Bytes, 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, alignof(support::ulittle64_t));534 initializeInputFromOutput(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 integers569 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(IntBytes, 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(Enums.size() * sizeof(MyEnum), alignof(MyEnum));595 initializeInputFromOutput(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, // Zero617 0x7F, // One byte618 0xFF, // One byte, all-ones619 0xAAAA, // Two bytes620 0xAAAAAAAA, // Four bytes621 0xAAAAAAAAAAAAAAAA, // Eight bytes622 0xffffffffffffffff // Eight bytess, all-ones623 };624 625 // Conservatively assume a 10-byte encoding for each of our LEB128s, with no626 // alignment requirement.627 initializeOutput(10 * TestValues.size(), 1);628 initializeInputFromOutput(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(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, // Zero651 0x7F, // One byte652 -0x7F, // One byte, negative653 0xFF, // One byte, all-ones654 0xAAAA, // Two bytes655 -0xAAAA, // Two bytes, negative656 0xAAAAAAAA, // Four bytes657 -0xAAAAAAAA, // Four bytes, negative658 0x2AAAAAAAAAAAAAAA, // Eight bytes659 -0x7ffffffffffffff // Eight bytess, negative660 };661 662 // Conservatively assume a 10-byte encoding for each of our LEB128s, with no663 // alignment requirement.664 initializeOutput(10 * TestValues.size(), 1);665 initializeInputFromOutput(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(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({-42, 42.42, 42});698 Foos.push_back({100, 3.1415, static_cast<char>(-89)});699 Foos.push_back({200, 2.718, static_cast<char>(-12) });700 701 const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]);702 703 initializeInput(ArrayRef(Bytes, 3 * sizeof(Foo)), 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(Bytes, 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(5, 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 full776 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 integers787 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(SourceBytes, alignof(int));792 initializeOutputFromInput(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(Length, 1);818 initializeInputFromOutput(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(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 corner837 // cases by making sure that the stream is allowed to grow and that838 // 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: 0845 EXPECT_THAT_ERROR(Writer.padToAlignment(111), Succeeded());846 // Offset 111: '*'847 EXPECT_THAT_ERROR(Writer.writeInteger('*'), Succeeded());848 // Offset 112..120: 0849 EXPECT_THAT_ERROR(Writer.padToAlignment(11), Succeeded());850 851 BinaryStreamReader Reader(Stream);852 char c;853 // Offset 0854 EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded());855 EXPECT_EQ('0', c);856 // Offset 1..110857 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 111863 EXPECT_THAT_ERROR(Reader.readInteger<char>(c), Succeeded());864 EXPECT_EQ('*', c);865 // Offset 112..120866 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 = {{1, 1.0}, {2, 2.0}, {3, 3.0}};924 BumpPtrAllocator Allocator;925 for (const auto &F : Foos) {926 uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(sizeof(Foo),927 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(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 namespace949