Files
acceptance-tests
data
debian
docs
external
Newtonsoft.Json
api-doc-tools
api-snapshot
aspnetwebstack
binary-reference-assemblies
bockbuild
boringssl
cecil
cecil-legacy
corefx
corert
helix-binaries
ikdasm
ikvm
illinker-test-assets
linker
llvm
bindings
cmake
docs
examples
include
lib
projects
resources
runtimes
scripts
test
tools
unittests
ADT
Analysis
AsmParser
BinaryFormat
Bitcode
CodeGen
DebugInfo
CodeView
DWARF
MSF
CMakeLists.txt
MSFBuilderTest.cpp
MSFCommonTest.cpp
MappedBlockStreamTest.cpp
PDB
CMakeLists.txt
ExecutionEngine
FuzzMutate
IR
LineEditor
Linker
MC
MI
Object
ObjectYAML
Option
ProfileData
Support
Target
Transforms
XRay
tools
CMakeLists.txt
utils
.arcconfig
.clang-format
.clang-tidy
.gitattributes
.gitignore
CMakeLists.txt
CODE_OWNERS.TXT
CREDITS.TXT
LICENSE.TXT
LLVMBuild.txt
README.txt
RELEASE_TESTERS.TXT
configure
llvm.spec.in
nuget-buildtasks
nunit-lite
roslyn-binaries
rx
xunit-binaries
how-to-bump-roslyn-binaries.md
ikvm-native
libgc
llvm
m4
man
mcs
mk
mono
msvc
po
runtime
samples
scripts
support
tools
COPYING.LIB
LICENSE
Makefile.am
Makefile.in
NEWS
README.md
acinclude.m4
aclocal.m4
autogen.sh
code_of_conduct.md
compile
config.guess
config.h.in
config.rpath
config.sub
configure.REMOVED.git-id
configure.ac.REMOVED.git-id
depcomp
install-sh
ltmain.sh.REMOVED.git-id
missing
mkinstalldirs
mono-uninstalled.pc.in
test-driver
winconfig.h
linux-packaging-mono/external/llvm/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp
Xamarin Public Jenkins (auto-signing) 64ac736ec5 Imported Upstream version 6.0.0.172
Former-commit-id: f3cc9b82f3e5bd8f0fd3ebc098f789556b44e9cd
2019-04-12 14:10:50 +00:00

549 lines
21 KiB
C++

