Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "minidump/minidump_file_writer.h" | |
| 16 | |
| 17 #include <dbghelp.h> | |
| 18 | |
| 19 #include <string> | |
| 20 | |
| 21 #include "base/basictypes.h" | |
| 22 #include "gtest/gtest.h" | |
| 23 #include "minidump/minidump_stream_writer.h" | |
| 24 #include "minidump/minidump_writable.h" | |
| 25 #include "util/file/file_writer.h" | |
| 26 #include "util/file/string_file_writer.h" | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 using namespace crashpad; | |
| 31 | |
| 32 TEST(MinidumpFileWriter, Empty) { | |
| 33 MinidumpFileWriter minidump_file; | |
| 34 StringFileWriter file_writer; | |
| 35 ASSERT_TRUE(minidump_file.WriteEverything(&file_writer)); | |
| 36 ASSERT_EQ(sizeof(MINIDUMP_HEADER), file_writer.string().size()); | |
| 37 | |
| 38 const MINIDUMP_HEADER* header = | |
| 39 reinterpret_cast<const MINIDUMP_HEADER*>(&file_writer.string()[0]); | |
| 40 | |
| 41 EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_SIGNATURE), header->Signature); | |
| 42 EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_VERSION), header->Version); | |
| 43 EXPECT_EQ(0u, header->NumberOfStreams); | |
| 44 EXPECT_EQ(0u, header->StreamDirectoryRva); | |
| 45 EXPECT_EQ(0u, header->CheckSum); | |
| 46 EXPECT_EQ(0u, header->TimeDateStamp); | |
| 47 EXPECT_EQ(MiniDumpNormal, header->Flags); | |
| 48 } | |
| 49 | |
| 50 class TestStream final : public internal::MinidumpStreamWriter { | |
| 51 public: | |
| 52 TestStream(MinidumpStreamType stream_type, | |
| 53 size_t stream_size, | |
| 54 uint8_t stream_value) | |
| 55 : stream_data_(stream_size, stream_value), stream_type_(stream_type) {} | |
| 56 | |
| 57 ~TestStream() {} | |
| 58 | |
| 59 // MinidumpStreamWriter: | |
| 60 virtual MinidumpStreamType StreamType() const override { | |
| 61 return stream_type_; | |
| 62 } | |
| 63 | |
| 64 protected: | |
| 65 // MinidumpWritable: | |
| 66 virtual size_t SizeOfObject() override { | |
| 67 EXPECT_GE(state(), kStateFrozen); | |
| 68 return stream_data_.size(); | |
| 69 } | |
| 70 | |
| 71 virtual bool WriteObject(FileWriterInterface* file_writer) override { | |
| 72 EXPECT_EQ(state(), kStateWritable); | |
| 73 return file_writer->Write(&stream_data_[0], stream_data_.size()); | |
| 74 } | |
| 75 | |
| 76 private: | |
| 77 std::string stream_data_; | |
| 78 MinidumpStreamType stream_type_; | |
| 79 | |
| 80 DISALLOW_COPY_AND_ASSIGN(TestStream); | |
| 81 }; | |
| 82 | |
| 83 TEST(MinidumpFileWriter, OneStream) { | |
| 84 MinidumpFileWriter minidump_file; | |
| 85 const time_t kTimestamp = 0x155d2fb8; | |
| 86 minidump_file.SetTimestamp(kTimestamp); | |
| 87 | |
| 88 const size_t kStreamSize = 5; | |
| 89 const MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d); | |
| 90 const uint8_t kStreamValue = 0x5a; | |
| 91 TestStream stream(kStreamType, kStreamSize, kStreamValue); | |
| 92 minidump_file.AddStream(&stream); | |
| 93 | |
| 94 StringFileWriter file_writer; | |
| 95 ASSERT_TRUE(minidump_file.WriteEverything(&file_writer)); | |
| 96 | |
| 97 const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); | |
| 98 const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); | |
| 99 const size_t kFileSize = kStreamOffset + kStreamSize; | |
| 100 | |
| 101 ASSERT_EQ(kFileSize, file_writer.string().size()); | |
| 102 | |
| 103 const MINIDUMP_HEADER* header = | |
| 104 reinterpret_cast<const MINIDUMP_HEADER*>(&file_writer.string()[0]); | |
| 105 | |
| 106 EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_SIGNATURE), header->Signature); | |
| 107 EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_VERSION), header->Version); | |
| 108 EXPECT_EQ(1u, header->NumberOfStreams); | |
| 109 EXPECT_EQ(kDirectoryOffset, header->StreamDirectoryRva); | |
| 110 EXPECT_EQ(0u, header->CheckSum); | |
| 111 EXPECT_EQ(kTimestamp, header->TimeDateStamp); | |
| 112 EXPECT_EQ(MiniDumpNormal, header->Flags); | |
| 113 | |
| 114 const MINIDUMP_DIRECTORY* directory = | |
| 115 reinterpret_cast<const MINIDUMP_DIRECTORY*>( | |
| 116 &file_writer.string()[kDirectoryOffset]); | |
| 117 | |
| 118 EXPECT_EQ(kStreamType, directory->StreamType); | |
| 119 EXPECT_EQ(kStreamSize, directory->Location.DataSize); | |
| 120 EXPECT_EQ(kStreamOffset, directory->Location.Rva); | |
| 121 | |
| 122 const uint8_t* stream_data = | |
| 123 reinterpret_cast<const uint8_t*>(&file_writer.string()[kStreamOffset]); | |
| 124 | |
| 125 std::string expected_stream(kStreamSize, kStreamValue); | |
| 126 EXPECT_EQ(0, memcmp(stream_data, expected_stream.c_str(), kStreamSize)); | |
| 127 } | |
| 128 | |
| 129 TEST(MinidumpFileWriter, ThreeStreams) { | |
| 130 MinidumpFileWriter minidump_file; | |
| 131 const time_t kTimestamp = 0x155d2fb8; | |
| 132 minidump_file.SetTimestamp(kTimestamp); | |
| 133 | |
| 134 const size_t kStream1Size = 5; | |
| 135 const MinidumpStreamType kStream1Type = static_cast<MinidumpStreamType>(0x6d); | |
| 136 const uint8_t kStream1Value = 0x5a; | |
| 137 TestStream stream1(kStream1Type, kStream1Size, kStream1Value); | |
| 138 minidump_file.AddStream(&stream1); | |
| 139 | |
| 140 // Make the second stream’s type be a smaller quantity than the first stream’s | |
| 141 // to test that the streams show up in the order that they were added, not in | |
| 142 // numeric order. | |
| 143 const size_t kStream2Size = 3; | |
| 144 const MinidumpStreamType kStream2Type = static_cast<MinidumpStreamType>(0x4d); | |
| 145 const uint8_t kStream2Value = 0xa5; | |
| 146 TestStream stream2(kStream2Type, kStream2Size, kStream2Value); | |
| 147 minidump_file.AddStream(&stream2); | |
| 148 | |
| 149 const size_t kStream3Size = 1; | |
| 150 const MinidumpStreamType kStream3Type = static_cast<MinidumpStreamType>(0x7e); | |
| 151 const uint8_t kStream3Value = 0x36; | |
| 152 TestStream stream3(kStream3Type, kStream3Size, kStream3Value); | |
| 153 minidump_file.AddStream(&stream3); | |
| 154 | |
| 155 StringFileWriter file_writer; | |
| 156 ASSERT_TRUE(minidump_file.WriteEverything(&file_writer)); | |
| 157 | |
| 158 const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); | |
| 159 const size_t kStream1Offset = | |
| 160 kDirectoryOffset + 3 * sizeof(MINIDUMP_DIRECTORY); | |
| 161 const size_t kStream2Padding = 3; | |
| 162 const size_t kStream2Offset = kStream1Offset + kStream1Size + kStream2Padding; | |
| 163 const size_t kStream3Padding = 1; | |
| 164 const size_t kStream3Offset = kStream2Offset + kStream2Size + kStream3Padding; | |
| 165 const size_t kFileSize = kStream3Offset + kStream3Size; | |
| 166 | |
| 167 ASSERT_EQ(kFileSize, file_writer.string().size()); | |
| 168 | |
| 169 const MINIDUMP_HEADER* header = | |
| 170 reinterpret_cast<const MINIDUMP_HEADER*>(&file_writer.string()[0]); | |
| 171 | |
| 172 EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_SIGNATURE), header->Signature); | |
| 173 EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_VERSION), header->Version); | |
| 174 EXPECT_EQ(3u, header->NumberOfStreams); | |
| 175 EXPECT_EQ(kDirectoryOffset, header->StreamDirectoryRva); | |
| 176 EXPECT_EQ(0u, header->CheckSum); | |
| 177 EXPECT_EQ(kTimestamp, header->TimeDateStamp); | |
| 178 EXPECT_EQ(MiniDumpNormal, header->Flags); | |
| 179 | |
| 180 const MINIDUMP_DIRECTORY* directory = | |
| 181 reinterpret_cast<const MINIDUMP_DIRECTORY*>( | |
| 182 &file_writer.string()[kDirectoryOffset]); | |
| 183 | |
| 184 EXPECT_EQ(kStream1Type, directory[0].StreamType); | |
| 185 EXPECT_EQ(kStream1Size, directory[0].Location.DataSize); | |
| 186 EXPECT_EQ(kStream1Offset, directory[0].Location.Rva); | |
| 187 EXPECT_EQ(kStream2Type, directory[1].StreamType); | |
| 188 EXPECT_EQ(kStream2Size, directory[1].Location.DataSize); | |
| 189 EXPECT_EQ(kStream2Offset, directory[1].Location.Rva); | |
| 190 EXPECT_EQ(kStream3Type, directory[2].StreamType); | |
| 191 EXPECT_EQ(kStream3Size, directory[2].Location.DataSize); | |
| 192 EXPECT_EQ(kStream3Offset, directory[2].Location.Rva); | |
| 193 | |
| 194 const uint8_t* stream1_data = | |
| 195 reinterpret_cast<const uint8_t*>(&file_writer.string()[kStream1Offset]); | |
| 196 | |
| 197 std::string expected_stream1(kStream1Size, kStream1Value); | |
| 198 EXPECT_EQ(0, memcmp(stream1_data, expected_stream1.c_str(), kStream1Size)); | |
| 199 | |
| 200 const int kZeroes[16] = {}; | |
| 201 ASSERT_GE(sizeof(kZeroes), kStream2Padding); | |
| 202 ASSERT_GE(sizeof(kZeroes), kStream3Padding); | |
| 203 | |
| 204 EXPECT_EQ(0, memcmp(stream1_data + kStream1Size, kZeroes, kStream2Padding)); | |
| 205 | |
| 206 const uint8_t* stream2_data = | |
| 207 reinterpret_cast<const uint8_t*>(&file_writer.string()[kStream2Offset]); | |
| 208 | |
| 209 std::string expected_stream2(kStream2Size, kStream2Value); | |
| 210 EXPECT_EQ(0, memcmp(stream2_data, expected_stream2.c_str(), kStream2Size)); | |
| 211 | |
| 212 EXPECT_EQ(0, memcmp(stream2_data + kStream2Size, kZeroes, kStream3Padding)); | |
| 213 | |
| 214 const uint8_t* stream3_data = | |
| 215 reinterpret_cast<const uint8_t*>(&file_writer.string()[kStream3Offset]); | |
| 216 | |
| 217 std::string expected_stream3(kStream3Size, kStream3Value); | |
| 218 EXPECT_EQ(0, memcmp(stream3_data, expected_stream3.c_str(), kStream3Size)); | |
| 219 } | |
| 220 | |
| 221 TEST(MinidumpFileWriterDeathTest, SameStreamType) { | |
| 222 MinidumpFileWriter minidump_file; | |
| 223 | |
| 224 const size_t kStream1Size = 5; | |
| 225 const MinidumpStreamType kStream1Type = static_cast<MinidumpStreamType>(0x4d); | |
| 226 const uint8_t kStream1Value = 0x5a; | |
| 227 TestStream stream1(kStream1Type, kStream1Size, kStream1Value); | |
| 228 minidump_file.AddStream(&stream1); | |
| 229 | |
| 230 // It is an error to add a second stream of the same type. | |
| 231 const size_t kStream2Size = 3; | |
| 232 const MinidumpStreamType kStream2Type = static_cast<MinidumpStreamType>(0x4d); | |
| 233 const uint8_t kStream2Value = 0xa5; | |
| 234 TestStream stream2(kStream2Type, kStream2Size, kStream2Value); | |
| 235 ASSERT_DEATH(minidump_file.AddStream(&stream2), "already present"); | |
|
Robert Sesek
2014/08/03 21:20:55
I guess this is why exceptions are kind of nice, b
Mark Mentovai
2014/08/03 22:45:54
rsesek wrote:
| |
| 236 } | |
| 237 | |
| 238 } // namespace | |
| OLD | NEW |