| Index: minidump/minidump_writable_test.cc
|
| diff --git a/minidump/minidump_writable_test.cc b/minidump/minidump_writable_test.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6adad96806cbd13c1037f9aaef729a7a9ae8862e
|
| --- /dev/null
|
| +++ b/minidump/minidump_writable_test.cc
|
| @@ -0,0 +1,835 @@
|
| +// Copyright 2014 The Crashpad Authors. All rights reserved.
|
| +//
|
| +// Licensed under the Apache License, Version 2.0 (the "License");
|
| +// you may not use this file except in compliance with the License.
|
| +// You may obtain a copy of the License at
|
| +//
|
| +// http://www.apache.org/licenses/LICENSE-2.0
|
| +//
|
| +// Unless required by applicable law or agreed to in writing, software
|
| +// distributed under the License is distributed on an "AS IS" BASIS,
|
| +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| +// See the License for the specific language governing permissions and
|
| +// limitations under the License.
|
| +
|
| +#include "minidump/minidump_writable.h"
|
| +
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/basictypes.h"
|
| +#include "gtest/gtest.h"
|
| +#include "util/file/string_file_writer.h"
|
| +
|
| +namespace {
|
| +
|
| +using namespace crashpad;
|
| +using namespace testing;
|
| +
|
| +class BaseTestMinidumpWritable : public crashpad::internal::MinidumpWritable {
|
| + public:
|
| + BaseTestMinidumpWritable()
|
| + : MinidumpWritable(),
|
| + children_(),
|
| + expected_offset_(-1),
|
| + alignment_(0),
|
| + phase_(kPhaseEarly),
|
| + has_alignment_(false),
|
| + has_phase_(false),
|
| + verified_(false) {}
|
| +
|
| + ~BaseTestMinidumpWritable() { EXPECT_TRUE(verified_); }
|
| +
|
| + void SetAlignment(size_t alignment) {
|
| + alignment_ = alignment;
|
| + has_alignment_ = true;
|
| + }
|
| +
|
| + void AddChild(BaseTestMinidumpWritable* child) { children_.push_back(child); }
|
| +
|
| + void SetPhaseLate() {
|
| + phase_ = kPhaseLate;
|
| + has_phase_ = true;
|
| + }
|
| +
|
| + void Verify() {
|
| + verified_ = true;
|
| + EXPECT_EQ(kStateWritten, state());
|
| + for (BaseTestMinidumpWritable* child : children_) {
|
| + child->Verify();
|
| + }
|
| + }
|
| +
|
| + protected:
|
| + virtual bool Freeze() override {
|
| + EXPECT_EQ(kStateMutable, state());
|
| + bool rv = MinidumpWritable::Freeze();
|
| + EXPECT_TRUE(rv);
|
| + EXPECT_EQ(kStateFrozen, state());
|
| + return rv;
|
| + }
|
| +
|
| + virtual size_t Alignment() override {
|
| + EXPECT_GE(state(), kStateFrozen);
|
| + return has_alignment_ ? alignment_ : MinidumpWritable::Alignment();
|
| + }
|
| +
|
| + virtual std::vector<MinidumpWritable*> Children() override {
|
| + EXPECT_GE(state(), kStateFrozen);
|
| + if (!children_.empty()) {
|
| + std::vector<MinidumpWritable*> children;
|
| + for (BaseTestMinidumpWritable* child : children_) {
|
| + children.push_back(child);
|
| + }
|
| + return children;
|
| + }
|
| + return MinidumpWritable::Children();
|
| + }
|
| +
|
| + virtual Phase WritePhase() override {
|
| + return has_phase_ ? phase_ : MinidumpWritable::Phase();
|
| + }
|
| +
|
| + virtual bool WillWriteAtOffsetImpl(off_t offset) override {
|
| + EXPECT_EQ(state(), kStateFrozen);
|
| + expected_offset_ = offset;
|
| + bool rv = MinidumpWritable::WillWriteAtOffsetImpl(offset);
|
| + EXPECT_TRUE(rv);
|
| + return rv;
|
| + }
|
| +
|
| + virtual bool WriteObject(FileWriterInterface* file_writer) override {
|
| + EXPECT_EQ(state(), kStateWritable);
|
| + EXPECT_EQ(expected_offset_, file_writer->Seek(0, SEEK_CUR));
|
| +
|
| + // Subclasses must override this.
|
| + return false;
|
| + }
|
| +
|
| + private:
|
| + std::vector<BaseTestMinidumpWritable*> children_;
|
| + off_t expected_offset_;
|
| + size_t alignment_;
|
| + Phase phase_;
|
| + bool has_alignment_;
|
| + bool has_phase_;
|
| + bool verified_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BaseTestMinidumpWritable);
|
| +};
|
| +
|
| +class TestStringMinidumpWritable final : public BaseTestMinidumpWritable {
|
| + public:
|
| + TestStringMinidumpWritable() : BaseTestMinidumpWritable(), data_() {}
|
| +
|
| + ~TestStringMinidumpWritable() {}
|
| +
|
| + void SetData(const std::string& string) { data_ = string; }
|
| +
|
| + protected:
|
| + virtual size_t SizeOfObject() override {
|
| + EXPECT_GE(state(), kStateFrozen);
|
| + return data_.size();
|
| + }
|
| +
|
| + virtual bool WriteObject(FileWriterInterface* file_writer) override {
|
| + BaseTestMinidumpWritable::WriteObject(file_writer);
|
| + EXPECT_TRUE(file_writer->Write(&data_[0], data_.size()));
|
| + return true;
|
| + }
|
| +
|
| + private:
|
| + std::string data_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestStringMinidumpWritable);
|
| +};
|
| +
|
| +TEST(MinidumpWritable, MinidumpWritable) {
|
| + StringFileWriter writer;
|
| +
|
| + {
|
| + SCOPED_TRACE("empty");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable string_writable;
|
| + EXPECT_TRUE(string_writable.WriteEverything(&writer));
|
| + EXPECT_TRUE(writer.string().empty());
|
| + string_writable.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("childless");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable string_writable;
|
| + string_writable.SetData("a");
|
| + EXPECT_TRUE(string_writable.WriteEverything(&writer));
|
| + EXPECT_EQ(1u, writer.string().size());
|
| + EXPECT_EQ("a", writer.string());
|
| + string_writable.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("parent-child");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("b");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("c");
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(5u, writer.string().size());
|
| + EXPECT_EQ(std::string("b\0\0\0c", 5), writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("base alignment 2");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("de");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("f");
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(5u, writer.string().size());
|
| + EXPECT_EQ(std::string("de\0\0f", 5), writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("base alignment 3");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("ghi");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("j");
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(5u, writer.string().size());
|
| + EXPECT_EQ(std::string("ghi\0j", 5), writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("base alignment 4");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("klmn");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("o");
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(5u, writer.string().size());
|
| + EXPECT_EQ("klmno", writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("base alignment 5");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("pqrst");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("u");
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(9u, writer.string().size());
|
| + EXPECT_EQ(std::string("pqrst\0\0\0u", 9), writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("two children");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("parent");
|
| + TestStringMinidumpWritable child_0;
|
| + child_0.SetData("child_0");
|
| + parent.AddChild(&child_0);
|
| + TestStringMinidumpWritable child_1;
|
| + child_1.SetData("child_1");
|
| + parent.AddChild(&child_1);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(23u, writer.string().size());
|
| + EXPECT_EQ(std::string("parent\0\0child_0\0child_1", 23), writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("grandchild");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("parent");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("child");
|
| + parent.AddChild(&child);
|
| + TestStringMinidumpWritable grandchild;
|
| + grandchild.SetData("grandchild");
|
| + child.AddChild(&grandchild);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(26u, writer.string().size());
|
| + EXPECT_EQ(std::string("parent\0\0child\0\0\0grandchild", 26),
|
| + writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("grandchild with empty parent");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("child");
|
| + parent.AddChild(&child);
|
| + TestStringMinidumpWritable grandchild;
|
| + grandchild.SetData("grandchild");
|
| + child.AddChild(&grandchild);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(18u, writer.string().size());
|
| + EXPECT_EQ(std::string("child\0\0\0grandchild", 18), writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("grandchild with empty child");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("parent");
|
| + TestStringMinidumpWritable child;
|
| + parent.AddChild(&child);
|
| + TestStringMinidumpWritable grandchild;
|
| + grandchild.SetData("grandchild");
|
| + child.AddChild(&grandchild);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(18u, writer.string().size());
|
| + EXPECT_EQ(std::string("parent\0\0grandchild", 18), writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("grandchild with empty grandchild");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("parent");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("child");
|
| + parent.AddChild(&child);
|
| + TestStringMinidumpWritable grandchild;
|
| + child.AddChild(&grandchild);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(13u, writer.string().size());
|
| + EXPECT_EQ(std::string("parent\0\0child", 13), writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("grandchild with late-phase grandchild");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("parent");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("child");
|
| + parent.AddChild(&child);
|
| + TestStringMinidumpWritable grandchild;
|
| + grandchild.SetData("grandchild");
|
| + grandchild.SetPhaseLate();
|
| + child.AddChild(&grandchild);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(26u, writer.string().size());
|
| + EXPECT_EQ(std::string("parent\0\0child\0\0\0grandchild", 26),
|
| + writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("grandchild with late-phase child");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("parent");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("child");
|
| + child.SetPhaseLate();
|
| + parent.AddChild(&child);
|
| + TestStringMinidumpWritable grandchild;
|
| + grandchild.SetData("grandchild");
|
| + child.AddChild(&grandchild);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(25u, writer.string().size());
|
| + EXPECT_EQ(std::string("parent\0\0grandchild\0\0child", 25),
|
| + writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("family tree");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("P..");
|
| + TestStringMinidumpWritable child_0;
|
| + child_0.SetData("C0.");
|
| + parent.AddChild(&child_0);
|
| + TestStringMinidumpWritable child_1;
|
| + child_1.SetData("C1.");
|
| + parent.AddChild(&child_1);
|
| + TestStringMinidumpWritable grandchild_00;
|
| + grandchild_00.SetData("G00");
|
| + child_0.AddChild(&grandchild_00);
|
| + TestStringMinidumpWritable grandchild_01;
|
| + grandchild_01.SetData("G01");
|
| + child_0.AddChild(&grandchild_01);
|
| + TestStringMinidumpWritable grandchild_10;
|
| + grandchild_10.SetData("G10");
|
| + child_1.AddChild(&grandchild_10);
|
| + TestStringMinidumpWritable grandchild_11;
|
| + grandchild_11.SetData("G11");
|
| + child_1.AddChild(&grandchild_11);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(27u, writer.string().size());
|
| + EXPECT_EQ(std::string("P..\0C0.\0G00\0G01\0C1.\0G10\0G11", 27),
|
| + writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("family tree with C0 late");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("P..");
|
| + TestStringMinidumpWritable child_0;
|
| + child_0.SetData("C0.");
|
| + child_0.SetPhaseLate();
|
| + parent.AddChild(&child_0);
|
| + TestStringMinidumpWritable child_1;
|
| + child_1.SetData("C1.");
|
| + parent.AddChild(&child_1);
|
| + TestStringMinidumpWritable grandchild_00;
|
| + grandchild_00.SetData("G00");
|
| + child_0.AddChild(&grandchild_00);
|
| + TestStringMinidumpWritable grandchild_01;
|
| + grandchild_01.SetData("G01");
|
| + child_0.AddChild(&grandchild_01);
|
| + TestStringMinidumpWritable grandchild_10;
|
| + grandchild_10.SetData("G10");
|
| + child_1.AddChild(&grandchild_10);
|
| + TestStringMinidumpWritable grandchild_11;
|
| + grandchild_11.SetData("G11");
|
| + child_1.AddChild(&grandchild_11);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(27u, writer.string().size());
|
| + EXPECT_EQ(std::string("P..\0G00\0G01\0C1.\0G10\0G11\0C0.", 27),
|
| + writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("family tree with G0 late");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("P..");
|
| + TestStringMinidumpWritable child_0;
|
| + child_0.SetData("C0.");
|
| + parent.AddChild(&child_0);
|
| + TestStringMinidumpWritable child_1;
|
| + child_1.SetData("C1.");
|
| + parent.AddChild(&child_1);
|
| + TestStringMinidumpWritable grandchild_00;
|
| + grandchild_00.SetData("G00");
|
| + grandchild_00.SetPhaseLate();
|
| + child_0.AddChild(&grandchild_00);
|
| + TestStringMinidumpWritable grandchild_01;
|
| + grandchild_01.SetData("G01");
|
| + grandchild_01.SetPhaseLate();
|
| + child_0.AddChild(&grandchild_01);
|
| + TestStringMinidumpWritable grandchild_10;
|
| + grandchild_10.SetData("G10");
|
| + child_1.AddChild(&grandchild_10);
|
| + TestStringMinidumpWritable grandchild_11;
|
| + grandchild_11.SetData("G11");
|
| + child_1.AddChild(&grandchild_11);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(27u, writer.string().size());
|
| + EXPECT_EQ(std::string("P..\0C0.\0C1.\0G10\0G11\0G00\0G01", 27),
|
| + writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("align 1");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("p");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("c");
|
| + child.SetAlignment(1);
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(2u, writer.string().size());
|
| + EXPECT_EQ("pc", writer.string());
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("align 2");
|
| + writer.Reset();
|
| + TestStringMinidumpWritable parent;
|
| + parent.SetData("p");
|
| + TestStringMinidumpWritable child;
|
| + child.SetData("c");
|
| + child.SetAlignment(2);
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| + EXPECT_EQ(3u, writer.string().size());
|
| + EXPECT_EQ(std::string("p\0c", 3), writer.string());
|
| + parent.Verify();
|
| + }
|
| +}
|
| +
|
| +class TestRVAMinidumpWritable final : public BaseTestMinidumpWritable {
|
| + public:
|
| + TestRVAMinidumpWritable() : BaseTestMinidumpWritable(), rva_() {}
|
| +
|
| + ~TestRVAMinidumpWritable() {}
|
| +
|
| + void SetRVA(MinidumpWritable* other) { other->RegisterRVA(&rva_); }
|
| +
|
| + protected:
|
| + virtual size_t SizeOfObject() override {
|
| + EXPECT_GE(state(), kStateFrozen);
|
| + return sizeof(rva_);
|
| + }
|
| +
|
| + virtual bool WriteObject(FileWriterInterface* file_writer) override {
|
| + BaseTestMinidumpWritable::WriteObject(file_writer);
|
| + EXPECT_TRUE(file_writer->Write(&rva_, sizeof(rva_)));
|
| + return true;
|
| + }
|
| +
|
| + private:
|
| + RVA rva_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestRVAMinidumpWritable);
|
| +};
|
| +
|
| +RVA RVAAtIndex(const std::string& string, size_t index) {
|
| + return *reinterpret_cast<const RVA*>(&string[index * sizeof(RVA)]);
|
| +}
|
| +
|
| +TEST(MinidumpWritable, RVA) {
|
| + StringFileWriter writer;
|
| +
|
| + {
|
| + SCOPED_TRACE("unset");
|
| + writer.Reset();
|
| + TestRVAMinidumpWritable rva_writable;
|
| + EXPECT_TRUE(rva_writable.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(sizeof(RVA), writer.string().size());
|
| + EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 0));
|
| + rva_writable.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("self");
|
| + writer.Reset();
|
| + TestRVAMinidumpWritable rva_writable;
|
| + rva_writable.SetRVA(&rva_writable);
|
| + EXPECT_TRUE(rva_writable.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(sizeof(RVA), writer.string().size());
|
| + EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 0));
|
| + rva_writable.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("parent-child self");
|
| + writer.Reset();
|
| + TestRVAMinidumpWritable parent;
|
| + parent.SetRVA(&parent);
|
| + TestRVAMinidumpWritable child;
|
| + child.SetRVA(&child);
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(2 * sizeof(RVA), writer.string().size());
|
| + EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 0));
|
| + EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 1));
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("parent-child only");
|
| + writer.Reset();
|
| + TestRVAMinidumpWritable parent;
|
| + TestRVAMinidumpWritable child;
|
| + parent.SetRVA(&child);
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(2 * sizeof(RVA), writer.string().size());
|
| + EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 0));
|
| + EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 1));
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("parent-child circular");
|
| + writer.Reset();
|
| + TestRVAMinidumpWritable parent;
|
| + TestRVAMinidumpWritable child;
|
| + parent.SetRVA(&child);
|
| + child.SetRVA(&parent);
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(2 * sizeof(RVA), writer.string().size());
|
| + EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 0));
|
| + EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 1));
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("grandchildren");
|
| + writer.Reset();
|
| + TestRVAMinidumpWritable parent;
|
| + TestRVAMinidumpWritable child;
|
| + parent.SetRVA(&child);
|
| + parent.AddChild(&child);
|
| + TestRVAMinidumpWritable grandchild_0;
|
| + grandchild_0.SetRVA(&child);
|
| + child.AddChild(&grandchild_0);
|
| + TestRVAMinidumpWritable grandchild_1;
|
| + grandchild_1.SetRVA(&child);
|
| + child.AddChild(&grandchild_1);
|
| + TestRVAMinidumpWritable grandchild_2;
|
| + grandchild_2.SetRVA(&child);
|
| + child.AddChild(&grandchild_2);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(5 * sizeof(RVA), writer.string().size());
|
| + EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 0));
|
| + EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 1));
|
| + EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 2));
|
| + EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 3));
|
| + EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 4));
|
| + parent.Verify();
|
| + }
|
| +}
|
| +
|
| +class TestLocationDescriptorMinidumpWritable final
|
| + : public BaseTestMinidumpWritable {
|
| + public:
|
| + TestLocationDescriptorMinidumpWritable()
|
| + : BaseTestMinidumpWritable(), location_descriptor_(), string_() {}
|
| +
|
| + ~TestLocationDescriptorMinidumpWritable() {}
|
| +
|
| + void SetLocationDescriptor(MinidumpWritable* other) {
|
| + other->RegisterLocationDescriptor(&location_descriptor_);
|
| + }
|
| +
|
| + void SetString(const std::string& string) { string_ = string; }
|
| +
|
| + protected:
|
| + virtual size_t SizeOfObject() override {
|
| + EXPECT_GE(state(), kStateFrozen);
|
| + // NUL-terminate.
|
| + return sizeof(location_descriptor_) + string_.size() + 1;
|
| + }
|
| +
|
| + virtual bool WriteObject(FileWriterInterface* file_writer) override {
|
| + BaseTestMinidumpWritable::WriteObject(file_writer);
|
| + WritableIoVec iov;
|
| + iov.iov_base = &location_descriptor_;
|
| + iov.iov_len = sizeof(location_descriptor_);
|
| + std::vector<WritableIoVec> iovecs(1, iov);
|
| + // NUL-terminate.
|
| + iov.iov_base = &string_[0];
|
| + iov.iov_len = string_.size() + 1;
|
| + iovecs.push_back(iov);
|
| + EXPECT_TRUE(file_writer->WriteIoVec(&iovecs));
|
| + return true;
|
| + }
|
| +
|
| + private:
|
| + MINIDUMP_LOCATION_DESCRIPTOR location_descriptor_;
|
| + std::string string_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestLocationDescriptorMinidumpWritable);
|
| +};
|
| +
|
| +struct LocationDescriptorAndData {
|
| + MINIDUMP_LOCATION_DESCRIPTOR location_descriptor;
|
| + char string[1];
|
| +};
|
| +
|
| +const LocationDescriptorAndData* LDDAtIndex(const std::string& string,
|
| + size_t index) {
|
| + return reinterpret_cast<const LocationDescriptorAndData*>(&string[index]);
|
| +}
|
| +
|
| +TEST(MinidumpWritable, LocationDescriptor) {
|
| + StringFileWriter writer;
|
| +
|
| + {
|
| + SCOPED_TRACE("unset");
|
| + writer.Reset();
|
| + TestLocationDescriptorMinidumpWritable location_descriptor_writable;
|
| + EXPECT_TRUE(location_descriptor_writable.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(9u, writer.string().size());
|
| + const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.Rva);
|
| + location_descriptor_writable.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("self");
|
| + writer.Reset();
|
| + TestLocationDescriptorMinidumpWritable location_descriptor_writable;
|
| + location_descriptor_writable.SetLocationDescriptor(
|
| + &location_descriptor_writable);
|
| + EXPECT_TRUE(location_descriptor_writable.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(9u, writer.string().size());
|
| + const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0);
|
| + EXPECT_EQ(9u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.Rva);
|
| + location_descriptor_writable.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("self with data");
|
| + writer.Reset();
|
| + TestLocationDescriptorMinidumpWritable location_descriptor_writable;
|
| + location_descriptor_writable.SetLocationDescriptor(
|
| + &location_descriptor_writable);
|
| + location_descriptor_writable.SetString("zz");
|
| + EXPECT_TRUE(location_descriptor_writable.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(11u, writer.string().size());
|
| + const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0);
|
| + EXPECT_EQ(11u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("zz", ldd->string);
|
| + location_descriptor_writable.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("parent-child self");
|
| + writer.Reset();
|
| + TestLocationDescriptorMinidumpWritable parent;
|
| + parent.SetLocationDescriptor(&parent);
|
| + parent.SetString("yy");
|
| + TestLocationDescriptorMinidumpWritable child;
|
| + child.SetLocationDescriptor(&child);
|
| + child.SetString("x");
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(22u, writer.string().size());
|
| + const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0);
|
| + EXPECT_EQ(11u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("yy", ldd->string);
|
| + ldd = LDDAtIndex(writer.string(), 12);
|
| + EXPECT_EQ(10u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(12u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("x", ldd->string);
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("parent-child only");
|
| + writer.Reset();
|
| + TestLocationDescriptorMinidumpWritable parent;
|
| + TestLocationDescriptorMinidumpWritable child;
|
| + parent.SetLocationDescriptor(&child);
|
| + parent.SetString("www");
|
| + child.SetString("vv");
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(23u, writer.string().size());
|
| + const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0);
|
| + EXPECT_EQ(11u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(12u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("www", ldd->string);
|
| + ldd = LDDAtIndex(writer.string(), 12);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("vv", ldd->string);
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("parent-child circular");
|
| + writer.Reset();
|
| + TestLocationDescriptorMinidumpWritable parent;
|
| + TestLocationDescriptorMinidumpWritable child;
|
| + parent.SetLocationDescriptor(&child);
|
| + parent.SetString("uuuu");
|
| + child.SetLocationDescriptor(&parent);
|
| + child.SetString("tttt");
|
| + parent.AddChild(&child);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(29u, writer.string().size());
|
| + const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0);
|
| + EXPECT_EQ(13u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(16u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("uuuu", ldd->string);
|
| + ldd = LDDAtIndex(writer.string(), 16);
|
| + EXPECT_EQ(13u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("tttt", ldd->string);
|
| + parent.Verify();
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("grandchildren");
|
| + writer.Reset();
|
| + TestLocationDescriptorMinidumpWritable parent;
|
| + TestLocationDescriptorMinidumpWritable child;
|
| + parent.SetLocationDescriptor(&child);
|
| + parent.SetString("s");
|
| + parent.AddChild(&child);
|
| + child.SetString("r");
|
| + TestLocationDescriptorMinidumpWritable grandchild_0;
|
| + grandchild_0.SetLocationDescriptor(&child);
|
| + grandchild_0.SetString("q");
|
| + child.AddChild(&grandchild_0);
|
| + TestLocationDescriptorMinidumpWritable grandchild_1;
|
| + grandchild_1.SetLocationDescriptor(&child);
|
| + grandchild_1.SetString("p");
|
| + child.AddChild(&grandchild_1);
|
| + TestLocationDescriptorMinidumpWritable grandchild_2;
|
| + grandchild_2.SetLocationDescriptor(&child);
|
| + grandchild_2.SetString("o");
|
| + child.AddChild(&grandchild_2);
|
| + EXPECT_TRUE(parent.WriteEverything(&writer));
|
| +
|
| + ASSERT_EQ(58u, writer.string().size());
|
| + const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0);
|
| + EXPECT_EQ(10u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(12u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("s", ldd->string);
|
| + ldd = LDDAtIndex(writer.string(), 12);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(0u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("r", ldd->string);
|
| + ldd = LDDAtIndex(writer.string(), 24);
|
| + EXPECT_EQ(10u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(12u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("q", ldd->string);
|
| + ldd = LDDAtIndex(writer.string(), 36);
|
| + EXPECT_EQ(10u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(12u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("p", ldd->string);
|
| + ldd = LDDAtIndex(writer.string(), 48);
|
| + EXPECT_EQ(10u, ldd->location_descriptor.DataSize);
|
| + EXPECT_EQ(12u, ldd->location_descriptor.Rva);
|
| + EXPECT_STREQ("o", ldd->string);
|
| + parent.Verify();
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
|
|