forked from OSchip/llvm-project
Remove unittests/DebugInfo/PDB/BinaryStreamTest.cpp (from r296555)
It breaks the ToT UBSan bots: /Users/vk/Desktop/llvm/include/llvm/DebugInfo/MSF/BinaryStreamArray.h:246:12: runtime error: reference binding to misaligned address 0x7f925540939a for type 'const int', which requires 4 byte alignment 0x7f925540939a: note: pointer points here 05 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 70 98 50 06 01 00 ^ 0 DebugInfoPDBTests 0x0000000106263cbd llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 45 1 DebugInfoPDBTests 0x00000001062628ff llvm::sys::RunSignalHandlers() + 159 2 DebugInfoPDBTests 0x0000000106264593 SignalHandler(int) + 179 3 libsystem_platform.dylib 0x0000000107bb3fba _sigtramp + 26 4 libsystem_pthread.dylib 0x0000000107bd82c8 _pthread_keys + 9720 5 libsystem_c.dylib 0x0000000107947f83 abort + 127 6 libclang_rt.ubsan_osx_dynamic.dylib 0x0000000106bb5fc2 __sanitizer::Abort() + 66 7 DebugInfoPDBTests 0x000000010613f880 llvm::FixedStreamArrayIterator<int>::operator+=(long) + 0 8 DebugInfoPDBTests 0x000000010613f615 llvm::FixedStreamArrayIterator<int>::operator*() const + 37 9 DebugInfoPDBTests 0x000000010613f3cb std::__1::enable_if<__is_forward_iterator<llvm::FixedStreamArrayIterator<int> >::value, void>::type std::__1::vector<int, std::__1::allocator<int> >::__construct_at_end<llvm::FixedStreamArrayIterator<int> >(llvm::FixedStreamArrayIterator<int>, llvm::FixedStreamArrayIterator<int>, unsigned long) + 251 10 DebugInfoPDBTests 0x000000010613f292 std::__1::vector<int, std::__1::allocator<int> >::vector<llvm::FixedStreamArrayIterator<int> >(llvm::FixedStreamArrayIterator<int>, std::__1::enable_if<(__is_forward_iterator<llvm::FixedStreamArrayIterator<int> >::value) && (is_constructible<int, std::__1::iterator_traits<llvm::FixedStreamArrayIterator<int> >::reference>::value), llvm::FixedStreamArrayIterator<int> >::type) + 226 11 DebugInfoPDBTests 0x000000010613ddb7 std::__1::vector<int, std::__1::allocator<int> >::vector<llvm::FixedStreamArrayIterator<int> >(llvm::FixedStreamArrayIterator<int>, std::__1::enable_if<(__is_forward_iterator<llvm::FixedStreamArrayIterator<int> >::value) && (is_constructible<int, std::__1::iterator_traits<llvm::FixedStreamArrayIterator<int> >::reference>::value), llvm::FixedStreamArrayIterator<int> >::type) + 87 12 DebugInfoPDBTests 0x000000010613d4af (anonymous namespace)::BinaryStreamTest_StreamReaderIntegerArray_Test::TestBody() + 1279 13 DebugInfoPDBTests 0x00000001062780f3 testing::Test::Run() + 179 14 DebugInfoPDBTests 0x0000000106279594 testing::TestInfo::Run() + 308 15 DebugInfoPDBTests 0x000000010627a6a3 testing::TestCase::Run() + 307 16 DebugInfoPDBTests 0x00000001062849d4 testing::internal::UnitTestImpl::RunAllTests() + 756 17 DebugInfoPDBTests 0x0000000106284558 testing::UnitTest::Run() + 152 18 DebugInfoPDBTests 0x0000000106266fa5 main + 117 19 libdyld.dylib 0x00000001078506a5 start + 1 zsh: abort ./unittests/DebugInfo/PDB/DebugInfoPDBTests llvm-svn: 296641
This commit is contained in:
parent
1fa70d71f2
commit
b0baffc9a6
|
@ -1,700 +0,0 @@
|
|||
//===- llvm/unittest/Support/BinaryStreamTest.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/BinaryByteStream.h"
|
||||
#include "llvm/DebugInfo/MSF/BinaryItemStream.h"
|
||||
#include "llvm/DebugInfo/MSF/BinaryStreamArray.h"
|
||||
#include "llvm/DebugInfo/MSF/BinaryStreamReader.h"
|
||||
#include "llvm/DebugInfo/MSF/BinaryStreamRef.h"
|
||||
#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::support;
|
||||
|
||||
#define EXPECT_NO_ERROR(Err) \
|
||||
{ \
|
||||
auto E = Err; \
|
||||
EXPECT_FALSE(static_cast<bool>(E)); \
|
||||
if (E) \
|
||||
consumeError(std::move(E)); \
|
||||
}
|
||||
|
||||
#define ASSERT_NO_ERROR(Err) \
|
||||
{ \
|
||||
auto E = Err; \
|
||||
ASSERT_FALSE(static_cast<bool>(E)); \
|
||||
if (E) \
|
||||
consumeError(std::move(E)); \
|
||||
}
|
||||
|
||||
#define EXPECT_ERROR(Err) \
|
||||
{ \
|
||||
auto E = Err; \
|
||||
EXPECT_TRUE(static_cast<bool>(E)); \
|
||||
if (E) \
|
||||
consumeError(std::move(E)); \
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class DiscontiguousStream : public WritableBinaryStream {
|
||||
public:
|
||||
DiscontiguousStream(MutableArrayRef<uint8_t> Data, endianness Endian)
|
||||
: Data(Data), PartitionIndex(Data.size() / 2), Endian(Endian) {}
|
||||
|
||||
endianness getEndian() const override { return Endian; }
|
||||
|
||||
Error readBytes(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) override {
|
||||
if (auto EC = checkOffset(Offset, Size))
|
||||
return EC;
|
||||
uint32_t S = startIndex(Offset);
|
||||
auto Ref = Data.drop_front(S);
|
||||
if (Ref.size() >= Size) {
|
||||
Buffer = Ref.take_front(Size);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t BytesLeft = Size - Ref.size();
|
||||
uint8_t *Ptr = Allocator.Allocate<uint8_t>(Size);
|
||||
::memcpy(Ptr, Ref.data(), Ref.size());
|
||||
::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft);
|
||||
Buffer = makeArrayRef<uint8_t>(Ptr, Size);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error readLongestContiguousChunk(uint32_t Offset,
|
||||
ArrayRef<uint8_t> &Buffer) override {
|
||||
if (auto EC = checkOffset(Offset, 1))
|
||||
return EC;
|
||||
uint32_t S = startIndex(Offset);
|
||||
Buffer = Data.drop_front(S);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t getLength() override { return Data.size(); }
|
||||
|
||||
Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override {
|
||||
if (auto EC = checkOffset(Offset, SrcData.size()))
|
||||
return EC;
|
||||
if (SrcData.empty())
|
||||
return Error::success();
|
||||
|
||||
uint32_t S = startIndex(Offset);
|
||||
MutableArrayRef<uint8_t> Ref(Data);
|
||||
Ref = Ref.drop_front(S);
|
||||
if (Ref.size() >= SrcData.size()) {
|
||||
::memcpy(Ref.data(), SrcData.data(), SrcData.size());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t BytesLeft = SrcData.size() - Ref.size();
|
||||
::memcpy(Ref.data(), SrcData.data(), Ref.size());
|
||||
::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft);
|
||||
return Error::success();
|
||||
}
|
||||
Error commit() override { return Error::success(); }
|
||||
|
||||
private:
|
||||
uint32_t startIndex(uint32_t Offset) const {
|
||||
return (Offset + PartitionIndex) % Data.size();
|
||||
}
|
||||
|
||||
uint32_t endIndex(uint32_t Offset, uint32_t Size) const {
|
||||
return (startIndex(Offset) + Size - 1) % Data.size();
|
||||
}
|
||||
|
||||
// Buffer is organized like this:
|
||||
// -------------------------------------------------
|
||||
// | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N-2-1 |
|
||||
// -------------------------------------------------
|
||||
// So reads from the beginning actually come from the middle.
|
||||
MutableArrayRef<uint8_t> Data;
|
||||
uint32_t PartitionIndex = 0;
|
||||
endianness Endian;
|
||||
BumpPtrAllocator Allocator;
|
||||
};
|
||||
|
||||
constexpr endianness Endians[] = { big, little, native };
|
||||
constexpr uint32_t NumEndians = llvm::array_lengthof(Endians);
|
||||
constexpr uint32_t NumStreams = 2 * NumEndians;
|
||||
|
||||
class BinaryStreamTest : public testing::Test {
|
||||
|
||||
public:
|
||||
BinaryStreamTest() {}
|
||||
|
||||
void SetUp() override {
|
||||
Streams.clear();
|
||||
Streams.resize(NumStreams);
|
||||
for (uint32_t I = 0; I < NumStreams; ++I)
|
||||
Streams[I].IsContiguous = (I % 2 == 0);
|
||||
|
||||
InputData.clear();
|
||||
OutputData.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
struct StreamPair {
|
||||
bool IsContiguous;
|
||||
std::unique_ptr<BinaryStream> Input;
|
||||
std::unique_ptr<WritableBinaryStream> Output;
|
||||
};
|
||||
|
||||
void initializeInput(ArrayRef<uint8_t> Input) {
|
||||
InputData = Input;
|
||||
|
||||
BrokenInputData.resize(InputData.size());
|
||||
if (!Input.empty()) {
|
||||
uint32_t PartitionIndex = InputData.size() / 2;
|
||||
uint32_t RightBytes = InputData.size() - PartitionIndex;
|
||||
uint32_t LeftBytes = PartitionIndex;
|
||||
if (RightBytes > 0)
|
||||
::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes);
|
||||
if (LeftBytes > 0)
|
||||
::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes);
|
||||
}
|
||||
|
||||
for (uint32_t I = 0; I < NumEndians; ++I) {
|
||||
auto InByteStream =
|
||||
llvm::make_unique<BinaryByteStream>(InputData, Endians[I]);
|
||||
auto InBrokenStream =
|
||||
llvm::make_unique<DiscontiguousStream>(BrokenInputData, Endians[I]);
|
||||
|
||||
Streams[I * 2].Input = std::move(InByteStream);
|
||||
Streams[I * 2 + 1].Input = std::move(InBrokenStream);
|
||||
}
|
||||
}
|
||||
|
||||
void initializeOutput(uint32_t Size) {
|
||||
OutputData.resize(Size);
|
||||
BrokenOutputData.resize(Size);
|
||||
|
||||
for (uint32_t I = 0; I < NumEndians; ++I) {
|
||||
Streams[I * 2].Output =
|
||||
llvm::make_unique<MutableBinaryByteStream>(OutputData, Endians[I]);
|
||||
Streams[I * 2 + 1].Output =
|
||||
llvm::make_unique<DiscontiguousStream>(BrokenOutputData, Endians[I]);
|
||||
}
|
||||
}
|
||||
|
||||
void initializeOutputFromInput() {
|
||||
for (uint32_t I = 0; I < NumEndians; ++I) {
|
||||
Streams[I * 2].Output =
|
||||
llvm::make_unique<MutableBinaryByteStream>(InputData, Endians[I]);
|
||||
Streams[I * 2 + 1].Output =
|
||||
llvm::make_unique<DiscontiguousStream>(BrokenInputData, Endians[I]);
|
||||
}
|
||||
}
|
||||
|
||||
void initializeInputFromOutput() {
|
||||
for (uint32_t I = 0; I < NumEndians; ++I) {
|
||||
Streams[I * 2].Input =
|
||||
llvm::make_unique<BinaryByteStream>(OutputData, Endians[I]);
|
||||
Streams[I * 2 + 1].Input =
|
||||
llvm::make_unique<DiscontiguousStream>(BrokenOutputData, Endians[I]);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> InputData;
|
||||
std::vector<uint8_t> BrokenInputData;
|
||||
|
||||
std::vector<uint8_t> OutputData;
|
||||
std::vector<uint8_t> BrokenOutputData;
|
||||
|
||||
std::vector<StreamPair> Streams;
|
||||
};
|
||||
|
||||
// Tests that a we can read from a BinaryByteStream without a StreamReader.
|
||||
TEST_F(BinaryStreamTest, BinaryByteStreamBounds) {
|
||||
std::vector<uint8_t> InputData = {1, 2, 3, 4, 5};
|
||||
initializeInput(InputData);
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
ArrayRef<uint8_t> Buffer;
|
||||
|
||||
// 1. If the read fits it should work.
|
||||
ASSERT_EQ(InputData.size(), Stream.Input->getLength());
|
||||
ASSERT_NO_ERROR(Stream.Input->readBytes(2, 1, Buffer));
|
||||
EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer);
|
||||
ASSERT_NO_ERROR(Stream.Input->readBytes(0, 4, Buffer));
|
||||
EXPECT_EQ(makeArrayRef(InputData).slice(0, 4), Buffer);
|
||||
|
||||
// 2. Reading past the bounds of the input should fail.
|
||||
EXPECT_ERROR(Stream.Input->readBytes(4, 2, Buffer));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamRefBounds) {
|
||||
std::vector<uint8_t> InputData = {1, 2, 3, 4, 5};
|
||||
initializeInput(InputData);
|
||||
|
||||
for (const auto &Stream : Streams) {
|
||||
ArrayRef<uint8_t> Buffer;
|
||||
BinaryStreamRef Ref(*Stream.Input);
|
||||
|
||||
// Read 1 byte from offset 2 should work
|
||||
ASSERT_EQ(InputData.size(), Ref.getLength());
|
||||
ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer));
|
||||
EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer);
|
||||
|
||||
// Reading everything from offset 2 on.
|
||||
ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer));
|
||||
if (Stream.IsContiguous)
|
||||
EXPECT_EQ(makeArrayRef(InputData).slice(2), Buffer);
|
||||
else
|
||||
EXPECT_FALSE(Buffer.empty());
|
||||
|
||||
// Reading 6 bytes from offset 0 is too big.
|
||||
EXPECT_ERROR(Ref.readBytes(0, 6, Buffer));
|
||||
EXPECT_ERROR(Ref.readLongestContiguousChunk(6, Buffer));
|
||||
|
||||
// Reading 1 byte from offset 2 after dropping 1 byte is the same as reading
|
||||
// 1 byte from offset 3.
|
||||
Ref = Ref.drop_front(1);
|
||||
ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer));
|
||||
if (Stream.IsContiguous)
|
||||
EXPECT_EQ(makeArrayRef(InputData).slice(3, 1), Buffer);
|
||||
else
|
||||
EXPECT_FALSE(Buffer.empty());
|
||||
|
||||
// Reading everything from offset 2 on after dropping 1 byte.
|
||||
ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer));
|
||||
if (Stream.IsContiguous)
|
||||
EXPECT_EQ(makeArrayRef(InputData).slice(3), Buffer);
|
||||
else
|
||||
EXPECT_FALSE(Buffer.empty());
|
||||
|
||||
// Reading 2 bytes from offset 2 after dropping 2 bytes is the same as
|
||||
// reading 2 bytes from offset 4, and should fail.
|
||||
Ref = Ref.drop_front(1);
|
||||
EXPECT_ERROR(Ref.readBytes(2, 2, Buffer));
|
||||
|
||||
// But if we read the longest contiguous chunk instead, we should still
|
||||
// get the 1 byte at the end.
|
||||
ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer));
|
||||
EXPECT_EQ(makeArrayRef(InputData).take_back(), Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that we can write to a BinaryStream without a StreamWriter.
|
||||
TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) {
|
||||
std::vector<uint8_t> InputData = {'T', 'e', 's', 't', '\0'};
|
||||
initializeInput(InputData);
|
||||
initializeOutput(InputData.size());
|
||||
|
||||
// For every combination of input stream and output stream.
|
||||
for (auto &Stream : Streams) {
|
||||
MutableArrayRef<uint8_t> Buffer;
|
||||
ASSERT_EQ(InputData.size(), Stream.Input->getLength());
|
||||
|
||||
// 1. Try two reads that are supposed to work. One from offset 0, and one
|
||||
// from the middle.
|
||||
uint32_t Offsets[] = {0, 3};
|
||||
for (auto Offset : Offsets) {
|
||||
uint32_t ExpectedSize = Stream.Input->getLength() - Offset;
|
||||
|
||||
// Read everything from Offset until the end of the input data.
|
||||
ArrayRef<uint8_t> Data;
|
||||
ASSERT_NO_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data));
|
||||
ASSERT_EQ(ExpectedSize, Data.size());
|
||||
|
||||
// Then write it to the destination.
|
||||
ASSERT_NO_ERROR(Stream.Output->writeBytes(0, Data));
|
||||
|
||||
// Then we read back what we wrote, it should match the corresponding
|
||||
// slice of the original input data.
|
||||
ArrayRef<uint8_t> Data2;
|
||||
ASSERT_NO_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2));
|
||||
EXPECT_EQ(makeArrayRef(InputData).drop_front(Offset), Data2);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BigData = {0, 1, 2, 3, 4};
|
||||
// 2. If the write is too big, it should fail.
|
||||
EXPECT_ERROR(Stream.Output->writeBytes(3, BigData));
|
||||
}
|
||||
}
|
||||
|
||||
// Test that FixedStreamArray works correctly.
|
||||
TEST_F(BinaryStreamTest, FixedStreamArray) {
|
||||
std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823};
|
||||
ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(Ints.data()),
|
||||
Ints.size() * sizeof(uint32_t));
|
||||
|
||||
initializeInput(IntBytes);
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
MutableArrayRef<uint8_t> Buffer;
|
||||
ASSERT_EQ(InputData.size(), Stream.Input->getLength());
|
||||
|
||||
FixedStreamArray<uint32_t> Array(*Stream.Input);
|
||||
auto Iter = Array.begin();
|
||||
ASSERT_EQ(Ints[0], *Iter++);
|
||||
ASSERT_EQ(Ints[1], *Iter++);
|
||||
ASSERT_EQ(Ints[2], *Iter++);
|
||||
ASSERT_EQ(Ints[3], *Iter++);
|
||||
ASSERT_EQ(Array.end(), Iter);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that VarStreamArray works correctly.
|
||||
TEST_F(BinaryStreamTest, VarStreamArray) {
|
||||
StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super "
|
||||
"Extra Longest Test Of All");
|
||||
ArrayRef<uint8_t> StringBytes(
|
||||
reinterpret_cast<const uint8_t *>(Strings.data()), Strings.size());
|
||||
initializeInput(StringBytes);
|
||||
|
||||
struct StringExtractor {
|
||||
public:
|
||||
Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) {
|
||||
if (Index == 0)
|
||||
Len = strlen("1. Test");
|
||||
else if (Index == 1)
|
||||
Len = strlen("2. Longer Test");
|
||||
else if (Index == 2)
|
||||
Len = strlen("3. Really Long Test");
|
||||
else
|
||||
Len = strlen("4. Super Extra Longest Test Of All");
|
||||
ArrayRef<uint8_t> Bytes;
|
||||
if (auto EC = Stream.readBytes(0, Len, Bytes))
|
||||
return EC;
|
||||
Item =
|
||||
StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
|
||||
++Index;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t Index = 0;
|
||||
};
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input);
|
||||
auto Iter = Array.begin();
|
||||
ASSERT_EQ("1. Test", *Iter++);
|
||||
ASSERT_EQ("2. Longer Test", *Iter++);
|
||||
ASSERT_EQ("3. Really Long Test", *Iter++);
|
||||
ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++);
|
||||
ASSERT_EQ(Array.end(), Iter);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderBounds) {
|
||||
std::vector<uint8_t> Bytes;
|
||||
|
||||
initializeInput(Bytes);
|
||||
for (auto &Stream : Streams) {
|
||||
StringRef S;
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
EXPECT_EQ(0U, Reader.bytesRemaining());
|
||||
EXPECT_ERROR(Reader.readFixedString(S, 1));
|
||||
}
|
||||
|
||||
Bytes.resize(5);
|
||||
initializeInput(Bytes);
|
||||
for (auto &Stream : Streams) {
|
||||
StringRef S;
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
EXPECT_EQ(Bytes.size(), Reader.bytesRemaining());
|
||||
EXPECT_NO_ERROR(Reader.readFixedString(S, 5));
|
||||
EXPECT_ERROR(Reader.readFixedString(S, 6));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderIntegers) {
|
||||
support::ulittle64_t Little{908234};
|
||||
support::ubig32_t Big{28907823};
|
||||
short NS = 2897;
|
||||
int NI = -89723;
|
||||
unsigned long NUL = 902309023UL;
|
||||
constexpr uint32_t Size =
|
||||
sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL);
|
||||
|
||||
initializeOutput(Size);
|
||||
initializeInputFromOutput();
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
BinaryStreamWriter Writer(*Stream.Output);
|
||||
ASSERT_NO_ERROR(Writer.writeObject(Little));
|
||||
ASSERT_NO_ERROR(Writer.writeObject(Big));
|
||||
ASSERT_NO_ERROR(Writer.writeInteger(NS));
|
||||
ASSERT_NO_ERROR(Writer.writeInteger(NI));
|
||||
ASSERT_NO_ERROR(Writer.writeInteger(NUL));
|
||||
|
||||
const support::ulittle64_t *Little2;
|
||||
const support::ubig32_t *Big2;
|
||||
short NS2;
|
||||
int NI2;
|
||||
unsigned long NUL2;
|
||||
|
||||
// 1. Reading fields individually.
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
ASSERT_NO_ERROR(Reader.readObject(Little2));
|
||||
ASSERT_NO_ERROR(Reader.readObject(Big2));
|
||||
ASSERT_NO_ERROR(Reader.readInteger(NS2));
|
||||
ASSERT_NO_ERROR(Reader.readInteger(NI2));
|
||||
ASSERT_NO_ERROR(Reader.readInteger(NUL2));
|
||||
ASSERT_EQ(0U, Reader.bytesRemaining());
|
||||
|
||||
EXPECT_EQ(Little, *Little2);
|
||||
EXPECT_EQ(Big, *Big2);
|
||||
EXPECT_EQ(NS, NS2);
|
||||
EXPECT_EQ(NI, NI2);
|
||||
EXPECT_EQ(NUL, NUL2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderIntegerArray) {
|
||||
// 1. Arrays of integers
|
||||
std::vector<int> Ints = {1, 2, 3, 4, 5};
|
||||
ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]),
|
||||
Ints.size() * sizeof(int));
|
||||
|
||||
initializeInput(IntBytes);
|
||||
for (auto &Stream : Streams) {
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
ArrayRef<int> IntsRef;
|
||||
ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size()));
|
||||
ASSERT_EQ(0U, Reader.bytesRemaining());
|
||||
EXPECT_EQ(makeArrayRef(Ints), IntsRef);
|
||||
|
||||
Reader.setOffset(0);
|
||||
FixedStreamArray<int> FixedIntsRef;
|
||||
ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size()));
|
||||
ASSERT_EQ(0U, Reader.bytesRemaining());
|
||||
ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderEnum) {
|
||||
enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 };
|
||||
|
||||
std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo};
|
||||
|
||||
initializeOutput(Enums.size() * sizeof(MyEnum));
|
||||
initializeInputFromOutput();
|
||||
for (auto &Stream : Streams) {
|
||||
BinaryStreamWriter Writer(*Stream.Output);
|
||||
for (auto Value : Enums)
|
||||
ASSERT_NO_ERROR(Writer.writeEnum(Value));
|
||||
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
|
||||
ArrayRef<MyEnum> Array;
|
||||
FixedStreamArray<MyEnum> FSA;
|
||||
|
||||
for (size_t I = 0; I < Enums.size(); ++I) {
|
||||
MyEnum Value;
|
||||
ASSERT_NO_ERROR(Reader.readEnum(Value));
|
||||
EXPECT_EQ(Enums[I], Value);
|
||||
}
|
||||
ASSERT_EQ(0U, Reader.bytesRemaining());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderObject) {
|
||||
struct Foo {
|
||||
int X;
|
||||
double Y;
|
||||
char Z;
|
||||
};
|
||||
|
||||
std::vector<Foo> Foos;
|
||||
Foos.push_back({-42, 42.42, 42});
|
||||
Foos.push_back({100, 3.1415, static_cast<char>(-89)});
|
||||
|
||||
const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]);
|
||||
|
||||
initializeInput(makeArrayRef(Bytes, 2 * sizeof(Foo)));
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
// 1. Reading object pointers.
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
const Foo *FPtrOut = nullptr;
|
||||
const Foo *GPtrOut = nullptr;
|
||||
ASSERT_NO_ERROR(Reader.readObject(FPtrOut));
|
||||
ASSERT_NO_ERROR(Reader.readObject(GPtrOut));
|
||||
EXPECT_EQ(0U, Reader.bytesRemaining());
|
||||
EXPECT_EQ(0, ::memcmp(&Foos[0], FPtrOut, sizeof(Foo)));
|
||||
EXPECT_EQ(0, ::memcmp(&Foos[1], GPtrOut, sizeof(Foo)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderStrings) {
|
||||
std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o',
|
||||
'\0', 'T', 'h', 'r', 'e', 'e', '\0',
|
||||
'F', 'o', 'u', 'r', '\0'};
|
||||
initializeInput(Bytes);
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
|
||||
StringRef S1;
|
||||
StringRef S2;
|
||||
StringRef S3;
|
||||
StringRef S4;
|
||||
ASSERT_NO_ERROR(Reader.readCString(S1));
|
||||
ASSERT_NO_ERROR(Reader.readCString(S2));
|
||||
ASSERT_NO_ERROR(Reader.readCString(S3));
|
||||
ASSERT_NO_ERROR(Reader.readCString(S4));
|
||||
ASSERT_EQ(0U, Reader.bytesRemaining());
|
||||
|
||||
EXPECT_EQ("One", S1);
|
||||
EXPECT_EQ("Two", S2);
|
||||
EXPECT_EQ("Three", S3);
|
||||
EXPECT_EQ("Four", S4);
|
||||
|
||||
S1 = S2 = S3 = S4 = "";
|
||||
Reader.setOffset(0);
|
||||
ASSERT_NO_ERROR(Reader.readFixedString(S1, 3));
|
||||
ASSERT_NO_ERROR(Reader.skip(1));
|
||||
ASSERT_NO_ERROR(Reader.readFixedString(S2, 3));
|
||||
ASSERT_NO_ERROR(Reader.skip(1));
|
||||
ASSERT_NO_ERROR(Reader.readFixedString(S3, 5));
|
||||
ASSERT_NO_ERROR(Reader.skip(1));
|
||||
ASSERT_NO_ERROR(Reader.readFixedString(S4, 4));
|
||||
ASSERT_NO_ERROR(Reader.skip(1));
|
||||
ASSERT_EQ(0U, Reader.bytesRemaining());
|
||||
|
||||
EXPECT_EQ("One", S1);
|
||||
EXPECT_EQ("Two", S2);
|
||||
EXPECT_EQ("Three", S3);
|
||||
EXPECT_EQ("Four", S4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamWriterBounds) {
|
||||
initializeOutput(5);
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
BinaryStreamWriter Writer(*Stream.Output);
|
||||
|
||||
// 1. Can write a string that exactly fills the buffer.
|
||||
EXPECT_EQ(5U, Writer.bytesRemaining());
|
||||
EXPECT_NO_ERROR(Writer.writeFixedString("abcde"));
|
||||
EXPECT_EQ(0U, Writer.bytesRemaining());
|
||||
|
||||
// 2. Can write an empty string even when you're full
|
||||
EXPECT_NO_ERROR(Writer.writeFixedString(""));
|
||||
EXPECT_ERROR(Writer.writeFixedString("a"));
|
||||
|
||||
// 3. Can't write a string that is one character too long.
|
||||
Writer.setOffset(0);
|
||||
EXPECT_ERROR(Writer.writeFixedString("abcdef"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) {
|
||||
// 3. Arrays of integers
|
||||
std::vector<int> SourceInts = {1, 2, 3, 4, 5};
|
||||
ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]),
|
||||
SourceInts.size() * sizeof(int));
|
||||
|
||||
initializeInput(SourceBytes);
|
||||
initializeOutputFromInput();
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
BinaryStreamWriter Writer(*Stream.Output);
|
||||
ArrayRef<int> Ints;
|
||||
ArrayRef<int> Ints2;
|
||||
// First read them, then write them, then read them back.
|
||||
ASSERT_NO_ERROR(Reader.readArray(Ints, SourceInts.size()));
|
||||
ASSERT_NO_ERROR(Writer.writeArray(Ints));
|
||||
|
||||
BinaryStreamReader ReaderBacker(*Stream.Output);
|
||||
ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size()));
|
||||
|
||||
EXPECT_EQ(makeArrayRef(SourceInts), Ints2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StringWriterStrings) {
|
||||
StringRef Strings[] = {"First", "Second", "Third", "Fourth"};
|
||||
|
||||
size_t Length = 0;
|
||||
for (auto S : Strings)
|
||||
Length += S.size() + 1;
|
||||
initializeOutput(Length);
|
||||
initializeInputFromOutput();
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
BinaryStreamWriter Writer(*Stream.Output);
|
||||
for (auto S : Strings)
|
||||
ASSERT_NO_ERROR(Writer.writeCString(S));
|
||||
std::vector<StringRef> InStrings;
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
while (!Reader.empty()) {
|
||||
StringRef S;
|
||||
ASSERT_NO_ERROR(Reader.readCString(S));
|
||||
InStrings.push_back(S);
|
||||
}
|
||||
EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct BinaryItemStreamObject {
|
||||
explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {}
|
||||
|
||||
ArrayRef<uint8_t> Bytes;
|
||||
};
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
template <> struct BinaryItemTraits<BinaryItemStreamObject> {
|
||||
static size_t length(const BinaryItemStreamObject &Item) {
|
||||
return Item.Bytes.size();
|
||||
}
|
||||
|
||||
static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) {
|
||||
return Item.Bytes;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
TEST_F(BinaryStreamTest, BinaryItemStream) {
|
||||
std::vector<BinaryItemStreamObject> Objects;
|
||||
|
||||
struct Foo {
|
||||
int X;
|
||||
double Y;
|
||||
};
|
||||
std::vector<Foo> Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}};
|
||||
BumpPtrAllocator Allocator;
|
||||
for (const auto &F : Foos) {
|
||||
uint8_t *Ptr = Allocator.Allocate<uint8_t>(sizeof(Foo));
|
||||
MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo));
|
||||
MutableBinaryByteStream Stream(Buffer, llvm::support::big);
|
||||
BinaryStreamWriter Writer(Stream);
|
||||
ASSERT_NO_ERROR(Writer.writeObject(F));
|
||||
Objects.push_back(BinaryItemStreamObject(Buffer));
|
||||
}
|
||||
|
||||
BinaryItemStream<BinaryItemStreamObject> ItemStream(big);
|
||||
ItemStream.setItems(Objects);
|
||||
BinaryStreamReader Reader(ItemStream);
|
||||
|
||||
for (const auto &F : Foos) {
|
||||
const Foo *F2;
|
||||
ASSERT_NO_ERROR(Reader.readObject(F2));
|
||||
|
||||
EXPECT_EQ(F.X, F2->X);
|
||||
EXPECT_DOUBLE_EQ(F.Y, F2->Y);
|
||||
}
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
|
@ -5,7 +5,6 @@ set(LLVM_LINK_COMPONENTS
|
|||
)
|
||||
|
||||
set(DebugInfoPDBSources
|
||||
BinaryStreamTest.cpp
|
||||
HashTableTest.cpp
|
||||
MappedBlockStreamTest.cpp
|
||||
StringTableBuilderTest.cpp
|
||||
|
|
Loading…
Reference in New Issue