Chromium Code Reviews| Index: minidump/minidump_thread_writer_test.cc |
| diff --git a/minidump/minidump_thread_writer_test.cc b/minidump/minidump_thread_writer_test.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ef817b685a505263f015ecbb084e7574b73f2ec8 |
| --- /dev/null |
| +++ b/minidump/minidump_thread_writer_test.cc |
| @@ -0,0 +1,556 @@ |
| +// 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_thread_writer.h" |
| + |
| +#include <dbghelp.h> |
| + |
| +#include "gtest/gtest.h" |
| +#include "minidump/minidump_context_test_util.h" |
| +#include "minidump/minidump_context_writer.h" |
| +#include "minidump/minidump_memory_writer.h" |
| +#include "minidump/minidump_memory_writer_test_util.h" |
| +#include "minidump/minidump_file_writer.h" |
| +#include "minidump/minidump_test_util.h" |
| +#include "util/file/string_file_writer.h" |
| + |
| +namespace crashpad { |
| +namespace test { |
| +namespace { |
| + |
| +// This returns the MINIDUMP_THREAD_LIST stream in |thread_list|. If |
| +// |memory_list| is non-NULL, a MINIDUMP_MEMORY_LIST stream is also expected in |
| +// |file_contents|, and that stream will be returned in |memory_list|. |
| +void GetThreadListStream(const std::string& file_contents, |
| + const MINIDUMP_THREAD_LIST** thread_list, |
| + const MINIDUMP_MEMORY_LIST** memory_list) { |
| + const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); |
| + const uint32_t kExpectedStreams = memory_list ? 2 : 1; |
| + const size_t kThreadListStreamOffset = |
| + kDirectoryOffset + kExpectedStreams * sizeof(MINIDUMP_DIRECTORY); |
| + const size_t kThreadsOffset = |
| + kThreadListStreamOffset + sizeof(MINIDUMP_THREAD_LIST); |
| + |
| + ASSERT_GE(file_contents.size(), kThreadsOffset); |
| + |
| + const MINIDUMP_HEADER* header = |
| + reinterpret_cast<const MINIDUMP_HEADER*>(&file_contents[0]); |
| + |
| + VerifyMinidumpHeader(header, kExpectedStreams, 0); |
| + if (testing::Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + const MINIDUMP_DIRECTORY* directory = |
| + reinterpret_cast<const MINIDUMP_DIRECTORY*>( |
| + &file_contents[kDirectoryOffset]); |
| + |
| + ASSERT_EQ(kMinidumpStreamTypeThreadList, directory[0].StreamType); |
| + ASSERT_GE(directory[0].Location.DataSize, sizeof(MINIDUMP_THREAD_LIST)); |
| + ASSERT_EQ(kThreadListStreamOffset, directory[0].Location.Rva); |
| + |
| + *thread_list = reinterpret_cast<const MINIDUMP_THREAD_LIST*>( |
| + &file_contents[kThreadListStreamOffset]); |
| + |
| + ASSERT_EQ(sizeof(MINIDUMP_THREAD_LIST) + |
| + (*thread_list)->NumberOfThreads * sizeof(MINIDUMP_THREAD), |
| + directory[0].Location.DataSize); |
| + |
| + if (memory_list) { |
| + *memory_list = reinterpret_cast<const MINIDUMP_MEMORY_LIST*>( |
| + &file_contents[directory[1].Location.Rva]); |
| + } |
| +} |
| + |
| +TEST(MinidumpThreadWriter, EmptyThreadList) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpThreadListWriter thread_list_writer; |
| + |
| + minidump_file_writer.AddStream(&thread_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_THREAD_LIST), |
| + file_writer.string().size()); |
| + |
| + const MINIDUMP_THREAD_LIST* thread_list; |
| + GetThreadListStream(file_writer.string(), &thread_list, NULL); |
| + if (Test::HasFatalFailure()) { |
|
Robert Sesek
2014/10/08 21:49:31
You use testing::Test above but not here.
Mark Mentovai
2014/10/08 22:41:03
Robert Sesek wrote:
|
| + return; |
| + } |
| + |
| + EXPECT_EQ(0u, thread_list->NumberOfThreads); |
| +} |
| + |
| +// The MINIDUMP_THREADs |expected| and |observed| are compared against each |
| +// other using gtest assertions. If |stack| is non-NULL, |observed| is expected |
| +// to contain a populated MINIDUMP_MEMORY_DESCRIPTOR in its Stack field, |
| +// otherwise, its Stack field is expected to be zeroed out. The memory |
| +// descriptor will be placed in |stack|. |observed| must contain a populated |
| +// ThreadContext field. The context will be recovered from |file_contents| and |
| +// stored in |context_base|. |
| +void ExpectThread(const MINIDUMP_THREAD* expected, |
| + const MINIDUMP_THREAD* observed, |
| + const std::string& file_contents, |
| + const MINIDUMP_MEMORY_DESCRIPTOR** stack, |
| + const void** context_base) { |
| + EXPECT_EQ(expected->ThreadId, observed->ThreadId); |
| + EXPECT_EQ(expected->SuspendCount, observed->SuspendCount); |
| + EXPECT_EQ(expected->PriorityClass, observed->PriorityClass); |
| + EXPECT_EQ(expected->Priority, observed->Priority); |
| + EXPECT_EQ(expected->Teb, observed->Teb); |
| + |
| + EXPECT_EQ(expected->Stack.StartOfMemoryRange, |
| + observed->Stack.StartOfMemoryRange); |
| + EXPECT_EQ(expected->Stack.Memory.DataSize, observed->Stack.Memory.DataSize); |
| + if (stack) { |
| + ASSERT_NE(0u, observed->Stack.Memory.DataSize); |
| + ASSERT_NE(0u, observed->Stack.Memory.Rva); |
| + ASSERT_GE(file_contents.size(), |
| + observed->Stack.Memory.Rva + observed->Stack.Memory.DataSize); |
| + *stack = &observed->Stack; |
| + } else { |
| + EXPECT_EQ(0u, observed->Stack.StartOfMemoryRange); |
| + EXPECT_EQ(0u, observed->Stack.Memory.DataSize); |
| + EXPECT_EQ(0u, observed->Stack.Memory.Rva); |
| + } |
| + |
| + EXPECT_EQ(expected->ThreadContext.DataSize, observed->ThreadContext.DataSize); |
| + ASSERT_NE(0u, observed->ThreadContext.DataSize); |
| + ASSERT_NE(0u, observed->ThreadContext.Rva); |
| + ASSERT_GE(file_contents.size(), |
| + observed->ThreadContext.Rva + expected->ThreadContext.DataSize); |
| + *context_base = &file_contents[observed->ThreadContext.Rva]; |
| +} |
| + |
| +TEST(MinidumpThreadWriter, OneThread_x86_NoStack) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpThreadListWriter thread_list_writer; |
| + |
| + const uint32_t kThreadID = 0x11111111; |
| + const uint32_t kSuspendCount = 1; |
| + const uint32_t kPriorityClass = 0x20; |
| + const uint32_t kPriority = 10; |
| + const uint64_t kTEB = 0x55555555; |
| + const uint32_t kSeed = 123; |
| + |
| + MinidumpThreadWriter thread_writer; |
| + thread_writer.SetThreadID(kThreadID); |
| + thread_writer.SetSuspendCount(kSuspendCount); |
| + thread_writer.SetPriorityClass(kPriorityClass); |
| + thread_writer.SetPriority(kPriority); |
| + thread_writer.SetTEB(kTEB); |
| + |
| + MinidumpContextX86Writer context_x86_writer; |
| + InitializeMinidumpContextX86(context_x86_writer.context(), kSeed); |
| + thread_writer.SetContext(&context_x86_writer); |
| + |
| + thread_list_writer.AddThread(&thread_writer); |
| + minidump_file_writer.AddStream(&thread_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_THREAD_LIST) + 1 * sizeof(MINIDUMP_THREAD) + |
| + 1 * sizeof(MinidumpContextX86), |
| + file_writer.string().size()); |
| + |
| + const MINIDUMP_THREAD_LIST* thread_list; |
| + GetThreadListStream(file_writer.string(), &thread_list, NULL); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + EXPECT_EQ(1u, thread_list->NumberOfThreads); |
| + |
| + MINIDUMP_THREAD expected = {}; |
| + expected.ThreadId = kThreadID; |
| + expected.SuspendCount = kSuspendCount; |
| + expected.PriorityClass = kPriorityClass; |
| + expected.Priority = kPriority; |
| + expected.Teb = kTEB; |
| + expected.ThreadContext.DataSize = sizeof(MinidumpContextX86); |
| + |
| + const MinidumpContextX86* observed_context; |
| + ExpectThread(&expected, |
| + &thread_list->Threads[0], |
| + file_writer.string(), |
| + NULL, |
| + reinterpret_cast<const void**>(&observed_context)); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMinidumpContextX86(kSeed, observed_context); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| +} |
| + |
| +TEST(MinidumpThreadWriter, OneThread_AMD64_Stack) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpThreadListWriter thread_list_writer; |
| + |
| + const uint32_t kThreadID = 0x22222222; |
| + const uint32_t kSuspendCount = 2; |
| + const uint32_t kPriorityClass = 0x30; |
| + const uint32_t kPriority = 20; |
| + const uint64_t kTEB = 0x5555555555555555; |
| + const uint64_t kMemoryBase = 0x765432100000; |
| + const size_t kMemorySize = 32; |
| + const uint8_t kMemoryValue = 99; |
| + const uint32_t kSeed = 456; |
| + |
| + MinidumpThreadWriter thread_writer; |
| + thread_writer.SetThreadID(kThreadID); |
| + thread_writer.SetSuspendCount(kSuspendCount); |
| + thread_writer.SetPriorityClass(kPriorityClass); |
| + thread_writer.SetPriority(kPriority); |
| + thread_writer.SetTEB(kTEB); |
| + |
| + TestMinidumpMemoryWriter memory_writer( |
| + kMemoryBase, kMemorySize, kMemoryValue); |
| + thread_writer.SetStack(&memory_writer); |
| + |
| + MinidumpContextAMD64Writer context_amd64_writer; |
| + InitializeMinidumpContextAMD64(context_amd64_writer.context(), kSeed); |
| + thread_writer.SetContext(&context_amd64_writer); |
| + |
| + thread_list_writer.AddThread(&thread_writer); |
| + minidump_file_writer.AddStream(&thread_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_THREAD_LIST) + 1 * sizeof(MINIDUMP_THREAD) + |
| + 1 * sizeof(MinidumpContextAMD64) + kMemorySize, |
| + file_writer.string().size()); |
| + |
| + const MINIDUMP_THREAD_LIST* thread_list; |
| + GetThreadListStream(file_writer.string(), &thread_list, NULL); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + EXPECT_EQ(1u, thread_list->NumberOfThreads); |
| + |
| + MINIDUMP_THREAD expected = {}; |
| + expected.ThreadId = kThreadID; |
| + expected.SuspendCount = kSuspendCount; |
| + expected.PriorityClass = kPriorityClass; |
| + expected.Priority = kPriority; |
| + expected.Teb = kTEB; |
| + expected.Stack.StartOfMemoryRange = kMemoryBase; |
| + expected.Stack.Memory.DataSize = kMemorySize; |
| + expected.ThreadContext.DataSize = sizeof(MinidumpContextAMD64); |
| + |
| + const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack; |
| + const MinidumpContextAMD64* observed_context; |
| + ExpectThread(&expected, |
| + &thread_list->Threads[0], |
| + file_writer.string(), |
| + &observed_stack, |
| + reinterpret_cast<const void**>(&observed_context)); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMinidumpMemoryDescriptorAndContents(&expected.Stack, |
| + observed_stack, |
| + file_writer.string(), |
| + kMemoryValue, |
| + true); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMinidumpContextAMD64(kSeed, observed_context); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| +} |
| + |
| +// The two MINIDUMP_MEMORY_DESCRIPTOR arguments are compared for equality using |
| +// gtest assertions. |
| +void ExpectMemoryDescriptors(const MINIDUMP_MEMORY_DESCRIPTOR* expected, |
|
Robert Sesek
2014/10/08 21:49:31
This may be useful in a more general location.
|
| + const MINIDUMP_MEMORY_DESCRIPTOR* observed) { |
| + EXPECT_EQ(expected->StartOfMemoryRange, observed->StartOfMemoryRange); |
| + EXPECT_EQ(expected->Memory.DataSize, observed->Memory.DataSize); |
| + EXPECT_EQ(expected->Memory.Rva, observed->Memory.Rva); |
| +} |
| + |
| +TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpThreadListWriter thread_list_writer; |
| + MinidumpMemoryListWriter memory_list_writer; |
| + thread_list_writer.SetMemoryListWriter(&memory_list_writer); |
| + |
| + const uint32_t kThreadID1 = 1111111; |
| + const uint32_t kSuspendCount1 = 111111; |
| + const uint32_t kPriorityClass1 = 11111; |
| + const uint32_t kPriority1 = 1111; |
| + const uint64_t kTEB1 = 111; |
| + const uint64_t kMemoryBase1 = 0x1110; |
| + const size_t kMemorySize1 = 16; |
| + const uint8_t kMemoryValue1 = 11; |
| + const uint32_t kSeed1 = 1; |
| + |
| + MinidumpThreadWriter thread_writer_1; |
| + thread_writer_1.SetThreadID(kThreadID1); |
| + thread_writer_1.SetSuspendCount(kSuspendCount1); |
| + thread_writer_1.SetPriorityClass(kPriorityClass1); |
| + thread_writer_1.SetPriority(kPriority1); |
| + thread_writer_1.SetTEB(kTEB1); |
| + |
| + TestMinidumpMemoryWriter memory_writer_1( |
| + kMemoryBase1, kMemorySize1, kMemoryValue1); |
| + thread_writer_1.SetStack(&memory_writer_1); |
| + |
| + MinidumpContextX86Writer context_x86_writer_1; |
| + InitializeMinidumpContextX86(context_x86_writer_1.context(), kSeed1); |
| + thread_writer_1.SetContext(&context_x86_writer_1); |
| + |
| + thread_list_writer.AddThread(&thread_writer_1); |
| + |
| + const uint32_t kThreadID2 = 2222222; |
| + const uint32_t kSuspendCount2 = 222222; |
| + const uint32_t kPriorityClass2 = 22222; |
| + const uint32_t kPriority2 = 2222; |
| + const uint64_t kTEB2 = 222; |
| + const uint64_t kMemoryBase2 = 0x2220; |
| + const size_t kMemorySize2 = 32; |
| + const uint8_t kMemoryValue2 = 22; |
| + const uint32_t kSeed2 = 2; |
| + |
| + MinidumpThreadWriter thread_writer_2; |
| + thread_writer_2.SetThreadID(kThreadID2); |
| + thread_writer_2.SetSuspendCount(kSuspendCount2); |
| + thread_writer_2.SetPriorityClass(kPriorityClass2); |
| + thread_writer_2.SetPriority(kPriority2); |
| + thread_writer_2.SetTEB(kTEB2); |
| + |
| + TestMinidumpMemoryWriter memory_writer_2( |
| + kMemoryBase2, kMemorySize2, kMemoryValue2); |
| + thread_writer_2.SetStack(&memory_writer_2); |
| + |
| + MinidumpContextX86Writer context_x86_writer_2; |
| + InitializeMinidumpContextX86(context_x86_writer_2.context(), kSeed2); |
| + thread_writer_2.SetContext(&context_x86_writer_2); |
| + |
| + thread_list_writer.AddThread(&thread_writer_2); |
| + |
| + const uint32_t kThreadID3 = 3333333; |
| + const uint32_t kSuspendCount3 = 333333; |
| + const uint32_t kPriorityClass3 = 33333; |
| + const uint32_t kPriority3 = 3333; |
| + const uint64_t kTEB3 = 333; |
| + const uint64_t kMemoryBase3 = 0x3330; |
| + const size_t kMemorySize3 = 48; |
| + const uint8_t kMemoryValue3 = 33; |
| + const uint32_t kSeed3 = 3; |
| + |
| + MinidumpThreadWriter thread_writer_3; |
| + thread_writer_3.SetThreadID(kThreadID3); |
| + thread_writer_3.SetSuspendCount(kSuspendCount3); |
| + thread_writer_3.SetPriorityClass(kPriorityClass3); |
| + thread_writer_3.SetPriority(kPriority3); |
| + thread_writer_3.SetTEB(kTEB3); |
| + |
| + TestMinidumpMemoryWriter memory_writer_3( |
| + kMemoryBase3, kMemorySize3, kMemoryValue3); |
| + thread_writer_3.SetStack(&memory_writer_3); |
| + |
| + MinidumpContextX86Writer context_x86_writer_3; |
| + InitializeMinidumpContextX86(context_x86_writer_3.context(), kSeed3); |
| + thread_writer_3.SetContext(&context_x86_writer_3); |
| + |
| + thread_list_writer.AddThread(&thread_writer_3); |
| + |
| + minidump_file_writer.AddStream(&thread_list_writer); |
| + minidump_file_writer.AddStream(&memory_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| + |
| + ASSERT_EQ(sizeof(MINIDUMP_HEADER) + 2 * sizeof(MINIDUMP_DIRECTORY) + |
| + sizeof(MINIDUMP_THREAD_LIST) + 3 * sizeof(MINIDUMP_THREAD) + |
| + sizeof(MINIDUMP_MEMORY_LIST) + |
| + 3 * sizeof(MINIDUMP_MEMORY_DESCRIPTOR) + |
| + 3 * sizeof(MinidumpContextX86) + kMemorySize1 + kMemorySize2 + |
| + kMemorySize3 + 12, // 12 for alignment |
| + file_writer.string().size()); |
| + |
| + const MINIDUMP_THREAD_LIST* thread_list; |
| + const MINIDUMP_MEMORY_LIST* memory_list; |
| + GetThreadListStream(file_writer.string(), &thread_list, &memory_list); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + EXPECT_EQ(3u, thread_list->NumberOfThreads); |
| + EXPECT_EQ(3u, memory_list->NumberOfMemoryRanges); |
| + |
| + { |
| + SCOPED_TRACE("thread 0"); |
|
Robert Sesek
2014/10/08 21:49:31
This is "thread 0" in the trace but "1" for all th
|
| + |
| + MINIDUMP_THREAD expected = {}; |
| + expected.ThreadId = kThreadID1; |
| + expected.SuspendCount = kSuspendCount1; |
| + expected.PriorityClass = kPriorityClass1; |
| + expected.Priority = kPriority1; |
| + expected.Teb = kTEB1; |
| + expected.Stack.StartOfMemoryRange = kMemoryBase1; |
| + expected.Stack.Memory.DataSize = kMemorySize1; |
| + expected.ThreadContext.DataSize = sizeof(MinidumpContextX86); |
| + |
| + const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack; |
| + const MinidumpContextX86* observed_context; |
| + ExpectThread(&expected, |
| + &thread_list->Threads[0], |
| + file_writer.string(), |
| + &observed_stack, |
| + reinterpret_cast<const void**>(&observed_context)); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMinidumpMemoryDescriptorAndContents(&expected.Stack, |
| + observed_stack, |
| + file_writer.string(), |
| + kMemoryValue1, |
| + false); |
| + if (Test::HasFatalFailure()) { |
|
Robert Sesek
2014/10/08 21:49:31
This could almost become a macro.
|
| + return; |
| + } |
| + |
| + ExpectMinidumpContextX86(kSeed1, observed_context); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMemoryDescriptors(observed_stack, &memory_list->MemoryRanges[0]); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + } |
| + |
| + { |
| + SCOPED_TRACE("thread 1"); |
| + |
| + MINIDUMP_THREAD expected = {}; |
| + expected.ThreadId = kThreadID2; |
| + expected.SuspendCount = kSuspendCount2; |
| + expected.PriorityClass = kPriorityClass2; |
| + expected.Priority = kPriority2; |
| + expected.Teb = kTEB2; |
| + expected.Stack.StartOfMemoryRange = kMemoryBase2; |
| + expected.Stack.Memory.DataSize = kMemorySize2; |
| + expected.ThreadContext.DataSize = sizeof(MinidumpContextX86); |
| + |
| + const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack; |
| + const MinidumpContextX86* observed_context; |
| + ExpectThread(&expected, |
| + &thread_list->Threads[1], |
| + file_writer.string(), |
| + &observed_stack, |
| + reinterpret_cast<const void**>(&observed_context)); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMinidumpMemoryDescriptorAndContents(&expected.Stack, |
| + observed_stack, |
| + file_writer.string(), |
| + kMemoryValue2, |
| + false); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMinidumpContextX86(kSeed2, observed_context); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMemoryDescriptors(observed_stack, &memory_list->MemoryRanges[1]); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + } |
| + |
| + { |
| + SCOPED_TRACE("thread 2"); |
| + |
| + MINIDUMP_THREAD expected = {}; |
| + expected.ThreadId = kThreadID3; |
| + expected.SuspendCount = kSuspendCount3; |
| + expected.PriorityClass = kPriorityClass3; |
| + expected.Priority = kPriority3; |
| + expected.Teb = kTEB3; |
| + expected.Stack.StartOfMemoryRange = kMemoryBase3; |
| + expected.Stack.Memory.DataSize = kMemorySize3; |
| + expected.ThreadContext.DataSize = sizeof(MinidumpContextX86); |
| + |
| + const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack; |
| + const MinidumpContextX86* observed_context; |
| + ExpectThread(&expected, |
| + &thread_list->Threads[2], |
| + file_writer.string(), |
| + &observed_stack, |
| + reinterpret_cast<const void**>(&observed_context)); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMinidumpMemoryDescriptorAndContents(&expected.Stack, |
| + observed_stack, |
| + file_writer.string(), |
| + kMemoryValue3, |
| + true); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMinidumpContextX86(kSeed3, observed_context); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + |
| + ExpectMemoryDescriptors(observed_stack, &memory_list->MemoryRanges[2]); |
| + if (Test::HasFatalFailure()) { |
| + return; |
| + } |
| + } |
| +} |
| + |
| +TEST(MinidumpThreadWriterDeathTest, NoContext) { |
| + MinidumpFileWriter minidump_file_writer; |
| + MinidumpThreadListWriter thread_list_writer; |
| + |
| + MinidumpThreadWriter thread_writer; |
| + |
| + thread_list_writer.AddThread(&thread_writer); |
| + minidump_file_writer.AddStream(&thread_list_writer); |
| + |
| + StringFileWriter file_writer; |
| + ASSERT_DEATH(minidump_file_writer.WriteEverything(&file_writer), "context_"); |
| +} |
| + |
| +} // namespace |
| +} // namespace test |
| +} // namespace crashpad |