1018338e5SZachary Turner //===- llvm/unittest/DebugInfo/MSF/MappedBlockStreamTest.cpp --------------===//
2018338e5SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6018338e5SZachary Turner //
7018338e5SZachary Turner //===----------------------------------------------------------------------===//
8018338e5SZachary Turner
9018338e5SZachary Turner #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
10018338e5SZachary Turner #include "llvm/Support/BinaryByteStream.h"
11018338e5SZachary Turner #include "llvm/Support/BinaryStreamReader.h"
12018338e5SZachary Turner #include "llvm/Support/BinaryStreamRef.h"
13018338e5SZachary Turner #include "llvm/Support/BinaryStreamWriter.h"
14018338e5SZachary Turner #include "llvm/Testing/Support/Error.h"
15018338e5SZachary Turner
169fb9d71dSZachary Turner #include "gmock/gmock.h"
17018338e5SZachary Turner #include "gtest/gtest.h"
18018338e5SZachary Turner
19018338e5SZachary Turner
20018338e5SZachary Turner using namespace llvm;
21018338e5SZachary Turner using namespace llvm::msf;
22018338e5SZachary Turner using namespace llvm::support;
23018338e5SZachary Turner
24018338e5SZachary Turner namespace {
25018338e5SZachary Turner
26018338e5SZachary Turner static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9};
27018338e5SZachary Turner static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'};
28018338e5SZachary Turner
29018338e5SZachary Turner class DiscontiguousStream : public WritableBinaryStream {
30018338e5SZachary Turner public:
DiscontiguousStream(ArrayRef<uint32_t> Blocks,MutableArrayRef<uint8_t> Data)31018338e5SZachary Turner DiscontiguousStream(ArrayRef<uint32_t> Blocks, MutableArrayRef<uint8_t> Data)
32018338e5SZachary Turner : Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {}
33018338e5SZachary Turner
block_size() const34018338e5SZachary Turner uint32_t block_size() const { return 1; }
block_count() const35018338e5SZachary Turner uint32_t block_count() const { return Blocks.size(); }
36018338e5SZachary Turner
getEndian() const37*02f67c09SKazu Hirata llvm::endianness getEndian() const override {
38*02f67c09SKazu Hirata return llvm::endianness::little;
39*02f67c09SKazu Hirata }
40018338e5SZachary Turner
readBytes(uint64_t Offset,uint64_t Size,ArrayRef<uint8_t> & Buffer)41646299d1SNico Weber Error readBytes(uint64_t Offset, uint64_t Size,
42018338e5SZachary Turner ArrayRef<uint8_t> &Buffer) override {
4396c6985bSZachary Turner if (auto EC = checkOffsetForRead(Offset, Size))
44018338e5SZachary Turner return EC;
45018338e5SZachary Turner Buffer = Data.slice(Offset, Size);
46018338e5SZachary Turner return Error::success();
47018338e5SZachary Turner }
48018338e5SZachary Turner
readLongestContiguousChunk(uint64_t Offset,ArrayRef<uint8_t> & Buffer)49646299d1SNico Weber Error readLongestContiguousChunk(uint64_t Offset,
50018338e5SZachary Turner ArrayRef<uint8_t> &Buffer) override {
5196c6985bSZachary Turner if (auto EC = checkOffsetForRead(Offset, 1))
52018338e5SZachary Turner return EC;
53018338e5SZachary Turner Buffer = Data.drop_front(Offset);
54018338e5SZachary Turner return Error::success();
55018338e5SZachary Turner }
56018338e5SZachary Turner
getLength()57646299d1SNico Weber uint64_t getLength() override { return Data.size(); }
58018338e5SZachary Turner
writeBytes(uint64_t Offset,ArrayRef<uint8_t> SrcData)59646299d1SNico Weber Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> SrcData) override {
6096c6985bSZachary Turner if (auto EC = checkOffsetForWrite(Offset, SrcData.size()))
61018338e5SZachary Turner return EC;
62018338e5SZachary Turner ::memcpy(&Data[Offset], SrcData.data(), SrcData.size());
63018338e5SZachary Turner return Error::success();
64018338e5SZachary Turner }
commit()65018338e5SZachary Turner Error commit() override { return Error::success(); }
66018338e5SZachary Turner
layout() const67018338e5SZachary Turner MSFStreamLayout layout() const {
68018338e5SZachary Turner return MSFStreamLayout{static_cast<uint32_t>(Data.size()), Blocks};
69018338e5SZachary Turner }
70018338e5SZachary Turner
71018338e5SZachary Turner BumpPtrAllocator Allocator;
72018338e5SZachary Turner
73018338e5SZachary Turner private:
74018338e5SZachary Turner std::vector<support::ulittle32_t> Blocks;
75018338e5SZachary Turner MutableArrayRef<uint8_t> Data;
76018338e5SZachary Turner };
77018338e5SZachary Turner
TEST(MappedBlockStreamTest,NumBlocks)78018338e5SZachary Turner TEST(MappedBlockStreamTest, NumBlocks) {
79018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
80018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
81018338e5SZachary Turner F.Allocator);
82018338e5SZachary Turner EXPECT_EQ(F.block_size(), S->getBlockSize());
83018338e5SZachary Turner EXPECT_EQ(F.layout().Blocks.size(), S->getNumBlocks());
84018338e5SZachary Turner }
85018338e5SZachary Turner
86018338e5SZachary Turner // Tests that a read which is entirely contained within a single block works
87018338e5SZachary Turner // and does not allocate.
TEST(MappedBlockStreamTest,ReadBeyondEndOfStreamRef)88018338e5SZachary Turner TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) {
89018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
90018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
91018338e5SZachary Turner F.Allocator);
92018338e5SZachary Turner
93018338e5SZachary Turner BinaryStreamReader R(*S);
94018338e5SZachary Turner BinaryStreamRef SR;
95018338e5SZachary Turner EXPECT_THAT_ERROR(R.readStreamRef(SR, 0U), Succeeded());
96018338e5SZachary Turner ArrayRef<uint8_t> Buffer;
97018338e5SZachary Turner EXPECT_THAT_ERROR(SR.readBytes(0U, 1U, Buffer), Failed());
98018338e5SZachary Turner EXPECT_THAT_ERROR(R.readStreamRef(SR, 1U), Succeeded());
99018338e5SZachary Turner EXPECT_THAT_ERROR(SR.readBytes(1U, 1U, Buffer), Failed());
100018338e5SZachary Turner }
101018338e5SZachary Turner
102018338e5SZachary Turner // Tests that a read which outputs into a full destination buffer works and
103018338e5SZachary Turner // does not fail due to the length of the output buffer.
TEST(MappedBlockStreamTest,ReadOntoNonEmptyBuffer)104018338e5SZachary Turner TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
105018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
106018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
107018338e5SZachary Turner F.Allocator);
108018338e5SZachary Turner
109018338e5SZachary Turner BinaryStreamReader R(*S);
110018338e5SZachary Turner StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
111018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded());
112018338e5SZachary Turner EXPECT_EQ(Str, StringRef("A"));
113018338e5SZachary Turner EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
114018338e5SZachary Turner }
115018338e5SZachary Turner
116018338e5SZachary Turner // Tests that a read which crosses a block boundary, but where the subsequent
117018338e5SZachary Turner // blocks are still contiguous in memory to the previous block works and does
118018338e5SZachary Turner // not allocate memory.
TEST(MappedBlockStreamTest,ZeroCopyReadContiguousBreak)119018338e5SZachary Turner TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
120018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
121018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
122018338e5SZachary Turner F.Allocator);
123018338e5SZachary Turner BinaryStreamReader R(*S);
124018338e5SZachary Turner StringRef Str;
125018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str, 2), Succeeded());
126018338e5SZachary Turner EXPECT_EQ(Str, StringRef("AB"));
127018338e5SZachary Turner EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
128018338e5SZachary Turner
129018338e5SZachary Turner R.setOffset(6);
130018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str, 4), Succeeded());
131018338e5SZachary Turner EXPECT_EQ(Str, StringRef("GHIJ"));
132018338e5SZachary Turner EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
133018338e5SZachary Turner }
134018338e5SZachary Turner
135018338e5SZachary Turner // Tests that a read which crosses a block boundary and cannot be referenced
136018338e5SZachary Turner // contiguously works and allocates only the precise amount of bytes
137018338e5SZachary Turner // requested.
TEST(MappedBlockStreamTest,CopyReadNonContiguousBreak)138018338e5SZachary Turner TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
139018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
140018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
141018338e5SZachary Turner F.Allocator);
142018338e5SZachary Turner BinaryStreamReader R(*S);
143018338e5SZachary Turner StringRef Str;
144018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str, 10), Succeeded());
145018338e5SZachary Turner EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
146018338e5SZachary Turner EXPECT_EQ(10U, F.Allocator.getBytesAllocated());
147018338e5SZachary Turner }
148018338e5SZachary Turner
149018338e5SZachary Turner // Test that an out of bounds read which doesn't cross a block boundary
150018338e5SZachary Turner // fails and allocates no memory.
TEST(MappedBlockStreamTest,InvalidReadSizeNoBreak)151018338e5SZachary Turner TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
152018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
153018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
154018338e5SZachary Turner F.Allocator);
155018338e5SZachary Turner BinaryStreamReader R(*S);
156018338e5SZachary Turner StringRef Str;
157018338e5SZachary Turner
158018338e5SZachary Turner R.setOffset(10);
159018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Failed());
160018338e5SZachary Turner EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
161018338e5SZachary Turner }
162018338e5SZachary Turner
163018338e5SZachary Turner // Test that an out of bounds read which crosses a contiguous block boundary
164018338e5SZachary Turner // fails and allocates no memory.
TEST(MappedBlockStreamTest,InvalidReadSizeContiguousBreak)165018338e5SZachary Turner TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
166018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
167018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
168018338e5SZachary Turner F.Allocator);
169018338e5SZachary Turner BinaryStreamReader R(*S);
170018338e5SZachary Turner StringRef Str;
171018338e5SZachary Turner
172018338e5SZachary Turner R.setOffset(6);
173018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str, 5), Failed());
174018338e5SZachary Turner EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
175018338e5SZachary Turner }
176018338e5SZachary Turner
177018338e5SZachary Turner // Test that an out of bounds read which crosses a discontiguous block
178018338e5SZachary Turner // boundary fails and allocates no memory.
TEST(MappedBlockStreamTest,InvalidReadSizeNonContiguousBreak)179018338e5SZachary Turner TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
180018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
181018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
182018338e5SZachary Turner F.Allocator);
183018338e5SZachary Turner BinaryStreamReader R(*S);
184018338e5SZachary Turner StringRef Str;
185018338e5SZachary Turner
186018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str, 11), Failed());
187018338e5SZachary Turner EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
188018338e5SZachary Turner }
189018338e5SZachary Turner
190018338e5SZachary Turner // Tests that a read which is entirely contained within a single block but
191018338e5SZachary Turner // beyond the end of a StreamRef fails.
TEST(MappedBlockStreamTest,ZeroCopyReadNoBreak)192018338e5SZachary Turner TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
193018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
194018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
195018338e5SZachary Turner F.Allocator);
196018338e5SZachary Turner BinaryStreamReader R(*S);
197018338e5SZachary Turner StringRef Str;
198018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded());
199018338e5SZachary Turner EXPECT_EQ(Str, StringRef("A"));
200018338e5SZachary Turner EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
201018338e5SZachary Turner }
202018338e5SZachary Turner
203018338e5SZachary Turner // Tests that a read which is not aligned on the same boundary as a previous
204018338e5SZachary Turner // cached request, but which is known to overlap that request, shares the
205018338e5SZachary Turner // previous allocation.
TEST(MappedBlockStreamTest,UnalignedOverlappingRead)206018338e5SZachary Turner TEST(MappedBlockStreamTest, UnalignedOverlappingRead) {
207018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
208018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
209018338e5SZachary Turner F.Allocator);
210018338e5SZachary Turner BinaryStreamReader R(*S);
211018338e5SZachary Turner StringRef Str1;
212018338e5SZachary Turner StringRef Str2;
213018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str1, 7), Succeeded());
214018338e5SZachary Turner EXPECT_EQ(Str1, StringRef("ABCDEFG"));
215018338e5SZachary Turner EXPECT_EQ(7U, F.Allocator.getBytesAllocated());
216018338e5SZachary Turner
217018338e5SZachary Turner R.setOffset(2);
218018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str2, 3), Succeeded());
219018338e5SZachary Turner EXPECT_EQ(Str2, StringRef("CDE"));
220018338e5SZachary Turner EXPECT_EQ(Str1.data() + 2, Str2.data());
221018338e5SZachary Turner EXPECT_EQ(7U, F.Allocator.getBytesAllocated());
222018338e5SZachary Turner }
223018338e5SZachary Turner
224018338e5SZachary Turner // Tests that a read which is not aligned on the same boundary as a previous
225018338e5SZachary Turner // cached request, but which only partially overlaps a previous cached request,
226018338e5SZachary Turner // still works correctly and allocates again from the shared pool.
TEST(MappedBlockStreamTest,UnalignedOverlappingReadFail)227018338e5SZachary Turner TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) {
228018338e5SZachary Turner DiscontiguousStream F(BlocksAry, DataAry);
229018338e5SZachary Turner auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
230018338e5SZachary Turner F.Allocator);
231018338e5SZachary Turner BinaryStreamReader R(*S);
232018338e5SZachary Turner StringRef Str1;
233018338e5SZachary Turner StringRef Str2;
234018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str1, 6), Succeeded());
235018338e5SZachary Turner EXPECT_EQ(Str1, StringRef("ABCDEF"));
236018338e5SZachary Turner EXPECT_EQ(6U, F.Allocator.getBytesAllocated());
237018338e5SZachary Turner
238018338e5SZachary Turner R.setOffset(4);
239018338e5SZachary Turner EXPECT_THAT_ERROR(R.readFixedString(Str2, 4), Succeeded());
240018338e5SZachary Turner EXPECT_EQ(Str2, StringRef("EFGH"));
241018338e5SZachary Turner EXPECT_EQ(10U, F.Allocator.getBytesAllocated());
242018338e5SZachary Turner }
243018338e5SZachary Turner
TEST(MappedBlockStreamTest,WriteBeyondEndOfStream)244018338e5SZachary Turner TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) {
245018338e5SZachary Turner static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
246018338e5SZachary Turner static uint8_t LargeBuffer[] = {'0', '1', '2', '3', '4', '5',
247018338e5SZachary Turner '6', '7', '8', '9', 'A'};
248018338e5SZachary Turner static uint8_t SmallBuffer[] = {'0', '1', '2'};
249018338e5SZachary Turner static_assert(sizeof(LargeBuffer) > sizeof(Data),
250018338e5SZachary Turner "LargeBuffer is not big enough");
251018338e5SZachary Turner
252018338e5SZachary Turner DiscontiguousStream F(BlocksAry, Data);
253018338e5SZachary Turner auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
254018338e5SZachary Turner F, F.Allocator);
255018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(LargeBuffer)), Failed());
256018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(SmallBuffer)),
257018338e5SZachary Turner Succeeded());
258018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(7, ArrayRef<uint8_t>(SmallBuffer)),
259018338e5SZachary Turner Succeeded());
260018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(8, ArrayRef<uint8_t>(SmallBuffer)), Failed());
261018338e5SZachary Turner }
262018338e5SZachary Turner
TEST(MappedBlockStreamTest,TestWriteBytesNoBreakBoundary)263018338e5SZachary Turner TEST(MappedBlockStreamTest, TestWriteBytesNoBreakBoundary) {
264018338e5SZachary Turner static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
265018338e5SZachary Turner DiscontiguousStream F(BlocksAry, Data);
266018338e5SZachary Turner auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
267018338e5SZachary Turner F, F.Allocator);
268018338e5SZachary Turner ArrayRef<uint8_t> Buffer;
269018338e5SZachary Turner
270018338e5SZachary Turner EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
271018338e5SZachary Turner EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
272018338e5SZachary Turner EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
273018338e5SZachary Turner EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
274018338e5SZachary Turner
275018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('J')), Succeeded());
276018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('A')), Succeeded());
277018338e5SZachary Turner
278018338e5SZachary Turner EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
279018338e5SZachary Turner EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
280018338e5SZachary Turner EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
281018338e5SZachary Turner EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
282018338e5SZachary Turner
283018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('A')), Succeeded());
284018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('J')), Succeeded());
285018338e5SZachary Turner
286018338e5SZachary Turner EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
287018338e5SZachary Turner EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
288018338e5SZachary Turner EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
289018338e5SZachary Turner EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
290018338e5SZachary Turner }
291018338e5SZachary Turner
TEST(MappedBlockStreamTest,TestWriteBytesBreakBoundary)292018338e5SZachary Turner TEST(MappedBlockStreamTest, TestWriteBytesBreakBoundary) {
293018338e5SZachary Turner static uint8_t Data[] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
294018338e5SZachary Turner static uint8_t TestData[] = {'T', 'E', 'S', 'T', 'I', 'N', 'G', '.'};
295018338e5SZachary Turner static uint8_t Expected[] = {'T', 'E', 'S', 'N', 'I',
296018338e5SZachary Turner 'T', 'G', '.', '0', '0'};
297018338e5SZachary Turner
298018338e5SZachary Turner DiscontiguousStream F(BlocksAry, Data);
299018338e5SZachary Turner auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
300018338e5SZachary Turner F, F.Allocator);
301018338e5SZachary Turner ArrayRef<uint8_t> Buffer;
302018338e5SZachary Turner
303018338e5SZachary Turner EXPECT_THAT_ERROR(S->writeBytes(0, TestData), Succeeded());
304018338e5SZachary Turner // First just compare the memory, then compare the result of reading the
305018338e5SZachary Turner // string out.
306018338e5SZachary Turner EXPECT_EQ(ArrayRef<uint8_t>(Data), ArrayRef<uint8_t>(Expected));
307018338e5SZachary Turner
308018338e5SZachary Turner EXPECT_THAT_ERROR(S->readBytes(0, 8, Buffer), Succeeded());
309018338e5SZachary Turner EXPECT_EQ(Buffer, ArrayRef<uint8_t>(TestData));
310018338e5SZachary Turner }
311018338e5SZachary Turner
TEST(MappedBlockStreamTest,TestWriteThenRead)312018338e5SZachary Turner TEST(MappedBlockStreamTest, TestWriteThenRead) {
313018338e5SZachary Turner std::vector<uint8_t> DataBytes(10);
314018338e5SZachary Turner MutableArrayRef<uint8_t> Data(DataBytes);
315018338e5SZachary Turner const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
316018338e5SZachary Turner
317018338e5SZachary Turner DiscontiguousStream F(Blocks, Data);
318018338e5SZachary Turner auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
319018338e5SZachary Turner F, F.Allocator);
320018338e5SZachary Turner
321018338e5SZachary Turner enum class MyEnum : uint32_t { Val1 = 2908234, Val2 = 120891234 };
322018338e5SZachary Turner using support::ulittle32_t;
323018338e5SZachary Turner
324018338e5SZachary Turner uint16_t u16[] = {31468, 0};
325018338e5SZachary Turner uint32_t u32[] = {890723408, 0};
326018338e5SZachary Turner MyEnum Enum[] = {MyEnum::Val1, MyEnum::Val2};
327018338e5SZachary Turner StringRef ZStr[] = {"Zero Str", ""};
328018338e5SZachary Turner StringRef FStr[] = {"Fixed Str", ""};
329018338e5SZachary Turner uint8_t byteArray0[] = {'1', '2'};
330018338e5SZachary Turner uint8_t byteArray1[] = {'0', '0'};
331018338e5SZachary Turner ArrayRef<uint8_t> byteArrayRef0(byteArray0);
332018338e5SZachary Turner ArrayRef<uint8_t> byteArrayRef1(byteArray1);
333018338e5SZachary Turner ArrayRef<uint8_t> byteArray[] = {byteArrayRef0, byteArrayRef1};
334018338e5SZachary Turner uint32_t intArr0[] = {890723408, 29082234};
335018338e5SZachary Turner uint32_t intArr1[] = {890723408, 29082234};
336018338e5SZachary Turner ArrayRef<uint32_t> intArray[] = {intArr0, intArr1};
337018338e5SZachary Turner
338018338e5SZachary Turner BinaryStreamReader Reader(*S);
339018338e5SZachary Turner BinaryStreamWriter Writer(*S);
340018338e5SZachary Turner EXPECT_THAT_ERROR(Writer.writeInteger(u16[0]), Succeeded());
341018338e5SZachary Turner EXPECT_THAT_ERROR(Reader.readInteger(u16[1]), Succeeded());
342018338e5SZachary Turner EXPECT_EQ(u16[0], u16[1]);
343018338e5SZachary Turner EXPECT_EQ(std::vector<uint8_t>({0, 0x7A, 0xEC, 0, 0, 0, 0, 0, 0, 0}),
344018338e5SZachary Turner DataBytes);
345018338e5SZachary Turner
346018338e5SZachary Turner Reader.setOffset(0);
347018338e5SZachary Turner Writer.setOffset(0);
348018338e5SZachary Turner ::memset(DataBytes.data(), 0, 10);
349018338e5SZachary Turner EXPECT_THAT_ERROR(Writer.writeInteger(u32[0]), Succeeded());
350018338e5SZachary Turner EXPECT_THAT_ERROR(Reader.readInteger(u32[1]), Succeeded());
351018338e5SZachary Turner EXPECT_EQ(u32[0], u32[1]);
352018338e5SZachary Turner EXPECT_EQ(std::vector<uint8_t>({0x17, 0x5C, 0x50, 0, 0, 0, 0x35, 0, 0, 0}),
353018338e5SZachary Turner DataBytes);
354018338e5SZachary Turner
355018338e5SZachary Turner Reader.setOffset(0);
356018338e5SZachary Turner Writer.setOffset(0);
357018338e5SZachary Turner ::memset(DataBytes.data(), 0, 10);
358018338e5SZachary Turner EXPECT_THAT_ERROR(Writer.writeEnum(Enum[0]), Succeeded());
359018338e5SZachary Turner EXPECT_THAT_ERROR(Reader.readEnum(Enum[1]), Succeeded());
360018338e5SZachary Turner EXPECT_EQ(Enum[0], Enum[1]);
361018338e5SZachary Turner EXPECT_EQ(std::vector<uint8_t>({0x2C, 0x60, 0x4A, 0, 0, 0, 0, 0, 0, 0}),
362018338e5SZachary Turner DataBytes);
363018338e5SZachary Turner
364018338e5SZachary Turner Reader.setOffset(0);
365018338e5SZachary Turner Writer.setOffset(0);
366018338e5SZachary Turner ::memset(DataBytes.data(), 0, 10);
367018338e5SZachary Turner EXPECT_THAT_ERROR(Writer.writeCString(ZStr[0]), Succeeded());
368018338e5SZachary Turner EXPECT_THAT_ERROR(Reader.readCString(ZStr[1]), Succeeded());
369018338e5SZachary Turner EXPECT_EQ(ZStr[0], ZStr[1]);
370018338e5SZachary Turner EXPECT_EQ(
371018338e5SZachary Turner std::vector<uint8_t>({'r', 'e', 'Z', ' ', 'S', 't', 'o', 'r', 0, 0}),
372018338e5SZachary Turner DataBytes);
373018338e5SZachary Turner
374018338e5SZachary Turner Reader.setOffset(0);
375018338e5SZachary Turner Writer.setOffset(0);
376018338e5SZachary Turner ::memset(DataBytes.data(), 0, 10);
377018338e5SZachary Turner EXPECT_THAT_ERROR(Writer.writeFixedString(FStr[0]), Succeeded());
378018338e5SZachary Turner EXPECT_THAT_ERROR(Reader.readFixedString(FStr[1], FStr[0].size()),
379018338e5SZachary Turner Succeeded());
380018338e5SZachary Turner EXPECT_EQ(FStr[0], FStr[1]);
381018338e5SZachary Turner EXPECT_EQ(
382018338e5SZachary Turner std::vector<uint8_t>({'x', 'i', 'F', 'd', ' ', 'S', 'e', 't', 0, 'r'}),
383018338e5SZachary Turner DataBytes);
384018338e5SZachary Turner
385018338e5SZachary Turner Reader.setOffset(0);
386018338e5SZachary Turner Writer.setOffset(0);
387018338e5SZachary Turner ::memset(DataBytes.data(), 0, 10);
388018338e5SZachary Turner EXPECT_THAT_ERROR(Writer.writeArray(byteArray[0]), Succeeded());
389018338e5SZachary Turner EXPECT_THAT_ERROR(Reader.readArray(byteArray[1], byteArray[0].size()),
390018338e5SZachary Turner Succeeded());
391018338e5SZachary Turner EXPECT_EQ(byteArray[0], byteArray[1]);
392018338e5SZachary Turner EXPECT_EQ(std::vector<uint8_t>({0, 0x32, 0x31, 0, 0, 0, 0, 0, 0, 0}),
393018338e5SZachary Turner DataBytes);
394018338e5SZachary Turner
395018338e5SZachary Turner Reader.setOffset(0);
396018338e5SZachary Turner Writer.setOffset(0);
397018338e5SZachary Turner ::memset(DataBytes.data(), 0, 10);
398018338e5SZachary Turner EXPECT_THAT_ERROR(Writer.writeArray(intArray[0]), Succeeded());
399018338e5SZachary Turner EXPECT_THAT_ERROR(Reader.readArray(intArray[1], intArray[0].size()),
400018338e5SZachary Turner Succeeded());
401018338e5SZachary Turner EXPECT_EQ(intArray[0], intArray[1]);
402018338e5SZachary Turner }
403018338e5SZachary Turner
TEST(MappedBlockStreamTest,TestWriteContiguousStreamRef)404018338e5SZachary Turner TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) {
405018338e5SZachary Turner std::vector<uint8_t> DestDataBytes(10);
406018338e5SZachary Turner MutableArrayRef<uint8_t> DestData(DestDataBytes);
407018338e5SZachary Turner const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
408018338e5SZachary Turner
409018338e5SZachary Turner std::vector<uint8_t> SrcDataBytes(10);
410018338e5SZachary Turner MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
411018338e5SZachary Turner
412018338e5SZachary Turner DiscontiguousStream F(DestBlocks, DestData);
413018338e5SZachary Turner auto DestStream = WritableMappedBlockStream::createStream(
414018338e5SZachary Turner F.block_size(), F.layout(), F, F.Allocator);
415018338e5SZachary Turner
416018338e5SZachary Turner // First write "Test Str" into the source stream.
417*02f67c09SKazu Hirata MutableBinaryByteStream SourceStream(SrcData, llvm::endianness::little);
418018338e5SZachary Turner BinaryStreamWriter SourceWriter(SourceStream);
419018338e5SZachary Turner EXPECT_THAT_ERROR(SourceWriter.writeCString("Test Str"), Succeeded());
420018338e5SZachary Turner EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
421018338e5SZachary Turner {'T', 'e', 's', 't', ' ', 'S', 't', 'r', 0, 0}));
422018338e5SZachary Turner
423018338e5SZachary Turner // Then write the source stream into the dest stream.
424018338e5SZachary Turner BinaryStreamWriter DestWriter(*DestStream);
425018338e5SZachary Turner EXPECT_THAT_ERROR(DestWriter.writeStreamRef(SourceStream), Succeeded());
426018338e5SZachary Turner EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
427018338e5SZachary Turner {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
428018338e5SZachary Turner
429018338e5SZachary Turner // Then read the string back out of the dest stream.
430018338e5SZachary Turner StringRef Result;
431018338e5SZachary Turner BinaryStreamReader DestReader(*DestStream);
432018338e5SZachary Turner EXPECT_THAT_ERROR(DestReader.readCString(Result), Succeeded());
433018338e5SZachary Turner EXPECT_EQ(Result, "Test Str");
434018338e5SZachary Turner }
435018338e5SZachary Turner
TEST(MappedBlockStreamTest,TestWriteDiscontiguousStreamRef)436018338e5SZachary Turner TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) {
437018338e5SZachary Turner std::vector<uint8_t> DestDataBytes(10);
438018338e5SZachary Turner MutableArrayRef<uint8_t> DestData(DestDataBytes);
439018338e5SZachary Turner const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
440018338e5SZachary Turner
441018338e5SZachary Turner std::vector<uint8_t> SrcDataBytes(10);
442018338e5SZachary Turner MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
443018338e5SZachary Turner const uint32_t SrcBlocks[] = {1, 0, 6, 3, 4, 5, 2, 7, 8, 9};
444018338e5SZachary Turner
445018338e5SZachary Turner DiscontiguousStream DestF(DestBlocks, DestData);
446018338e5SZachary Turner DiscontiguousStream SrcF(SrcBlocks, SrcData);
447018338e5SZachary Turner
448018338e5SZachary Turner auto Dest = WritableMappedBlockStream::createStream(
449018338e5SZachary Turner DestF.block_size(), DestF.layout(), DestF, DestF.Allocator);
450018338e5SZachary Turner auto Src = WritableMappedBlockStream::createStream(
451018338e5SZachary Turner SrcF.block_size(), SrcF.layout(), SrcF, SrcF.Allocator);
452018338e5SZachary Turner
453018338e5SZachary Turner // First write "Test Str" into the source stream.
454018338e5SZachary Turner BinaryStreamWriter SourceWriter(*Src);
455018338e5SZachary Turner EXPECT_THAT_ERROR(SourceWriter.writeCString("Test Str"), Succeeded());
456018338e5SZachary Turner EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
457018338e5SZachary Turner {'e', 'T', 't', 't', ' ', 'S', 's', 'r', 0, 0}));
458018338e5SZachary Turner
459018338e5SZachary Turner // Then write the source stream into the dest stream.
460018338e5SZachary Turner BinaryStreamWriter DestWriter(*Dest);
461018338e5SZachary Turner EXPECT_THAT_ERROR(DestWriter.writeStreamRef(*Src), Succeeded());
462018338e5SZachary Turner EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
463018338e5SZachary Turner {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
464018338e5SZachary Turner
465018338e5SZachary Turner // Then read the string back out of the dest stream.
466018338e5SZachary Turner StringRef Result;
467018338e5SZachary Turner BinaryStreamReader DestReader(*Dest);
468018338e5SZachary Turner EXPECT_THAT_ERROR(DestReader.readCString(Result), Succeeded());
469018338e5SZachary Turner EXPECT_EQ(Result, "Test Str");
470018338e5SZachary Turner }
471018338e5SZachary Turner
TEST(MappedBlockStreamTest,DataLivesAfterStreamDestruction)472018338e5SZachary Turner TEST(MappedBlockStreamTest, DataLivesAfterStreamDestruction) {
473018338e5SZachary Turner std::vector<uint8_t> DataBytes(10);
474018338e5SZachary Turner MutableArrayRef<uint8_t> Data(DataBytes);
475018338e5SZachary Turner const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
476018338e5SZachary Turner
477018338e5SZachary Turner StringRef Str[] = {"Zero Str", ""};
478018338e5SZachary Turner
479018338e5SZachary Turner DiscontiguousStream F(Blocks, Data);
480018338e5SZachary Turner {
481018338e5SZachary Turner auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
482018338e5SZachary Turner F, F.Allocator);
483018338e5SZachary Turner
484018338e5SZachary Turner BinaryStreamReader Reader(*S);
485018338e5SZachary Turner BinaryStreamWriter Writer(*S);
486018338e5SZachary Turner ::memset(DataBytes.data(), 0, 10);
487018338e5SZachary Turner EXPECT_THAT_ERROR(Writer.writeCString(Str[0]), Succeeded());
488018338e5SZachary Turner EXPECT_THAT_ERROR(Reader.readCString(Str[1]), Succeeded());
489018338e5SZachary Turner EXPECT_EQ(Str[0], Str[1]);
490018338e5SZachary Turner }
491018338e5SZachary Turner
492018338e5SZachary Turner EXPECT_EQ(Str[0], Str[1]);
493018338e5SZachary Turner }
4949fb9d71dSZachary Turner } // namespace
4959fb9d71dSZachary Turner
4969fb9d71dSZachary Turner MATCHER_P3(BlockIsFilledWith, Layout, BlockIndex, Byte, "succeeded") {
4979fb9d71dSZachary Turner uint64_t Offset = msf::blockToOffset(BlockIndex, Layout.SB->BlockSize);
49838818b60Sserge-sans-paille ArrayRef<uint8_t> BufferRef = ArrayRef(arg);
4999fb9d71dSZachary Turner BufferRef = BufferRef.slice(Offset, Layout.SB->BlockSize);
__anon328fc6c40202(uint8_t B) 5009fb9d71dSZachary Turner return llvm::all_of(BufferRef, [this](uint8_t B) { return B == Byte; });
5019fb9d71dSZachary Turner }
5029fb9d71dSZachary Turner
5039fb9d71dSZachary Turner namespace {
TEST(MappedBlockStreamTest,CreateFpmStream)5049fb9d71dSZachary Turner TEST(MappedBlockStreamTest, CreateFpmStream) {
5059fb9d71dSZachary Turner BumpPtrAllocator Allocator;
5069fb9d71dSZachary Turner SuperBlock SB;
5079fb9d71dSZachary Turner MSFLayout L;
5089fb9d71dSZachary Turner L.SB = &SB;
5099fb9d71dSZachary Turner
5109fb9d71dSZachary Turner SB.FreeBlockMapBlock = 1;
5119fb9d71dSZachary Turner SB.BlockSize = 4096;
5129fb9d71dSZachary Turner
5139fb9d71dSZachary Turner constexpr uint32_t NumFileBlocks = 4096 * 4;
5149fb9d71dSZachary Turner
5159fb9d71dSZachary Turner std::vector<uint8_t> MsfBuffer(NumFileBlocks * SB.BlockSize);
516b8885926SKazu Hirata MutableBinaryByteStream MsfStream(MsfBuffer, llvm::endianness::little);
5179fb9d71dSZachary Turner
5189fb9d71dSZachary Turner SB.NumBlocks = NumFileBlocks;
5199fb9d71dSZachary Turner auto FpmStream =
5209fb9d71dSZachary Turner WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator);
5219fb9d71dSZachary Turner // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
5229fb9d71dSZachary Turner // blocks. This translates to 1 FPM block.
5239fb9d71dSZachary Turner EXPECT_EQ(2048u, FpmStream->getLength());
5249fb9d71dSZachary Turner EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
5259fb9d71dSZachary Turner EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks[0]);
5269fb9d71dSZachary Turner // All blocks from FPM1 should be 1 initialized, and all blocks from FPM2
5279fb9d71dSZachary Turner // should be 0 initialized (since we requested the main FPM, not the alt FPM)
5289fb9d71dSZachary Turner for (int I = 0; I < 4; ++I) {
5299fb9d71dSZachary Turner EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0xFF));
5309fb9d71dSZachary Turner EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0));
5319fb9d71dSZachary Turner }
5329fb9d71dSZachary Turner
5339fb9d71dSZachary Turner ::memset(MsfBuffer.data(), 0, MsfBuffer.size());
5349fb9d71dSZachary Turner FpmStream =
5359fb9d71dSZachary Turner WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator, true);
5369fb9d71dSZachary Turner // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
5379fb9d71dSZachary Turner // blocks. This translates to 1 FPM block.
5389fb9d71dSZachary Turner EXPECT_EQ(2048u, FpmStream->getLength());
5399fb9d71dSZachary Turner EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
5409fb9d71dSZachary Turner EXPECT_EQ(2u, FpmStream->getStreamLayout().Blocks[0]);
5419fb9d71dSZachary Turner // All blocks from FPM2 should be 1 initialized, and all blocks from FPM1
5429fb9d71dSZachary Turner // should be 0 initialized (since we requested the alt FPM, not the main FPM)
5439fb9d71dSZachary Turner for (int I = 0; I < 4; ++I) {
5449fb9d71dSZachary Turner EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0));
5459fb9d71dSZachary Turner EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0xFF));
5469fb9d71dSZachary Turner }
5479fb9d71dSZachary Turner }
548018338e5SZachary Turner
549018338e5SZachary Turner } // end anonymous namespace
550