Home | History | Annotate | Download | only in PDB
      1 //===- llvm/unittest/DebugInfo/PDB/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 <unordered_map>
     11 
     12 #include "llvm/DebugInfo/CodeView/ByteStream.h"
     13 #include "llvm/DebugInfo/CodeView/StreamReader.h"
     14 #include "llvm/DebugInfo/CodeView/StreamRef.h"
     15 #include "llvm/DebugInfo/CodeView/StreamWriter.h"
     16 #include "llvm/DebugInfo/PDB/Raw/IPDBFile.h"
     17 #include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h"
     18 #include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
     19 #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
     20 #include "gtest/gtest.h"
     21 
     22 using namespace llvm;
     23 using namespace llvm::codeview;
     24 using namespace llvm::pdb;
     25 
     26 namespace {
     27 
     28 #define EXPECT_NO_ERROR(Err)                                                   \
     29   {                                                                            \
     30     auto E = Err;                                                              \
     31     EXPECT_FALSE(static_cast<bool>(E));                                        \
     32     if (E)                                                                     \
     33       consumeError(std::move(E));                                              \
     34   }
     35 
     36 #define EXPECT_ERROR(Err)                                                      \
     37   {                                                                            \
     38     auto E = Err;                                                              \
     39     EXPECT_TRUE(static_cast<bool>(E));                                         \
     40     if (E)                                                                     \
     41       consumeError(std::move(E));                                              \
     42   }
     43 
     44 static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9};
     45 static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'};
     46 
     47 class DiscontiguousFile : public IPDBFile {
     48 public:
     49   DiscontiguousFile(ArrayRef<uint32_t> Blocks, MutableArrayRef<uint8_t> Data)
     50       : Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {}
     51 
     52   uint32_t getBlockSize() const override { return 1; }
     53   uint32_t getBlockCount() const override { return Blocks.size(); }
     54   uint32_t getNumStreams() const override { return 1; }
     55   uint32_t getStreamByteSize(uint32_t StreamIndex) const override {
     56     return getBlockCount() * getBlockSize();
     57   }
     58   ArrayRef<support::ulittle32_t>
     59   getStreamBlockList(uint32_t StreamIndex) const override {
     60     if (StreamIndex != 0)
     61       return ArrayRef<support::ulittle32_t>();
     62     return Blocks;
     63   }
     64   Expected<ArrayRef<uint8_t>> getBlockData(uint32_t BlockIndex,
     65                                            uint32_t NumBytes) const override {
     66     return ArrayRef<uint8_t>(&Data[BlockIndex], NumBytes);
     67   }
     68 
     69   Error setBlockData(uint32_t BlockIndex, uint32_t Offset,
     70                      ArrayRef<uint8_t> SrcData) const override {
     71     if (BlockIndex >= Blocks.size())
     72       return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
     73     if (Offset > getBlockSize() - SrcData.size())
     74       return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
     75     ::memcpy(&Data[BlockIndex] + Offset, SrcData.data(), SrcData.size());
     76     return Error::success();
     77   }
     78 
     79 private:
     80   std::vector<support::ulittle32_t> Blocks;
     81   MutableArrayRef<uint8_t> Data;
     82 };
     83 
     84 class MappedBlockStreamImpl : public MappedBlockStream {
     85 public:
     86   MappedBlockStreamImpl(std::unique_ptr<IPDBStreamData> Data,
     87                         const IPDBFile &File)
     88       : MappedBlockStream(std::move(Data), File) {}
     89 };
     90 
     91 // Tests that a read which is entirely contained within a single block works
     92 // and does not allocate.
     93 TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) {
     94   DiscontiguousFile F(BlocksAry, DataAry);
     95   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
     96   StreamReader R(S);
     97   StreamRef SR;
     98   EXPECT_NO_ERROR(R.readStreamRef(SR, 0U));
     99   ArrayRef<uint8_t> Buffer;
    100   EXPECT_ERROR(SR.readBytes(0U, 1U, Buffer));
    101   EXPECT_NO_ERROR(R.readStreamRef(SR, 1U));
    102   EXPECT_ERROR(SR.readBytes(1U, 1U, Buffer));
    103 }
    104 
    105 // Tests that a read which outputs into a full destination buffer works and
    106 // does not fail due to the length of the output buffer.
    107 TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
    108   DiscontiguousFile F(BlocksAry, DataAry);
    109   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    110   StreamReader R(S);
    111   StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
    112   EXPECT_NO_ERROR(R.readFixedString(Str, 1));
    113   EXPECT_EQ(Str, StringRef("A"));
    114   EXPECT_EQ(0U, S.getNumBytesCopied());
    115 }
    116 
    117 // Tests that a read which crosses a block boundary, but where the subsequent
    118 // blocks are still contiguous in memory to the previous block works and does
    119 // not allocate memory.
    120 TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
    121   DiscontiguousFile F(BlocksAry, DataAry);
    122   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    123   StreamReader R(S);
    124   StringRef Str;
    125   EXPECT_NO_ERROR(R.readFixedString(Str, 2));
    126   EXPECT_EQ(Str, StringRef("AB"));
    127   EXPECT_EQ(0U, S.getNumBytesCopied());
    128 
    129   R.setOffset(6);
    130   EXPECT_NO_ERROR(R.readFixedString(Str, 4));
    131   EXPECT_EQ(Str, StringRef("GHIJ"));
    132   EXPECT_EQ(0U, S.getNumBytesCopied());
    133 }
    134 
    135 // Tests that a read which crosses a block boundary and cannot be referenced
    136 // contiguously works and allocates only the precise amount of bytes
    137 // requested.
    138 TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
    139   DiscontiguousFile F(BlocksAry, DataAry);
    140   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    141   StreamReader R(S);
    142   StringRef Str;
    143   EXPECT_NO_ERROR(R.readFixedString(Str, 10));
    144   EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
    145   EXPECT_EQ(10U, S.getNumBytesCopied());
    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   DiscontiguousFile F(BlocksAry, DataAry);
    152   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    153   StreamReader R(S);
    154   StringRef Str;
    155 
    156   R.setOffset(10);
    157   EXPECT_ERROR(R.readFixedString(Str, 1));
    158   EXPECT_EQ(0U, S.getNumBytesCopied());
    159 }
    160 
    161 // Test that an out of bounds read which crosses a contiguous block boundary
    162 // fails and allocates no memory.
    163 TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
    164   DiscontiguousFile F(BlocksAry, DataAry);
    165   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    166   StreamReader R(S);
    167   StringRef Str;
    168 
    169   R.setOffset(6);
    170   EXPECT_ERROR(R.readFixedString(Str, 5));
    171   EXPECT_EQ(0U, S.getNumBytesCopied());
    172 }
    173 
    174 // Test that an out of bounds read which crosses a discontiguous block
    175 // boundary fails and allocates no memory.
    176 TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
    177   DiscontiguousFile F(BlocksAry, DataAry);
    178   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    179   StreamReader R(S);
    180   StringRef Str;
    181 
    182   EXPECT_ERROR(R.readFixedString(Str, 11));
    183   EXPECT_EQ(0U, S.getNumBytesCopied());
    184 }
    185 
    186 // Tests that a read which is entirely contained within a single block but
    187 // beyond the end of a StreamRef fails.
    188 TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
    189   DiscontiguousFile F(BlocksAry, DataAry);
    190   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    191   StreamReader R(S);
    192   StringRef Str;
    193   EXPECT_NO_ERROR(R.readFixedString(Str, 1));
    194   EXPECT_EQ(Str, StringRef("A"));
    195   EXPECT_EQ(0U, S.getNumBytesCopied());
    196 }
    197 
    198 // Tests that a read which is not aligned on the same boundary as a previous
    199 // cached request, but which is known to overlap that request, shares the
    200 // previous allocation.
    201 TEST(MappedBlockStreamTest, UnalignedOverlappingRead) {
    202   DiscontiguousFile F(BlocksAry, DataAry);
    203   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    204   StreamReader R(S);
    205   StringRef Str1;
    206   StringRef Str2;
    207   EXPECT_NO_ERROR(R.readFixedString(Str1, 7));
    208   EXPECT_EQ(Str1, StringRef("ABCDEFG"));
    209   EXPECT_EQ(7U, S.getNumBytesCopied());
    210 
    211   R.setOffset(2);
    212   EXPECT_NO_ERROR(R.readFixedString(Str2, 3));
    213   EXPECT_EQ(Str2, StringRef("CDE"));
    214   EXPECT_EQ(Str1.data() + 2, Str2.data());
    215   EXPECT_EQ(7U, S.getNumBytesCopied());
    216 }
    217 
    218 // Tests that a read which is not aligned on the same boundary as a previous
    219 // cached request, but which only partially overlaps a previous cached request,
    220 // still works correctly and allocates again from the shared pool.
    221 TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) {
    222   DiscontiguousFile F(BlocksAry, DataAry);
    223   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    224   StreamReader R(S);
    225   StringRef Str1;
    226   StringRef Str2;
    227   EXPECT_NO_ERROR(R.readFixedString(Str1, 6));
    228   EXPECT_EQ(Str1, StringRef("ABCDEF"));
    229   EXPECT_EQ(6U, S.getNumBytesCopied());
    230 
    231   R.setOffset(4);
    232   EXPECT_NO_ERROR(R.readFixedString(Str2, 4));
    233   EXPECT_EQ(Str2, StringRef("EFGH"));
    234   EXPECT_EQ(10U, S.getNumBytesCopied());
    235 }
    236 
    237 TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) {
    238   static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
    239   static uint8_t LargeBuffer[] = {'0', '1', '2', '3', '4', '5',
    240                                   '6', '7', '8', '9', 'A'};
    241   static uint8_t SmallBuffer[] = {'0', '1', '2'};
    242   static_assert(sizeof(LargeBuffer) > sizeof(Data),
    243                 "LargeBuffer is not big enough");
    244 
    245   DiscontiguousFile F(BlocksAry, Data);
    246   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    247   ArrayRef<uint8_t> Buffer;
    248 
    249   EXPECT_ERROR(S.writeBytes(0, ArrayRef<uint8_t>(LargeBuffer)));
    250   EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef<uint8_t>(SmallBuffer)));
    251   EXPECT_NO_ERROR(S.writeBytes(7, ArrayRef<uint8_t>(SmallBuffer)));
    252   EXPECT_ERROR(S.writeBytes(8, ArrayRef<uint8_t>(SmallBuffer)));
    253 }
    254 
    255 TEST(MappedBlockStreamTest, TestWriteBytesNoBreakBoundary) {
    256   static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
    257   DiscontiguousFile F(BlocksAry, Data);
    258   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    259   ArrayRef<uint8_t> Buffer;
    260 
    261   EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer));
    262   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
    263   EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer));
    264   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
    265 
    266   EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef<uint8_t>('J')));
    267   EXPECT_NO_ERROR(S.writeBytes(9, ArrayRef<uint8_t>('A')));
    268 
    269   EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer));
    270   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
    271   EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer));
    272   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
    273 
    274   EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef<uint8_t>('A')));
    275   EXPECT_NO_ERROR(S.writeBytes(9, ArrayRef<uint8_t>('J')));
    276 
    277   EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer));
    278   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
    279   EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer));
    280   EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
    281 }
    282 
    283 TEST(MappedBlockStreamTest, TestWriteBytesBreakBoundary) {
    284   static uint8_t Data[] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
    285   static uint8_t TestData[] = {'T', 'E', 'S', 'T', 'I', 'N', 'G', '.'};
    286   static uint8_t Expected[] = {'T', 'E', 'S', 'N', 'I',
    287                                'T', 'G', '.', '0', '0'};
    288 
    289   DiscontiguousFile F(BlocksAry, Data);
    290   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    291   ArrayRef<uint8_t> Buffer;
    292 
    293   EXPECT_NO_ERROR(S.writeBytes(0, TestData));
    294   // First just compare the memory, then compare the result of reading the
    295   // string out.
    296   EXPECT_EQ(ArrayRef<uint8_t>(Data), ArrayRef<uint8_t>(Expected));
    297 
    298   EXPECT_NO_ERROR(S.readBytes(0, 8, Buffer));
    299   EXPECT_EQ(Buffer, ArrayRef<uint8_t>(TestData));
    300 }
    301 
    302 TEST(MappedBlockStreamTest, TestWriteThenRead) {
    303   std::vector<uint8_t> DataBytes(10);
    304   MutableArrayRef<uint8_t> Data(DataBytes);
    305   const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
    306 
    307   DiscontiguousFile F(Blocks, Data);
    308   MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
    309 
    310   enum class MyEnum : uint32_t { Val1 = 2908234, Val2 = 120891234 };
    311   using support::ulittle32_t;
    312 
    313   uint16_t u16[] = {31468, 0};
    314   uint32_t u32[] = {890723408, 0};
    315   MyEnum Enum[] = {MyEnum::Val1, MyEnum::Val2};
    316   StringRef ZStr[] = {"Zero Str", ""};
    317   StringRef FStr[] = {"Fixed Str", ""};
    318   uint8_t byteArray0[] = {'1', '2'};
    319   uint8_t byteArray1[] = {'0', '0'};
    320   ArrayRef<uint8_t> byteArrayRef0(byteArray0);
    321   ArrayRef<uint8_t> byteArrayRef1(byteArray1);
    322   ArrayRef<uint8_t> byteArray[] = { byteArrayRef0, byteArrayRef1 };
    323   ArrayRef<uint32_t> intArray[] = {{890723408, 29082234}, {0, 0}};
    324 
    325   StreamReader Reader(S);
    326   StreamWriter Writer(S);
    327   EXPECT_NO_ERROR(Writer.writeInteger(u16[0]));
    328   EXPECT_NO_ERROR(Reader.readInteger(u16[1]));
    329   EXPECT_EQ(u16[0], u16[1]);
    330   EXPECT_EQ(std::vector<uint8_t>({0, 0x7A, 0xEC, 0, 0, 0, 0, 0, 0, 0}),
    331             DataBytes);
    332 
    333   Reader.setOffset(0);
    334   Writer.setOffset(0);
    335   ::memset(DataBytes.data(), 0, 10);
    336   EXPECT_NO_ERROR(Writer.writeInteger(u32[0]));
    337   EXPECT_NO_ERROR(Reader.readInteger(u32[1]));
    338   EXPECT_EQ(u32[0], u32[1]);
    339   EXPECT_EQ(std::vector<uint8_t>({0x17, 0x5C, 0x50, 0, 0, 0, 0x35, 0, 0, 0}),
    340             DataBytes);
    341 
    342   Reader.setOffset(0);
    343   Writer.setOffset(0);
    344   ::memset(DataBytes.data(), 0, 10);
    345   EXPECT_NO_ERROR(Writer.writeEnum(Enum[0]));
    346   EXPECT_NO_ERROR(Reader.readEnum(Enum[1]));
    347   EXPECT_EQ(Enum[0], Enum[1]);
    348   EXPECT_EQ(std::vector<uint8_t>({0x2C, 0x60, 0x4A, 0, 0, 0, 0, 0, 0, 0}),
    349             DataBytes);
    350 
    351   Reader.setOffset(0);
    352   Writer.setOffset(0);
    353   ::memset(DataBytes.data(), 0, 10);
    354   EXPECT_NO_ERROR(Writer.writeZeroString(ZStr[0]));
    355   EXPECT_NO_ERROR(Reader.readZeroString(ZStr[1]));
    356   EXPECT_EQ(ZStr[0], ZStr[1]);
    357   EXPECT_EQ(
    358       std::vector<uint8_t>({'r', 'e', 'Z', ' ', 'S', 't', 'o', 'r', 0, 0}),
    359       DataBytes);
    360 
    361   Reader.setOffset(0);
    362   Writer.setOffset(0);
    363   ::memset(DataBytes.data(), 0, 10);
    364   EXPECT_NO_ERROR(Writer.writeFixedString(FStr[0]));
    365   EXPECT_NO_ERROR(Reader.readFixedString(FStr[1], FStr[0].size()));
    366   EXPECT_EQ(FStr[0], FStr[1]);
    367   EXPECT_EQ(
    368       std::vector<uint8_t>({'x', 'i', 'F', 'd', ' ', 'S', 'e', 't', 0, 'r'}),
    369       DataBytes);
    370 
    371   Reader.setOffset(0);
    372   Writer.setOffset(0);
    373   ::memset(DataBytes.data(), 0, 10);
    374   EXPECT_NO_ERROR(Writer.writeArray(byteArray[0]));
    375   EXPECT_NO_ERROR(Reader.readArray(byteArray[1], byteArray[0].size()));
    376   EXPECT_EQ(byteArray[0], byteArray[1]);
    377   EXPECT_EQ(std::vector<uint8_t>({0, 0x32, 0x31, 0, 0, 0, 0, 0, 0, 0}),
    378             DataBytes);
    379 
    380   Reader.setOffset(0);
    381   Writer.setOffset(0);
    382   ::memset(DataBytes.data(), 0, 10);
    383   EXPECT_NO_ERROR(Writer.writeArray(intArray[0]));
    384   EXPECT_NO_ERROR(Reader.readArray(intArray[1], intArray[0].size()));
    385   EXPECT_EQ(intArray[0], intArray[1]);
    386 }
    387 
    388 TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) {
    389   std::vector<uint8_t> DestDataBytes(10);
    390   MutableArrayRef<uint8_t> DestData(DestDataBytes);
    391   const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
    392 
    393   std::vector<uint8_t> SrcDataBytes(10);
    394   MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
    395 
    396   DiscontiguousFile F(DestBlocks, DestData);
    397   MappedBlockStreamImpl DestStream(llvm::make_unique<IndexedStreamData>(0, F),
    398                                    F);
    399 
    400   // First write "Test Str" into the source stream.
    401   ByteStream<true> SourceStream(SrcData);
    402   StreamWriter SourceWriter(SourceStream);
    403   EXPECT_NO_ERROR(SourceWriter.writeZeroString("Test Str"));
    404   EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
    405                               {'T', 'e', 's', 't', ' ', 'S', 't', 'r', 0, 0}));
    406 
    407   // Then write the source stream into the dest stream.
    408   StreamWriter DestWriter(DestStream);
    409   EXPECT_NO_ERROR(DestWriter.writeStreamRef(SourceStream));
    410   EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
    411                                {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
    412 
    413   // Then read the string back out of the dest stream.
    414   StringRef Result;
    415   StreamReader DestReader(DestStream);
    416   EXPECT_NO_ERROR(DestReader.readZeroString(Result));
    417   EXPECT_EQ(Result, "Test Str");
    418 }
    419 
    420 TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) {
    421   std::vector<uint8_t> DestDataBytes(10);
    422   MutableArrayRef<uint8_t> DestData(DestDataBytes);
    423   const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
    424 
    425   std::vector<uint8_t> SrcDataBytes(10);
    426   MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
    427   const uint32_t SrcBlocks[] = {1, 0, 6, 3, 4, 5, 2, 7, 8, 9};
    428 
    429   DiscontiguousFile DestFile(DestBlocks, DestData);
    430   DiscontiguousFile SrcFile(SrcBlocks, SrcData);
    431 
    432   MappedBlockStreamImpl DestStream(
    433       llvm::make_unique<IndexedStreamData>(0, DestFile), DestFile);
    434   MappedBlockStreamImpl SrcStream(
    435       llvm::make_unique<IndexedStreamData>(0, SrcFile), SrcFile);
    436 
    437   // First write "Test Str" into the source stream.
    438   StreamWriter SourceWriter(SrcStream);
    439   EXPECT_NO_ERROR(SourceWriter.writeZeroString("Test Str"));
    440   EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
    441                               {'e', 'T', 't', 't', ' ', 'S', 's', 'r', 0, 0}));
    442 
    443   // Then write the source stream into the dest stream.
    444   StreamWriter DestWriter(DestStream);
    445   EXPECT_NO_ERROR(DestWriter.writeStreamRef(SrcStream));
    446   EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
    447                                {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
    448 
    449   // Then read the string back out of the dest stream.
    450   StringRef Result;
    451   StreamReader DestReader(DestStream);
    452   EXPECT_NO_ERROR(DestReader.readZeroString(Result));
    453   EXPECT_EQ(Result, "Test Str");
    454 }
    455 
    456 } // end anonymous namespace
    457