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