Home | History | Annotate | Download | only in MSF
      1 //===- llvm/unittest/DebugInfo/MSF/MappedBlockStreamTest.cpp --------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
     11 #include "llvm/Support/BinaryByteStream.h"
     12 #include "llvm/Support/BinaryStreamReader.h"
     13 #include "llvm/Support/BinaryStreamRef.h"
     14 #include "llvm/Support/BinaryStreamWriter.h"
     15 #include "llvm/Testing/Support/Error.h"
     16 
     17 #include "gmock/gmock.h"
     18 #include "gtest/gtest.h"
     19 
     20 
     21 using namespace llvm;
     22 using namespace llvm::msf;
     23 using namespace llvm::support;
     24 
     25 namespace {
     26 
     27 static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9};
     28 static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'};
     29 
     30 class DiscontiguousStream : public WritableBinaryStream {
     31 public:
     32   DiscontiguousStream(ArrayRef<uint32_t> Blocks, MutableArrayRef<uint8_t> Data)
     33       : Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {}
     34 
     35   uint32_t block_size() const { return 1; }
     36   uint32_t block_count() const { return Blocks.size(); }
     37 
     38   endianness getEndian() const override { return little; }
     39 
     40   Error readBytes(uint32_t Offset, uint32_t Size,
     41                   ArrayRef<uint8_t> &Buffer) override {
     42     if (auto EC = checkOffsetForRead(Offset, Size))
     43       return EC;
     44     Buffer = Data.slice(Offset, Size);
     45     return Error::success();
     46   }
     47 
     48   Error readLongestContiguousChunk(uint32_t Offset,
     49                                    ArrayRef<uint8_t> &Buffer) override {
     50     if (auto EC = checkOffsetForRead(Offset, 1))
     51       return EC;
     52     Buffer = Data.drop_front(Offset);
     53     return Error::success();
     54   }
     55 
     56   uint32_t getLength() override { return Data.size(); }
     57 
     58   Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override {
     59     if (auto EC = checkOffsetForWrite(Offset, SrcData.size()))
     60       return EC;
     61     ::memcpy(&Data[Offset], SrcData.data(), SrcData.size());
     62     return Error::success();
     63   }
     64   Error commit() override { return Error::success(); }
     65 
     66   MSFStreamLayout layout() const {
     67     return MSFStreamLayout{static_cast<uint32_t>(Data.size()), Blocks};
     68   }
     69 
     70   BumpPtrAllocator Allocator;
     71 
     72 private:
     73   std::vector<support::ulittle32_t> Blocks;
     74   MutableArrayRef<uint8_t> Data;
     75 };
     76 
     77 TEST(MappedBlockStreamTest, NumBlocks) {
     78   DiscontiguousStream F(BlocksAry, DataAry);
     79   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
     80                                            F.Allocator);
     81   EXPECT_EQ(F.block_size(), S->getBlockSize());
     82   EXPECT_EQ(F.layout().Blocks.size(), S->getNumBlocks());
     83 }
     84 
     85 // Tests that a read which is entirely contained within a single block works
     86 // and does not allocate.
     87 TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) {
     88   DiscontiguousStream F(BlocksAry, DataAry);
     89   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
     90                                            F.Allocator);
     91 
     92   BinaryStreamReader R(*S);
     93   BinaryStreamRef SR;
     94   EXPECT_THAT_ERROR(R.readStreamRef(SR, 0U), Succeeded());
     95   ArrayRef<uint8_t> Buffer;
     96   EXPECT_THAT_ERROR(SR.readBytes(0U, 1U, Buffer), Failed());
     97   EXPECT_THAT_ERROR(R.readStreamRef(SR, 1U), Succeeded());
     98   EXPECT_THAT_ERROR(SR.readBytes(1U, 1U, Buffer), Failed());
     99 }
    100 
    101 // Tests that a read which outputs into a full destination buffer works and
    102 // does not fail due to the length of the output buffer.
    103 TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
    104   DiscontiguousStream F(BlocksAry, DataAry);
    105   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    106                                            F.Allocator);
    107 
    108   BinaryStreamReader R(*S);
    109   StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
    110   EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded());
    111   EXPECT_EQ(Str, StringRef("A"));
    112   EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
    113 }
    114 
    115 // Tests that a read which crosses a block boundary, but where the subsequent
    116 // blocks are still contiguous in memory to the previous block works and does
    117 // not allocate memory.
    118 TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
    119   DiscontiguousStream F(BlocksAry, DataAry);
    120   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    121                                            F.Allocator);
    122   BinaryStreamReader R(*S);
    123   StringRef Str;
    124   EXPECT_THAT_ERROR(R.readFixedString(Str, 2), Succeeded());
    125   EXPECT_EQ(Str, StringRef("AB"));
    126   EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
    127 
    128   R.setOffset(6);
    129   EXPECT_THAT_ERROR(R.readFixedString(Str, 4), Succeeded());
    130   EXPECT_EQ(Str, StringRef("GHIJ"));
    131   EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
    132 }
    133 
    134 // Tests that a read which crosses a block boundary and cannot be referenced
    135 // contiguously works and allocates only the precise amount of bytes
    136 // requested.
    137 TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
    138   DiscontiguousStream F(BlocksAry, DataAry);
    139   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    140                                            F.Allocator);
    141   BinaryStreamReader R(*S);
    142   StringRef Str;
    143   EXPECT_THAT_ERROR(R.readFixedString(Str, 10), Succeeded());
    144   EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
    145   EXPECT_EQ(10U, F.Allocator.getBytesAllocated());
    146 }
    147 
    148 // Test that an out of bounds read which doesn't cross a block boundary
    149 // fails and allocates no memory.
    150 TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
    151   DiscontiguousStream F(BlocksAry, DataAry);
    152   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    153                                            F.Allocator);
    154   BinaryStreamReader R(*S);
    155   StringRef Str;
    156 
    157   R.setOffset(10);
    158   EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Failed());
    159   EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
    160 }
    161 
    162 // Test that an out of bounds read which crosses a contiguous block boundary
    163 // fails and allocates no memory.
    164 TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
    165   DiscontiguousStream F(BlocksAry, DataAry);
    166   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    167                                            F.Allocator);
    168   BinaryStreamReader R(*S);
    169   StringRef Str;
    170 
    171   R.setOffset(6);
    172   EXPECT_THAT_ERROR(R.readFixedString(Str, 5), Failed());
    173   EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
    174 }
    175 
    176 // Test that an out of bounds read which crosses a discontiguous block
    177 // boundary fails and allocates no memory.
    178 TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
    179   DiscontiguousStream F(BlocksAry, DataAry);
    180   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    181                                            F.Allocator);
    182   BinaryStreamReader R(*S);
    183   StringRef Str;
    184 
    185   EXPECT_THAT_ERROR(R.readFixedString(Str, 11), Failed());
    186   EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
    187 }
    188 
    189 // Tests that a read which is entirely contained within a single block but
    190 // beyond the end of a StreamRef fails.
    191 TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
    192   DiscontiguousStream F(BlocksAry, DataAry);
    193   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    194                                            F.Allocator);
    195   BinaryStreamReader R(*S);
    196   StringRef Str;
    197   EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded());
    198   EXPECT_EQ(Str, StringRef("A"));
    199   EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
    200 }
    201 
    202 // Tests that a read which is not aligned on the same boundary as a previous
    203 // cached request, but which is known to overlap that request, shares the
    204 // previous allocation.
    205 TEST(MappedBlockStreamTest, UnalignedOverlappingRead) {
    206   DiscontiguousStream F(BlocksAry, DataAry);
    207   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    208                                            F.Allocator);
    209   BinaryStreamReader R(*S);
    210   StringRef Str1;
    211   StringRef Str2;
    212   EXPECT_THAT_ERROR(R.readFixedString(Str1, 7), Succeeded());
    213   EXPECT_EQ(Str1, StringRef("ABCDEFG"));
    214   EXPECT_EQ(7U, F.Allocator.getBytesAllocated());
    215 
    216   R.setOffset(2);
    217   EXPECT_THAT_ERROR(R.readFixedString(Str2, 3), Succeeded());
    218   EXPECT_EQ(Str2, StringRef("CDE"));
    219   EXPECT_EQ(Str1.data() + 2, Str2.data());
    220   EXPECT_EQ(7U, F.Allocator.getBytesAllocated());
    221 }
    222 
    223 // Tests that a read which is not aligned on the same boundary as a previous
    224 // cached request, but which only partially overlaps a previous cached request,
    225 // still works correctly and allocates again from the shared pool.
    226 TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) {
    227   DiscontiguousStream F(BlocksAry, DataAry);
    228   auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
    229                                            F.Allocator);
    230   BinaryStreamReader R(*S);
    231   StringRef Str1;
    232   StringRef Str2;
    233   EXPECT_THAT_ERROR(R.readFixedString(Str1, 6), Succeeded());
    234   EXPECT_EQ(Str1, StringRef("ABCDEF"));
    235   EXPECT_EQ(6U, F.Allocator.getBytesAllocated());
    236 
    237   R.setOffset(4);
    238   EXPECT_THAT_ERROR(R.readFixedString(Str2, 4), Succeeded());
    239   EXPECT_EQ(Str2, StringRef("EFGH"));
    240   EXPECT_EQ(10U, F.Allocator.getBytesAllocated());
    241 }
    242 
    243 TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) {
    244   static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
    245   static uint8_t LargeBuffer[] = {'0', '1', '2', '3', '4', '5',
    246                                   '6', '7', '8', '9', 'A'};
    247   static uint8_t SmallBuffer[] = {'0', '1', '2'};
    248   static_assert(sizeof(LargeBuffer) > sizeof(Data),
    249                 "LargeBuffer is not big enough");
    250 
    251   DiscontiguousStream F(BlocksAry, Data);
    252   auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
    253                                                    F, F.Allocator);
    254   EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(LargeBuffer)), Failed());
    255   EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(SmallBuffer)),
    256                     Succeeded());
    257   EXPECT_THAT_ERROR(S->writeBytes(7, ArrayRef<uint8_t>(SmallBuffer)),
    258                     Succeeded());
    259   EXPECT_THAT_ERROR(S->writeBytes(8, ArrayRef<uint8_t>(SmallBuffer)), Failed());
    260 }
    261 
    262 TEST(MappedBlockStreamTest, TestWriteBytesNoBreakBoundary) {
    263   static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
    264   DiscontiguousStream F(BlocksAry, Data);
    265   auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
    266                                                    F, F.Allocator);
    267   ArrayRef<uint8_t> Buffer;
    268 
    269   EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
    270   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
    271   EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
    272   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
    273 
    274   EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('J')), Succeeded());
    275   EXPECT_THAT_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('A')), Succeeded());
    276 
    277   EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
    278   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
    279   EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
    280   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
    281 
    282   EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('A')), Succeeded());
    283   EXPECT_THAT_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('J')), Succeeded());
    284 
    285   EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
    286   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
    287   EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
    288   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
    289 }
    290 
    291 TEST(MappedBlockStreamTest, TestWriteBytesBreakBoundary) {
    292   static uint8_t Data[] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
    293   static uint8_t TestData[] = {'T', 'E', 'S', 'T', 'I', 'N', 'G', '.'};
    294   static uint8_t Expected[] = {'T', 'E', 'S', 'N', 'I',
    295                                'T', 'G', '.', '0', '0'};
    296 
    297   DiscontiguousStream F(BlocksAry, Data);
    298   auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
    299                                                    F, F.Allocator);
    300   ArrayRef<uint8_t> Buffer;
    301 
    302   EXPECT_THAT_ERROR(S->writeBytes(0, TestData), Succeeded());
    303   // First just compare the memory, then compare the result of reading the
    304   // string out.
    305   EXPECT_EQ(ArrayRef<uint8_t>(Data), ArrayRef<uint8_t>(Expected));
    306 
    307   EXPECT_THAT_ERROR(S->readBytes(0, 8, Buffer), Succeeded());
    308   EXPECT_EQ(Buffer, ArrayRef<uint8_t>(TestData));
    309 }
    310 
    311 TEST(MappedBlockStreamTest, TestWriteThenRead) {
    312   std::vector<uint8_t> DataBytes(10);
    313   MutableArrayRef<uint8_t> Data(DataBytes);
    314   const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
    315 
    316   DiscontiguousStream F(Blocks, Data);
    317   auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
    318                                                    F, F.Allocator);
    319 
    320   enum class MyEnum : uint32_t { Val1 = 2908234, Val2 = 120891234 };
    321   using support::ulittle32_t;
    322 
    323   uint16_t u16[] = {31468, 0};
    324   uint32_t u32[] = {890723408, 0};
    325   MyEnum Enum[] = {MyEnum::Val1, MyEnum::Val2};
    326   StringRef ZStr[] = {"Zero Str", ""};
    327   StringRef FStr[] = {"Fixed Str", ""};
    328   uint8_t byteArray0[] = {'1', '2'};
    329   uint8_t byteArray1[] = {'0', '0'};
    330   ArrayRef<uint8_t> byteArrayRef0(byteArray0);
    331   ArrayRef<uint8_t> byteArrayRef1(byteArray1);
    332   ArrayRef<uint8_t> byteArray[] = {byteArrayRef0, byteArrayRef1};
    333   uint32_t intArr0[] = {890723408, 29082234};
    334   uint32_t intArr1[] = {890723408, 29082234};
    335   ArrayRef<uint32_t> intArray[] = {intArr0, intArr1};
    336 
    337   BinaryStreamReader Reader(*S);
    338   BinaryStreamWriter Writer(*S);
    339   EXPECT_THAT_ERROR(Writer.writeInteger(u16[0]), Succeeded());
    340   EXPECT_THAT_ERROR(Reader.readInteger(u16[1]), Succeeded());
    341   EXPECT_EQ(u16[0], u16[1]);
    342   EXPECT_EQ(std::vector<uint8_t>({0, 0x7A, 0xEC, 0, 0, 0, 0, 0, 0, 0}),
    343             DataBytes);
    344 
    345   Reader.setOffset(0);
    346   Writer.setOffset(0);
    347   ::memset(DataBytes.data(), 0, 10);
    348   EXPECT_THAT_ERROR(Writer.writeInteger(u32[0]), Succeeded());
    349   EXPECT_THAT_ERROR(Reader.readInteger(u32[1]), Succeeded());
    350   EXPECT_EQ(u32[0], u32[1]);
    351   EXPECT_EQ(std::vector<uint8_t>({0x17, 0x5C, 0x50, 0, 0, 0, 0x35, 0, 0, 0}),
    352             DataBytes);
    353 
    354   Reader.setOffset(0);
    355   Writer.setOffset(0);
    356   ::memset(DataBytes.data(), 0, 10);
    357   EXPECT_THAT_ERROR(Writer.writeEnum(Enum[0]), Succeeded());
    358   EXPECT_THAT_ERROR(Reader.readEnum(Enum[1]), Succeeded());
    359   EXPECT_EQ(Enum[0], Enum[1]);
    360   EXPECT_EQ(std::vector<uint8_t>({0x2C, 0x60, 0x4A, 0, 0, 0, 0, 0, 0, 0}),
    361             DataBytes);
    362 
    363   Reader.setOffset(0);
    364   Writer.setOffset(0);
    365   ::memset(DataBytes.data(), 0, 10);
    366   EXPECT_THAT_ERROR(Writer.writeCString(ZStr[0]), Succeeded());
    367   EXPECT_THAT_ERROR(Reader.readCString(ZStr[1]), Succeeded());
    368   EXPECT_EQ(ZStr[0], ZStr[1]);
    369   EXPECT_EQ(
    370       std::vector<uint8_t>({'r', 'e', 'Z', ' ', 'S', 't', 'o', 'r', 0, 0}),
    371       DataBytes);
    372 
    373   Reader.setOffset(0);
    374   Writer.setOffset(0);
    375   ::memset(DataBytes.data(), 0, 10);
    376   EXPECT_THAT_ERROR(Writer.writeFixedString(FStr[0]), Succeeded());
    377   EXPECT_THAT_ERROR(Reader.readFixedString(FStr[1], FStr[0].size()),
    378                     Succeeded());
    379   EXPECT_EQ(FStr[0], FStr[1]);
    380   EXPECT_EQ(
    381       std::vector<uint8_t>({'x', 'i', 'F', 'd', ' ', 'S', 'e', 't', 0, 'r'}),
    382       DataBytes);
    383 
    384   Reader.setOffset(0);
    385   Writer.setOffset(0);
    386   ::memset(DataBytes.data(), 0, 10);
    387   EXPECT_THAT_ERROR(Writer.writeArray(byteArray[0]), Succeeded());
    388   EXPECT_THAT_ERROR(Reader.readArray(byteArray[1], byteArray[0].size()),
    389                     Succeeded());
    390   EXPECT_EQ(byteArray[0], byteArray[1]);
    391   EXPECT_EQ(std::vector<uint8_t>({0, 0x32, 0x31, 0, 0, 0, 0, 0, 0, 0}),
    392             DataBytes);
    393 
    394   Reader.setOffset(0);
    395   Writer.setOffset(0);
    396   ::memset(DataBytes.data(), 0, 10);
    397   EXPECT_THAT_ERROR(Writer.writeArray(intArray[0]), Succeeded());
    398   EXPECT_THAT_ERROR(Reader.readArray(intArray[1], intArray[0].size()),
    399                     Succeeded());
    400   EXPECT_EQ(intArray[0], intArray[1]);
    401 }
    402 
    403 TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) {
    404   std::vector<uint8_t> DestDataBytes(10);
    405   MutableArrayRef<uint8_t> DestData(DestDataBytes);
    406   const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
    407 
    408   std::vector<uint8_t> SrcDataBytes(10);
    409   MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
    410 
    411   DiscontiguousStream F(DestBlocks, DestData);
    412   auto DestStream = WritableMappedBlockStream::createStream(
    413       F.block_size(), F.layout(), F, F.Allocator);
    414 
    415   // First write "Test Str" into the source stream.
    416   MutableBinaryByteStream SourceStream(SrcData, little);
    417   BinaryStreamWriter SourceWriter(SourceStream);
    418   EXPECT_THAT_ERROR(SourceWriter.writeCString("Test Str"), Succeeded());
    419   EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
    420                               {'T', 'e', 's', 't', ' ', 'S', 't', 'r', 0, 0}));
    421 
    422   // Then write the source stream into the dest stream.
    423   BinaryStreamWriter DestWriter(*DestStream);
    424   EXPECT_THAT_ERROR(DestWriter.writeStreamRef(SourceStream), Succeeded());
    425   EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
    426                                {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
    427 
    428   // Then read the string back out of the dest stream.
    429   StringRef Result;
    430   BinaryStreamReader DestReader(*DestStream);
    431   EXPECT_THAT_ERROR(DestReader.readCString(Result), Succeeded());
    432   EXPECT_EQ(Result, "Test Str");
    433 }
    434 
    435 TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) {
    436   std::vector<uint8_t> DestDataBytes(10);
    437   MutableArrayRef<uint8_t> DestData(DestDataBytes);
    438   const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
    439 
    440   std::vector<uint8_t> SrcDataBytes(10);
    441   MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
    442   const uint32_t SrcBlocks[] = {1, 0, 6, 3, 4, 5, 2, 7, 8, 9};
    443 
    444   DiscontiguousStream DestF(DestBlocks, DestData);
    445   DiscontiguousStream SrcF(SrcBlocks, SrcData);
    446 
    447   auto Dest = WritableMappedBlockStream::createStream(
    448       DestF.block_size(), DestF.layout(), DestF, DestF.Allocator);
    449   auto Src = WritableMappedBlockStream::createStream(
    450       SrcF.block_size(), SrcF.layout(), SrcF, SrcF.Allocator);
    451 
    452   // First write "Test Str" into the source stream.
    453   BinaryStreamWriter SourceWriter(*Src);
    454   EXPECT_THAT_ERROR(SourceWriter.writeCString("Test Str"), Succeeded());
    455   EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
    456                               {'e', 'T', 't', 't', ' ', 'S', 's', 'r', 0, 0}));
    457 
    458   // Then write the source stream into the dest stream.
    459   BinaryStreamWriter DestWriter(*Dest);
    460   EXPECT_THAT_ERROR(DestWriter.writeStreamRef(*Src), Succeeded());
    461   EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
    462                                {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
    463 
    464   // Then read the string back out of the dest stream.
    465   StringRef Result;
    466   BinaryStreamReader DestReader(*Dest);
    467   EXPECT_THAT_ERROR(DestReader.readCString(Result), Succeeded());
    468   EXPECT_EQ(Result, "Test Str");
    469 }
    470 
    471 TEST(MappedBlockStreamTest, DataLivesAfterStreamDestruction) {
    472   std::vector<uint8_t> DataBytes(10);
    473   MutableArrayRef<uint8_t> Data(DataBytes);
    474   const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
    475 
    476   StringRef Str[] = {"Zero Str", ""};
    477 
    478   DiscontiguousStream F(Blocks, Data);
    479   {
    480     auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
    481                                                      F, F.Allocator);
    482 
    483     BinaryStreamReader Reader(*S);
    484     BinaryStreamWriter Writer(*S);
    485     ::memset(DataBytes.data(), 0, 10);
    486     EXPECT_THAT_ERROR(Writer.writeCString(Str[0]), Succeeded());
    487     EXPECT_THAT_ERROR(Reader.readCString(Str[1]), Succeeded());
    488     EXPECT_EQ(Str[0], Str[1]);
    489   }
    490 
    491   EXPECT_EQ(Str[0], Str[1]);
    492 }
    493 } // namespace
    494 
    495 MATCHER_P3(BlockIsFilledWith, Layout, BlockIndex, Byte, "succeeded") {
    496   uint64_t Offset = msf::blockToOffset(BlockIndex, Layout.SB->BlockSize);
    497   ArrayRef<uint8_t> BufferRef = makeArrayRef(arg);
    498   BufferRef = BufferRef.slice(Offset, Layout.SB->BlockSize);
    499   return llvm::all_of(BufferRef, [this](uint8_t B) { return B == Byte; });
    500 }
    501 
    502 namespace {
    503 TEST(MappedBlockStreamTest, CreateFpmStream) {
    504   BumpPtrAllocator Allocator;
    505   SuperBlock SB;
    506   MSFLayout L;
    507   L.SB = &SB;
    508 
    509   SB.FreeBlockMapBlock = 1;
    510   SB.BlockSize = 4096;
    511 
    512   constexpr uint32_t NumFileBlocks = 4096 * 4;
    513 
    514   std::vector<uint8_t> MsfBuffer(NumFileBlocks * SB.BlockSize);
    515   MutableBinaryByteStream MsfStream(MsfBuffer, llvm::support::little);
    516 
    517   SB.NumBlocks = NumFileBlocks;
    518   auto FpmStream =
    519       WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator);
    520   // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
    521   // blocks.  This translates to 1 FPM block.
    522   EXPECT_EQ(2048u, FpmStream->getLength());
    523   EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
    524   EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks[0]);
    525   // All blocks from FPM1 should be 1 initialized, and all blocks from FPM2
    526   // should be 0 initialized (since we requested the main FPM, not the alt FPM)
    527   for (int I = 0; I < 4; ++I) {
    528     EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0xFF));
    529     EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0));
    530   }
    531 
    532   ::memset(MsfBuffer.data(), 0, MsfBuffer.size());
    533   FpmStream =
    534       WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator, true);
    535   // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
    536   // blocks.  This translates to 1 FPM block.
    537   EXPECT_EQ(2048u, FpmStream->getLength());
    538   EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
    539   EXPECT_EQ(2u, FpmStream->getStreamLayout().Blocks[0]);
    540   // All blocks from FPM2 should be 1 initialized, and all blocks from FPM1
    541   // should be 0 initialized (since we requested the alt FPM, not the main FPM)
    542   for (int I = 0; I < 4; ++I) {
    543     EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0));
    544     EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0xFF));
    545   }
    546 }
    547 
    548 } // end anonymous namespace
    549