//===- llvm/unittest/DebugInfo/MSF/MappedBlockStreamTest.cpp --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::msf;
using namespace llvm::support;
namespace {
static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9};
static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'};
class DiscontiguousStream : public WritableBinaryStream {
public:
DiscontiguousStream(ArrayRef<uint32_t> Blocks, MutableArrayRef<uint8_t> Data)
: Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {}
uint32_t block_size() const { return 1; }
uint32_t block_count() const { return Blocks.size(); }
endianness getEndian() const override { return little; }
Error readBytes(uint32_t Offset, uint32_t Size,
ArrayRef<uint8_t> &Buffer) override {
if (auto EC = checkOffsetForRead(Offset, Size))
return EC;
Buffer = Data.slice(Offset, Size);
return Error::success();
}
Error readLongestContiguousChunk(uint32_t Offset,
ArrayRef<uint8_t> &Buffer) override {
if (auto EC = checkOffsetForRead(Offset, 1))
return EC;
Buffer = Data.drop_front(Offset);
return Error::success();
}
uint32_t getLength() override { return Data.size(); }
Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override {
if (auto EC = checkOffsetForWrite(Offset, SrcData.size()))
return EC;
::memcpy(&Data[Offset], SrcData.data(), SrcData.size());
return Error::success();
}
Error commit() override { return Error::success(); }
MSFStreamLayout layout() const {
return MSFStreamLayout{static_cast<uint32_t>(Data.size()), Blocks};
}
BumpPtrAllocator Allocator;
private:
std::vector<support::ulittle32_t> Blocks;
MutableArrayRef<uint8_t> Data;
};
TEST(MappedBlockStreamTest, NumBlocks) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
EXPECT_EQ(F.block_size(), S->getBlockSize());
EXPECT_EQ(F.layout().Blocks.size(), S->getNumBlocks());
}
// Tests that a read which is entirely contained within a single block works
// and does not allocate.
TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
BinaryStreamRef SR;
EXPECT_THAT_ERROR(R.readStreamRef(SR, 0U), Succeeded());
ArrayRef<uint8_t> Buffer;
EXPECT_THAT_ERROR(SR.readBytes(0U, 1U, Buffer), Failed());
EXPECT_THAT_ERROR(R.readStreamRef(SR, 1U), Succeeded());
EXPECT_THAT_ERROR(SR.readBytes(1U, 1U, Buffer), Failed());
}
// Tests that a read which outputs into a full destination buffer works and
// does not fail due to the length of the output buffer.
TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded());
EXPECT_EQ(Str, StringRef("A"));
EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Tests that a read which crosses a block boundary, but where the subsequent
// blocks are still contiguous in memory to the previous block works and does
// not allocate memory.
TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str;
EXPECT_THAT_ERROR(R.readFixedString(Str, 2), Succeeded());
EXPECT_EQ(Str, StringRef("AB"));
EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
R.setOffset(6);
EXPECT_THAT_ERROR(R.readFixedString(Str, 4), Succeeded());
EXPECT_EQ(Str, StringRef("GHIJ"));
EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Tests that a read which crosses a block boundary and cannot be referenced
// contiguously works and allocates only the precise amount of bytes
// requested.
TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str;
EXPECT_THAT_ERROR(R.readFixedString(Str, 10), Succeeded());
EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
EXPECT_EQ(10U, F.Allocator.getBytesAllocated());
}
// Test that an out of bounds read which doesn't cross a block boundary
// fails and allocates no memory.
TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str;
R.setOffset(10);
EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Failed());
EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Test that an out of bounds read which crosses a contiguous block boundary
// fails and allocates no memory.
TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str;
R.setOffset(6);
EXPECT_THAT_ERROR(R.readFixedString(Str, 5), Failed());
EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Test that an out of bounds read which crosses a discontiguous block
// boundary fails and allocates no memory.
TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str;
EXPECT_THAT_ERROR(R.readFixedString(Str, 11), Failed());
EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Tests that a read which is entirely contained within a single block but
// beyond the end of a StreamRef fails.
TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str;
EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded());
EXPECT_EQ(Str, StringRef("A"));
EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Tests that a read which is not aligned on the same boundary as a previous
// cached request, but which is known to overlap that request, shares the
// previous allocation.
TEST(MappedBlockStreamTest, UnalignedOverlappingRead) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str1;
StringRef Str2;
EXPECT_THAT_ERROR(R.readFixedString(Str1, 7), Succeeded());
EXPECT_EQ(Str1, StringRef("ABCDEFG"));
EXPECT_EQ(7U, F.Allocator.getBytesAllocated());
R.setOffset(2);
EXPECT_THAT_ERROR(R.readFixedString(Str2, 3), Succeeded());
EXPECT_EQ(Str2, StringRef("CDE"));
EXPECT_EQ(Str1.data() + 2, Str2.data());
EXPECT_EQ(7U, F.Allocator.getBytesAllocated());
}
// Tests that a read which is not aligned on the same boundary as a previous
// cached request, but which only partially overlaps a previous cached request,
// still works correctly and allocates again from the shared pool.
TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F,
F.Allocator);
BinaryStreamReader R(*S);
StringRef Str1;
StringRef Str2;
EXPECT_THAT_ERROR(R.readFixedString(Str1, 6), Succeeded());
EXPECT_EQ(Str1, StringRef("ABCDEF"));
EXPECT_EQ(6U, F.Allocator.getBytesAllocated());
R.setOffset(4);
EXPECT_THAT_ERROR(R.readFixedString(Str2, 4), Succeeded());
EXPECT_EQ(Str2, StringRef("EFGH"));
EXPECT_EQ(10U, F.Allocator.getBytesAllocated());
}
TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) {
static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
static uint8_t LargeBuffer[] = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A'};
static uint8_t SmallBuffer[] = {'0', '1', '2'};
static_assert(sizeof(LargeBuffer) > sizeof(Data),
"LargeBuffer is not big enough");
DiscontiguousStream F(BlocksAry, Data);
auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
F, F.Allocator);
EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(LargeBuffer)), Failed());
EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(SmallBuffer)),
Succeeded());
EXPECT_THAT_ERROR(S->writeBytes(7, ArrayRef<uint8_t>(SmallBuffer)),
Succeeded());
EXPECT_THAT_ERROR(S->writeBytes(8, ArrayRef<uint8_t>(SmallBuffer)), Failed());
}
TEST(MappedBlockStreamTest, TestWriteBytesNoBreakBoundary) {
static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
DiscontiguousStream F(BlocksAry, Data);
auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
F, F.Allocator);
ArrayRef<uint8_t> Buffer;
EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('J')), Succeeded());
EXPECT_THAT_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('A')), Succeeded());
EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('A')), Succeeded());
EXPECT_THAT_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('J')), Succeeded());
EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded());
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded());
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
}
TEST(MappedBlockStreamTest, TestWriteBytesBreakBoundary) {
static uint8_t Data[] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
static uint8_t TestData[] = {'T', 'E', 'S', 'T', 'I', 'N', 'G', '.'};
static uint8_t Expected[] = {'T', 'E', 'S', 'N', 'I',
'T', 'G', '.', '0', '0'};
DiscontiguousStream F(BlocksAry, Data);
auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
F, F.Allocator);
ArrayRef<uint8_t> Buffer;
EXPECT_THAT_ERROR(S->writeBytes(0, TestData), Succeeded());
// First just compare the memory, then compare the result of reading the
// string out.
EXPECT_EQ(ArrayRef<uint8_t>(Data), ArrayRef<uint8_t>(Expected));
EXPECT_THAT_ERROR(S->readBytes(0, 8, Buffer), Succeeded());
EXPECT_EQ(Buffer, ArrayRef<uint8_t>(TestData));
}
TEST(MappedBlockStreamTest, TestWriteThenRead) {
std::vector<uint8_t> DataBytes(10);
MutableArrayRef<uint8_t> Data(DataBytes);
const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
DiscontiguousStream F(Blocks, Data);
auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
F, F.Allocator);
enum class MyEnum : uint32_t { Val1 = 2908234, Val2 = 120891234 };
using support::ulittle32_t;
uint16_t u16[] = {31468, 0};
uint32_t u32[] = {890723408, 0};
MyEnum Enum[] = {MyEnum::Val1, MyEnum::Val2};
StringRef ZStr[] = {"Zero Str", ""};
StringRef FStr[] = {"Fixed Str", ""};
uint8_t byteArray0[] = {'1', '2'};
uint8_t byteArray1[] = {'0', '0'};
ArrayRef<uint8_t> byteArrayRef0(byteArray0);
ArrayRef<uint8_t> byteArrayRef1(byteArray1);
ArrayRef<uint8_t> byteArray[] = {byteArrayRef0, byteArrayRef1};
uint32_t intArr0[] = {890723408, 29082234};
uint32_t intArr1[] = {890723408, 29082234};
ArrayRef<uint32_t> intArray[] = {intArr0, intArr1};
BinaryStreamReader Reader(*S);
BinaryStreamWriter Writer(*S);
EXPECT_THAT_ERROR(Writer.writeInteger(u16[0]), Succeeded());
EXPECT_THAT_ERROR(Reader.readInteger(u16[1]), Succeeded());
EXPECT_EQ(u16[0], u16[1]);
EXPECT_EQ(std::vector<uint8_t>({0, 0x7A, 0xEC, 0, 0, 0, 0, 0, 0, 0}),
DataBytes);
Reader.setOffset(0);
Writer.setOffset(0);
::memset(DataBytes.data(), 0, 10);
EXPECT_THAT_ERROR(Writer.writeInteger(u32[0]), Succeeded());
EXPECT_THAT_ERROR(Reader.readInteger(u32[1]), Succeeded());
EXPECT_EQ(u32[0], u32[1]);
EXPECT_EQ(std::vector<uint8_t>({0x17, 0x5C, 0x50, 0, 0, 0, 0x35, 0, 0, 0}),
DataBytes);
Reader.setOffset(0);
Writer.setOffset(0);
::memset(DataBytes.data(), 0, 10);
EXPECT_THAT_ERROR(Writer.writeEnum(Enum[0]), Succeeded());
EXPECT_THAT_ERROR(Reader.readEnum(Enum[1]), Succeeded());
EXPECT_EQ(Enum[0], Enum[1]);
EXPECT_EQ(std::vector<uint8_t>({0x2C, 0x60, 0x4A, 0, 0, 0, 0, 0, 0, 0}),
DataBytes);
Reader.setOffset(0);
Writer.setOffset(0);
::memset(DataBytes.data(), 0, 10);
EXPECT_THAT_ERROR(Writer.writeCString(ZStr[0]), Succeeded());
EXPECT_THAT_ERROR(Reader.readCString(ZStr[1]), Succeeded());
EXPECT_EQ(ZStr[0], ZStr[1]);
EXPECT_EQ(
std::vector<uint8_t>({'r', 'e', 'Z', ' ', 'S', 't', 'o', 'r', 0, 0}),
DataBytes);
Reader.setOffset(0);
Writer.setOffset(0);
::memset(DataBytes.data(), 0, 10);
EXPECT_THAT_ERROR(Writer.writeFixedString(FStr[0]), Succeeded());
EXPECT_THAT_ERROR(Reader.readFixedString(FStr[1], FStr[0].size()),
Succeeded());
EXPECT_EQ(FStr[0], FStr[1]);
EXPECT_EQ(
std::vector<uint8_t>({'x', 'i', 'F', 'd', ' ', 'S', 'e', 't', 0, 'r'}),
DataBytes);
Reader.setOffset(0);
Writer.setOffset(0);
::memset(DataBytes.data(), 0, 10);
EXPECT_THAT_ERROR(Writer.writeArray(byteArray[0]), Succeeded());
EXPECT_THAT_ERROR(Reader.readArray(byteArray[1], byteArray[0].size()),
Succeeded());
EXPECT_EQ(byteArray[0], byteArray[1]);
EXPECT_EQ(std::vector<uint8_t>({0, 0x32, 0x31, 0, 0, 0, 0, 0, 0, 0}),
DataBytes);
Reader.setOffset(0);
Writer.setOffset(0);
::memset(DataBytes.data(), 0, 10);
EXPECT_THAT_ERROR(Writer.writeArray(intArray[0]), Succeeded());
EXPECT_THAT_ERROR(Reader.readArray(intArray[1], intArray[0].size()),
Succeeded());
EXPECT_EQ(intArray[0], intArray[1]);
}
TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) {
std::vector<uint8_t> DestDataBytes(10);
MutableArrayRef<uint8_t> DestData(DestDataBytes);
const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
std::vector<uint8_t> SrcDataBytes(10);
MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
DiscontiguousStream F(DestBlocks, DestData);
auto DestStream = WritableMappedBlockStream::createStream(
F.block_size(), F.layout(), F, F.Allocator);
// First write "Test Str" into the source stream.
MutableBinaryByteStream SourceStream(SrcData, little);
BinaryStreamWriter SourceWriter(SourceStream);
EXPECT_THAT_ERROR(SourceWriter.writeCString("Test Str"), Succeeded());
EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
{'T', 'e', 's', 't', ' ', 'S', 't', 'r', 0, 0}));
// Then write the source stream into the dest stream.
BinaryStreamWriter DestWriter(*DestStream);
EXPECT_THAT_ERROR(DestWriter.writeStreamRef(SourceStream), Succeeded());
EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
{'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
// Then read the string back out of the dest stream.
StringRef Result;
BinaryStreamReader DestReader(*DestStream);
EXPECT_THAT_ERROR(DestReader.readCString(Result), Succeeded());
EXPECT_EQ(Result, "Test Str");
}
TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) {
std::vector<uint8_t> DestDataBytes(10);
MutableArrayRef<uint8_t> DestData(DestDataBytes);
const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
std::vector<uint8_t> SrcDataBytes(10);
MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
const uint32_t SrcBlocks[] = {1, 0, 6, 3, 4, 5, 2, 7, 8, 9};
DiscontiguousStream DestF(DestBlocks, DestData);
DiscontiguousStream SrcF(SrcBlocks, SrcData);
auto Dest = WritableMappedBlockStream::createStream(
DestF.block_size(), DestF.layout(), DestF, DestF.Allocator);
auto Src = WritableMappedBlockStream::createStream(
SrcF.block_size(), SrcF.layout(), SrcF, SrcF.Allocator);
// First write "Test Str" into the source stream.
BinaryStreamWriter SourceWriter(*Src);
EXPECT_THAT_ERROR(SourceWriter.writeCString("Test Str"), Succeeded());
EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
{'e', 'T', 't', 't', ' ', 'S', 's', 'r', 0, 0}));
// Then write the source stream into the dest stream.
BinaryStreamWriter DestWriter(*Dest);
EXPECT_THAT_ERROR(DestWriter.writeStreamRef(*Src), Succeeded());
EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
{'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
// Then read the string back out of the dest stream.
StringRef Result;
BinaryStreamReader DestReader(*Dest);
EXPECT_THAT_ERROR(DestReader.readCString(Result), Succeeded());
EXPECT_EQ(Result, "Test Str");
}
TEST(MappedBlockStreamTest, DataLivesAfterStreamDestruction) {
std::vector<uint8_t> DataBytes(10);
MutableArrayRef<uint8_t> Data(DataBytes);
const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
StringRef Str[] = {"Zero Str", ""};
DiscontiguousStream F(Blocks, Data);
{
auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
F, F.Allocator);
BinaryStreamReader Reader(*S);
BinaryStreamWriter Writer(*S);
::memset(DataBytes.data(), 0, 10);
EXPECT_THAT_ERROR(Writer.writeCString(Str[0]), Succeeded());
EXPECT_THAT_ERROR(Reader.readCString(Str[1]), Succeeded());
EXPECT_EQ(Str[0], Str[1]);
}
EXPECT_EQ(Str[0], Str[1]);
}
} // namespace
MATCHER_P3(BlockIsFilledWith, Layout, BlockIndex, Byte, "succeeded") {
uint64_t Offset = msf::blockToOffset(BlockIndex, Layout.SB->BlockSize);
ArrayRef<uint8_t> BufferRef = makeArrayRef(arg);
BufferRef = BufferRef.slice(Offset, Layout.SB->BlockSize);
return llvm::all_of(BufferRef, [this](uint8_t B) { return B == Byte; });
}
namespace {
TEST(MappedBlockStreamTest, CreateFpmStream) {
BumpPtrAllocator Allocator;
SuperBlock SB;
MSFLayout L;
L.SB = &SB;
SB.FreeBlockMapBlock = 1;
SB.BlockSize = 4096;
constexpr uint32_t NumFileBlocks = 4096 * 4;
std::vector<uint8_t> MsfBuffer(NumFileBlocks * SB.BlockSize);
MutableBinaryByteStream MsfStream(MsfBuffer, llvm::support::little);
SB.NumBlocks = NumFileBlocks;
auto FpmStream =
WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator);
// 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
// blocks. This translates to 1 FPM block.
EXPECT_EQ(2048u, FpmStream->getLength());
EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks[0]);
// All blocks from FPM1 should be 1 initialized, and all blocks from FPM2
// should be 0 initialized (since we requested the main FPM, not the alt FPM)
for (int I = 0; I < 4; ++I) {
EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0xFF));
EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0));
}
::memset(MsfBuffer.data(), 0, MsfBuffer.size());
FpmStream =
WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator, true);
// 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
// blocks. This translates to 1 FPM block.
EXPECT_EQ(2048u, FpmStream->getLength());
EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
EXPECT_EQ(2u, FpmStream->getStreamLayout().Blocks[0]);
// All blocks from FPM2 should be 1 initialized, and all blocks from FPM1
// should be 0 initialized (since we requested the alt FPM, not the main FPM)
for (int I = 0; I < 4; ++I) {
EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0));
EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0xFF));
}
}
} // end anonymous namespace