xref: /llvm-project/llvm/unittests/DebugInfo/MSF/MSFBuilderTest.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1018338e5SZachary Turner //===- MSFBuilderTest.cpp  Tests manipulation of MSF stream metadata ------===//
2018338e5SZachary Turner //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6018338e5SZachary Turner //
7018338e5SZachary Turner //===----------------------------------------------------------------------===//
8018338e5SZachary Turner 
9018338e5SZachary Turner #include "llvm/DebugInfo/MSF/MSFBuilder.h"
10018338e5SZachary Turner #include "llvm/DebugInfo/MSF/MSFCommon.h"
11018338e5SZachary Turner #include "llvm/Testing/Support/Error.h"
12018338e5SZachary Turner 
139fb9d71dSZachary Turner #include "gmock/gmock-matchers.h"
149fb9d71dSZachary Turner #include "gmock/gmock.h"
15018338e5SZachary Turner #include "gtest/gtest.h"
16018338e5SZachary Turner 
17018338e5SZachary Turner using namespace llvm;
18018338e5SZachary Turner using namespace llvm::msf;
199fb9d71dSZachary Turner using namespace testing;
20018338e5SZachary Turner 
21018338e5SZachary Turner namespace {
22018338e5SZachary Turner class MSFBuilderTest : public testing::Test {
23018338e5SZachary Turner protected:
initializeSimpleSuperBlock(msf::SuperBlock & SB)24018338e5SZachary Turner   void initializeSimpleSuperBlock(msf::SuperBlock &SB) {
25018338e5SZachary Turner     initializeSuperBlock(SB);
26018338e5SZachary Turner     SB.NumBlocks = 1000;
27018338e5SZachary Turner     SB.NumDirectoryBytes = 8192;
28018338e5SZachary Turner   }
29018338e5SZachary Turner 
initializeSuperBlock(msf::SuperBlock & SB)30018338e5SZachary Turner   void initializeSuperBlock(msf::SuperBlock &SB) {
31018338e5SZachary Turner     ::memset(&SB, 0, sizeof(SB));
32018338e5SZachary Turner 
33018338e5SZachary Turner     ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
34018338e5SZachary Turner     SB.FreeBlockMapBlock = 1;
35018338e5SZachary Turner     SB.BlockMapAddr = 1;
36018338e5SZachary Turner     SB.BlockSize = 4096;
37018338e5SZachary Turner     SB.NumDirectoryBytes = 0;
38018338e5SZachary Turner     SB.NumBlocks = 2; // one for the Super Block, one for the directory
39018338e5SZachary Turner   }
40018338e5SZachary Turner 
41018338e5SZachary Turner   BumpPtrAllocator Allocator;
42018338e5SZachary Turner };
43018338e5SZachary Turner } // namespace
44018338e5SZachary Turner 
TEST_F(MSFBuilderTest,ValidateSuperBlockAccept)45018338e5SZachary Turner TEST_F(MSFBuilderTest, ValidateSuperBlockAccept) {
46018338e5SZachary Turner   // Test that a known good super block passes validation.
47018338e5SZachary Turner   SuperBlock SB;
48018338e5SZachary Turner   initializeSuperBlock(SB);
49018338e5SZachary Turner 
50018338e5SZachary Turner   EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Succeeded());
51018338e5SZachary Turner }
52018338e5SZachary Turner 
TEST_F(MSFBuilderTest,ValidateSuperBlockReject)53018338e5SZachary Turner TEST_F(MSFBuilderTest, ValidateSuperBlockReject) {
54018338e5SZachary Turner   // Test that various known problems cause a super block to be rejected.
55018338e5SZachary Turner   SuperBlock SB;
56018338e5SZachary Turner   initializeSimpleSuperBlock(SB);
57018338e5SZachary Turner 
58018338e5SZachary Turner   // Mismatched magic
59018338e5SZachary Turner   SB.MagicBytes[0] = 8;
60018338e5SZachary Turner   EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
61018338e5SZachary Turner   initializeSimpleSuperBlock(SB);
62018338e5SZachary Turner 
63018338e5SZachary Turner   // Block 0 is reserved for super block, can't be occupied by the block map
64018338e5SZachary Turner   SB.BlockMapAddr = 0;
65018338e5SZachary Turner   EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
66018338e5SZachary Turner   initializeSimpleSuperBlock(SB);
67018338e5SZachary Turner 
68018338e5SZachary Turner   // Block sizes have to be powers of 2.
69018338e5SZachary Turner   SB.BlockSize = 3120;
70018338e5SZachary Turner   EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
71018338e5SZachary Turner   initializeSimpleSuperBlock(SB);
72018338e5SZachary Turner 
73018338e5SZachary Turner   // The directory itself has a maximum size.
74018338e5SZachary Turner   SB.NumDirectoryBytes = SB.BlockSize * SB.BlockSize / 4;
75018338e5SZachary Turner   EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Succeeded());
76018338e5SZachary Turner   SB.NumDirectoryBytes = SB.NumDirectoryBytes + 4;
77018338e5SZachary Turner   EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
78018338e5SZachary Turner }
79018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestUsedBlocksMarkedAsUsed)80018338e5SZachary Turner TEST_F(MSFBuilderTest, TestUsedBlocksMarkedAsUsed) {
81018338e5SZachary Turner   // Test that when assigning a stream to a known list of blocks, the blocks
82018338e5SZachary Turner   // are correctly marked as used after adding, but no other incorrect blocks
83018338e5SZachary Turner   // are accidentally marked as used.
84018338e5SZachary Turner 
85018338e5SZachary Turner   std::vector<uint32_t> Blocks = {4, 5, 6, 7, 8, 9, 10, 11, 12};
86018338e5SZachary Turner   // Allocate some extra blocks at the end so we can verify that they're free
87018338e5SZachary Turner   // after the initialization.
88018338e5SZachary Turner   uint32_t NumBlocks = msf::getMinimumBlockCount() + Blocks.size() + 10;
89018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096, NumBlocks);
90018338e5SZachary Turner   ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());
91018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
92018338e5SZachary Turner 
93018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(Blocks.size() * 4096, Blocks),
94018338e5SZachary Turner                        Succeeded());
95018338e5SZachary Turner 
96018338e5SZachary Turner   for (auto B : Blocks) {
97018338e5SZachary Turner     EXPECT_FALSE(Msf.isBlockFree(B));
98018338e5SZachary Turner   }
99018338e5SZachary Turner 
100018338e5SZachary Turner   uint32_t FreeBlockStart = Blocks.back() + 1;
101018338e5SZachary Turner   for (uint32_t I = FreeBlockStart; I < NumBlocks; ++I) {
102018338e5SZachary Turner     EXPECT_TRUE(Msf.isBlockFree(I));
103018338e5SZachary Turner   }
104018338e5SZachary Turner }
105018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestAddStreamNoDirectoryBlockIncrease)106018338e5SZachary Turner TEST_F(MSFBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
107018338e5SZachary Turner   // Test that adding a new stream correctly updates the directory.  This only
108018338e5SZachary Turner   // tests the case where the directory *DOES NOT* grow large enough that it
109018338e5SZachary Turner   // crosses a Block boundary.
110018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
111018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
112018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
113018338e5SZachary Turner 
114ee8010abSZachary Turner   auto ExpectedL1 = Msf.generateLayout();
115018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());
116018338e5SZachary Turner   MSFLayout &L1 = *ExpectedL1;
117018338e5SZachary Turner 
118018338e5SZachary Turner   auto OldDirBlocks = L1.DirectoryBlocks;
119018338e5SZachary Turner   EXPECT_EQ(1U, OldDirBlocks.size());
120018338e5SZachary Turner 
121018338e5SZachary Turner   auto ExpectedMsf2 = MSFBuilder::create(Allocator, 4096);
122018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf2, Succeeded());
123018338e5SZachary Turner   auto &Msf2 = *ExpectedMsf2;
124018338e5SZachary Turner 
125018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf2.addStream(4000), Succeeded());
126018338e5SZachary Turner   EXPECT_EQ(1U, Msf2.getNumStreams());
127018338e5SZachary Turner   EXPECT_EQ(4000U, Msf2.getStreamSize(0));
128018338e5SZachary Turner   auto Blocks = Msf2.getStreamBlocks(0);
129018338e5SZachary Turner   EXPECT_EQ(1U, Blocks.size());
130018338e5SZachary Turner 
131ee8010abSZachary Turner   auto ExpectedL2 = Msf2.generateLayout();
132018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedL2, Succeeded());
133018338e5SZachary Turner   MSFLayout &L2 = *ExpectedL2;
134018338e5SZachary Turner   auto NewDirBlocks = L2.DirectoryBlocks;
135018338e5SZachary Turner   EXPECT_EQ(1U, NewDirBlocks.size());
136018338e5SZachary Turner }
137018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestAddStreamWithDirectoryBlockIncrease)138018338e5SZachary Turner TEST_F(MSFBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
139018338e5SZachary Turner   // Test that adding a new stream correctly updates the directory.  This only
140018338e5SZachary Turner   // tests the case where the directory *DOES* grow large enough that it
141018338e5SZachary Turner   // crosses a Block boundary.  This is because the newly added stream occupies
142018338e5SZachary Turner   // so many Blocks that need to be indexed in the directory that the directory
143018338e5SZachary Turner   // crosses a Block boundary.
144018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
145018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
146018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
147018338e5SZachary Turner 
148018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(4096 * 4096 / sizeof(uint32_t)),
149018338e5SZachary Turner                        Succeeded());
150018338e5SZachary Turner 
151ee8010abSZachary Turner   auto ExpectedL1 = Msf.generateLayout();
152018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());
153018338e5SZachary Turner   MSFLayout &L1 = *ExpectedL1;
154018338e5SZachary Turner   auto DirBlocks = L1.DirectoryBlocks;
155018338e5SZachary Turner   EXPECT_EQ(2U, DirBlocks.size());
156018338e5SZachary Turner }
157018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestGrowStreamNoBlockIncrease)158018338e5SZachary Turner TEST_F(MSFBuilderTest, TestGrowStreamNoBlockIncrease) {
159018338e5SZachary Turner   // Test growing an existing stream by a value that does not affect the number
160018338e5SZachary Turner   // of blocks it occupies.
161018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
162018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
163018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
164018338e5SZachary Turner 
165018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(1024), Succeeded());
166018338e5SZachary Turner   EXPECT_EQ(1024U, Msf.getStreamSize(0));
167018338e5SZachary Turner   auto OldStreamBlocks = Msf.getStreamBlocks(0);
168018338e5SZachary Turner   EXPECT_EQ(1U, OldStreamBlocks.size());
169018338e5SZachary Turner 
170018338e5SZachary Turner   EXPECT_THAT_ERROR(Msf.setStreamSize(0, 2048), Succeeded());
171018338e5SZachary Turner   EXPECT_EQ(2048U, Msf.getStreamSize(0));
172018338e5SZachary Turner   auto NewStreamBlocks = Msf.getStreamBlocks(0);
173018338e5SZachary Turner   EXPECT_EQ(1U, NewStreamBlocks.size());
174018338e5SZachary Turner 
175018338e5SZachary Turner   EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
176018338e5SZachary Turner }
177018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestGrowStreamWithBlockIncrease)178018338e5SZachary Turner TEST_F(MSFBuilderTest, TestGrowStreamWithBlockIncrease) {
179018338e5SZachary Turner   // Test that growing an existing stream to a value large enough that it causes
180018338e5SZachary Turner   // the need to allocate new Blocks to the stream correctly updates the
181018338e5SZachary Turner   // stream's
182018338e5SZachary Turner   // block list.
183018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
184018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
185018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
186018338e5SZachary Turner 
187018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
188018338e5SZachary Turner   EXPECT_EQ(2048U, Msf.getStreamSize(0));
189018338e5SZachary Turner   std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
190018338e5SZachary Turner   EXPECT_EQ(1U, OldStreamBlocks.size());
191018338e5SZachary Turner 
192018338e5SZachary Turner   EXPECT_THAT_ERROR(Msf.setStreamSize(0, 6144), Succeeded());
193018338e5SZachary Turner   EXPECT_EQ(6144U, Msf.getStreamSize(0));
194018338e5SZachary Turner   std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
195018338e5SZachary Turner   EXPECT_EQ(2U, NewStreamBlocks.size());
196018338e5SZachary Turner 
197018338e5SZachary Turner   EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
198018338e5SZachary Turner   EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);
199018338e5SZachary Turner }
200018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestShrinkStreamNoBlockDecrease)201018338e5SZachary Turner TEST_F(MSFBuilderTest, TestShrinkStreamNoBlockDecrease) {
202018338e5SZachary Turner   // Test that shrinking an existing stream by a value that does not affect the
203018338e5SZachary Turner   // number of Blocks it occupies makes no changes to stream's block list.
204018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
205018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
206018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
207018338e5SZachary Turner 
208018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
209018338e5SZachary Turner   EXPECT_EQ(2048U, Msf.getStreamSize(0));
210018338e5SZachary Turner   std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
211018338e5SZachary Turner   EXPECT_EQ(1U, OldStreamBlocks.size());
212018338e5SZachary Turner 
213018338e5SZachary Turner   EXPECT_THAT_ERROR(Msf.setStreamSize(0, 1024), Succeeded());
214018338e5SZachary Turner   EXPECT_EQ(1024U, Msf.getStreamSize(0));
215018338e5SZachary Turner   std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
216018338e5SZachary Turner   EXPECT_EQ(1U, NewStreamBlocks.size());
217018338e5SZachary Turner 
218018338e5SZachary Turner   EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
219018338e5SZachary Turner }
220018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestShrinkStreamWithBlockDecrease)221018338e5SZachary Turner TEST_F(MSFBuilderTest, TestShrinkStreamWithBlockDecrease) {
222018338e5SZachary Turner   // Test that shrinking an existing stream to a value large enough that it
223018338e5SZachary Turner   // causes the need to deallocate new Blocks to the stream correctly updates
224018338e5SZachary Turner   // the stream's block list.
225018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
226018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
227018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
228018338e5SZachary Turner 
229018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(6144), Succeeded());
230018338e5SZachary Turner   EXPECT_EQ(6144U, Msf.getStreamSize(0));
231018338e5SZachary Turner   std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
232018338e5SZachary Turner   EXPECT_EQ(2U, OldStreamBlocks.size());
233018338e5SZachary Turner 
234018338e5SZachary Turner   EXPECT_THAT_ERROR(Msf.setStreamSize(0, 2048), Succeeded());
235018338e5SZachary Turner   EXPECT_EQ(2048U, Msf.getStreamSize(0));
236018338e5SZachary Turner   std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
237018338e5SZachary Turner   EXPECT_EQ(1U, NewStreamBlocks.size());
238018338e5SZachary Turner 
239018338e5SZachary Turner   EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
240018338e5SZachary Turner }
241018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestRejectReusedStreamBlock)242018338e5SZachary Turner TEST_F(MSFBuilderTest, TestRejectReusedStreamBlock) {
243018338e5SZachary Turner   // Test that attempting to add a stream and assigning a block that is already
244018338e5SZachary Turner   // in use by another stream fails.
245018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
246018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
247018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
248018338e5SZachary Turner 
249018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(6144), Succeeded());
250018338e5SZachary Turner 
251018338e5SZachary Turner   std::vector<uint32_t> Blocks = {2, 3};
252018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(6144, Blocks), Failed());
253018338e5SZachary Turner }
254018338e5SZachary Turner 
TEST_F(MSFBuilderTest,TestBlockCountsWhenAddingStreams)255018338e5SZachary Turner TEST_F(MSFBuilderTest, TestBlockCountsWhenAddingStreams) {
256018338e5SZachary Turner   // Test that when adding multiple streams, the number of used and free Blocks
257018338e5SZachary Turner   // allocated to the MSF file are as expected.
258018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
259018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
260018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
261018338e5SZachary Turner 
262018338e5SZachary Turner   // one for the super block, one for the directory block map
263018338e5SZachary Turner   uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();
264018338e5SZachary Turner   EXPECT_EQ(msf::getMinimumBlockCount(), NumUsedBlocks);
265018338e5SZachary Turner   EXPECT_EQ(0U, Msf.getNumFreeBlocks());
266018338e5SZachary Turner 
267018338e5SZachary Turner   const uint32_t StreamSizes[] = {4000, 6193, 189723};
268018338e5SZachary Turner   for (int I = 0; I < 3; ++I) {
269018338e5SZachary Turner     EXPECT_THAT_EXPECTED(Msf.addStream(StreamSizes[I]), Succeeded());
270018338e5SZachary Turner     NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);
271018338e5SZachary Turner     EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());
272018338e5SZachary Turner     EXPECT_EQ(0U, Msf.getNumFreeBlocks());
273018338e5SZachary Turner   }
274018338e5SZachary Turner }
275018338e5SZachary Turner 
TEST_F(MSFBuilderTest,BuildMsfLayout)276018338e5SZachary Turner TEST_F(MSFBuilderTest, BuildMsfLayout) {
277018338e5SZachary Turner   // Test that we can generate an MSFLayout structure from a valid layout
278018338e5SZachary Turner   // specification.
279018338e5SZachary Turner   auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
280018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
281018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
282018338e5SZachary Turner 
283018338e5SZachary Turner   const uint32_t StreamSizes[] = {4000, 6193, 189723};
284018338e5SZachary Turner   uint32_t ExpectedNumBlocks = msf::getMinimumBlockCount();
285018338e5SZachary Turner   for (int I = 0; I < 3; ++I) {
286018338e5SZachary Turner     EXPECT_THAT_EXPECTED(Msf.addStream(StreamSizes[I]), Succeeded());
287018338e5SZachary Turner     ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
288018338e5SZachary Turner   }
289018338e5SZachary Turner   ++ExpectedNumBlocks; // The directory itself should use 1 block
290018338e5SZachary Turner 
291ee8010abSZachary Turner   auto ExpectedLayout = Msf.generateLayout();
292018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
293018338e5SZachary Turner   MSFLayout &L = *ExpectedLayout;
294018338e5SZachary Turner   EXPECT_EQ(4096U, L.SB->BlockSize);
295018338e5SZachary Turner   EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);
296018338e5SZachary Turner 
297018338e5SZachary Turner   EXPECT_EQ(1U, L.DirectoryBlocks.size());
298018338e5SZachary Turner 
299018338e5SZachary Turner   EXPECT_EQ(3U, L.StreamMap.size());
300018338e5SZachary Turner   EXPECT_EQ(3U, L.StreamSizes.size());
301018338e5SZachary Turner   for (int I = 0; I < 3; ++I) {
302018338e5SZachary Turner     EXPECT_EQ(StreamSizes[I], L.StreamSizes[I]);
303018338e5SZachary Turner     uint32_t ExpectedNumBlocks = bytesToBlocks(StreamSizes[I], 4096);
304018338e5SZachary Turner     EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());
305018338e5SZachary Turner   }
306018338e5SZachary Turner }
307018338e5SZachary Turner 
TEST_F(MSFBuilderTest,UseDirectoryBlockHint)308018338e5SZachary Turner TEST_F(MSFBuilderTest, UseDirectoryBlockHint) {
309018338e5SZachary Turner   Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(
310018338e5SZachary Turner       Allocator, 4096, msf::getMinimumBlockCount() + 1, false);
311018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
312018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
313018338e5SZachary Turner 
314018338e5SZachary Turner   uint32_t B = msf::getFirstUnreservedBlock();
315018338e5SZachary Turner   EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());
316018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(2048, {B + 2}), Succeeded());
317018338e5SZachary Turner 
318ee8010abSZachary Turner   auto ExpectedLayout = Msf.generateLayout();
319018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
320018338e5SZachary Turner   MSFLayout &L = *ExpectedLayout;
321018338e5SZachary Turner   EXPECT_EQ(msf::getMinimumBlockCount() + 2, L.SB->NumBlocks);
322018338e5SZachary Turner   EXPECT_EQ(1U, L.DirectoryBlocks.size());
323018338e5SZachary Turner   EXPECT_EQ(1U, L.StreamMap[0].size());
324018338e5SZachary Turner 
325018338e5SZachary Turner   EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
326018338e5SZachary Turner   EXPECT_EQ(B + 2, L.StreamMap[0].front());
327018338e5SZachary Turner }
328018338e5SZachary Turner 
TEST_F(MSFBuilderTest,DirectoryBlockHintInsufficient)329018338e5SZachary Turner TEST_F(MSFBuilderTest, DirectoryBlockHintInsufficient) {
330018338e5SZachary Turner   Expected<MSFBuilder> ExpectedMsf =
331018338e5SZachary Turner       MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
332018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
333018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
334018338e5SZachary Turner   uint32_t B = msf::getFirstUnreservedBlock();
335018338e5SZachary Turner   EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());
336018338e5SZachary Turner 
337018338e5SZachary Turner   uint32_t Size = 4096 * 4096 / 4;
338018338e5SZachary Turner   EXPECT_THAT_EXPECTED(Msf.addStream(Size), Succeeded());
339018338e5SZachary Turner 
340ee8010abSZachary Turner   auto ExpectedLayout = Msf.generateLayout();
341018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
342018338e5SZachary Turner   MSFLayout &L = *ExpectedLayout;
343018338e5SZachary Turner   EXPECT_EQ(2U, L.DirectoryBlocks.size());
344018338e5SZachary Turner   EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
345018338e5SZachary Turner }
346018338e5SZachary Turner 
TEST_F(MSFBuilderTest,DirectoryBlockHintOverestimated)347018338e5SZachary Turner TEST_F(MSFBuilderTest, DirectoryBlockHintOverestimated) {
348018338e5SZachary Turner   Expected<MSFBuilder> ExpectedMsf =
349018338e5SZachary Turner       MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
350018338e5SZachary Turner   EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
351018338e5SZachary Turner   auto &Msf = *ExpectedMsf;
352018338e5SZachary Turner 
353018338e5SZachary Turner   uint32_t B = msf::getFirstUnreservedBlock();
354018338e5SZachary Turner   EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1, B + 2}), Succeeded());
355018338e5SZachary Turner 
356018338e5SZachary Turner   ASSERT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
357018338e5SZachary Turner 
358ee8010abSZachary Turner   auto ExpectedLayout = Msf.generateLayout();
359018338e5SZachary Turner   ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
360018338e5SZachary Turner   MSFLayout &L = *ExpectedLayout;
361018338e5SZachary Turner   EXPECT_EQ(1U, L.DirectoryBlocks.size());
362018338e5SZachary Turner   EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
363018338e5SZachary Turner }
3649fb9d71dSZachary Turner 
TEST_F(MSFBuilderTest,StreamDoesntUseFpmBlocks)3659fb9d71dSZachary Turner TEST_F(MSFBuilderTest, StreamDoesntUseFpmBlocks) {
3669fb9d71dSZachary Turner   Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(Allocator, 4096);
3679fb9d71dSZachary Turner   ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());
3689fb9d71dSZachary Turner   auto &Msf = *ExpectedMsf;
3699fb9d71dSZachary Turner 
3709fb9d71dSZachary Turner   // A block is 4096 bytes, and every 4096 blocks we have 2 reserved FPM blocks.
3719fb9d71dSZachary Turner   // By creating add a stream that spans 4096*4096*3 bytes, we ensure that we
3729fb9d71dSZachary Turner   // cross over a couple of reserved FPM blocks, and that none of them are
3739fb9d71dSZachary Turner   // allocated to the stream.
3749fb9d71dSZachary Turner   constexpr uint32_t StreamSize = 4096 * 4096 * 3;
3759fb9d71dSZachary Turner   Expected<uint32_t> SN = Msf.addStream(StreamSize);
3769fb9d71dSZachary Turner   ASSERT_THAT_EXPECTED(SN, Succeeded());
3779fb9d71dSZachary Turner 
378ee8010abSZachary Turner   auto ExpectedLayout = Msf.generateLayout();
3799fb9d71dSZachary Turner   ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
3809fb9d71dSZachary Turner   MSFLayout &L = *ExpectedLayout;
3819fb9d71dSZachary Turner   auto BlocksRef = L.StreamMap[*SN];
3829fb9d71dSZachary Turner   std::vector<uint32_t> Blocks(BlocksRef.begin(), BlocksRef.end());
3839fb9d71dSZachary Turner   EXPECT_EQ(StreamSize, L.StreamSizes[*SN]);
3849fb9d71dSZachary Turner 
3859fb9d71dSZachary Turner   for (uint32_t I = 0; I <= 3; ++I) {
3863203e274SZachary Turner     // Pages from both FPMs are always allocated.
3873203e274SZachary Turner     EXPECT_FALSE(L.FreePageMap.test(2 + I * 4096));
3889fb9d71dSZachary Turner     EXPECT_FALSE(L.FreePageMap.test(1 + I * 4096));
3899fb9d71dSZachary Turner   }
3909fb9d71dSZachary Turner 
3919fb9d71dSZachary Turner   for (uint32_t I = 1; I <= 3; ++I) {
3929fb9d71dSZachary Turner     EXPECT_THAT(Blocks, Not(Contains(1 + I * 4096)));
3939fb9d71dSZachary Turner     EXPECT_THAT(Blocks, Not(Contains(2 + I * 4096)));
3949fb9d71dSZachary Turner   }
3959fb9d71dSZachary Turner }
396