// Copyright 2014 The Crashpad Authors // // 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_id_map.h" #include #include #include #include "gtest/gtest.h" #include "snapshot/test/test_thread_snapshot.h" namespace crashpad { namespace test { namespace { class MinidumpThreadIDMapTest : public testing::Test { public: MinidumpThreadIDMapTest() : Test(), thread_snapshots_(), test_thread_snapshots_() { } MinidumpThreadIDMapTest(const MinidumpThreadIDMapTest&) = delete; MinidumpThreadIDMapTest& operator=(const MinidumpThreadIDMapTest&) = delete; ~MinidumpThreadIDMapTest() override {} // testing::Test: void SetUp() override { for (size_t index = 0; index < std::size(test_thread_snapshots_); ++index) { thread_snapshots_.push_back(&test_thread_snapshots_[index]); } } protected: static bool MapHasKeyValue( const MinidumpThreadIDMap* map, uint64_t key, uint32_t expected_value) { auto iterator = map->find(key); if (iterator == map->end()) { EXPECT_NE(iterator, map->end()); return false; } if (iterator->second != expected_value) { EXPECT_EQ(iterator->second, expected_value); return false; } return true; } void SetThreadID(size_t index, uint64_t thread_id) { ASSERT_LT(index, std::size(test_thread_snapshots_)); test_thread_snapshots_[index].SetThreadID(thread_id); } const std::vector& thread_snapshots() const { return thread_snapshots_; } private: std::vector thread_snapshots_; TestThreadSnapshot test_thread_snapshots_[5]; }; TEST_F(MinidumpThreadIDMapTest, NoThreads) { // Don’t use thread_snapshots(), because it’s got some threads in it, and the // point of this test is to make sure that BuildMinidumpThreadIDMap() works // with no threads. std::vector thread_snapshots; MinidumpThreadIDMap thread_id_map; BuildMinidumpThreadIDMap(thread_snapshots, &thread_id_map); EXPECT_TRUE(thread_id_map.empty()); } TEST_F(MinidumpThreadIDMapTest, SimpleMapping) { SetThreadID(0, 1); SetThreadID(1, 3); SetThreadID(2, 5); SetThreadID(3, 7); SetThreadID(4, 9); MinidumpThreadIDMap thread_id_map; BuildMinidumpThreadIDMap(thread_snapshots(), &thread_id_map); EXPECT_EQ(thread_id_map.size(), 5u); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 1, 1); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 3, 3); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 5, 5); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 7, 7); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 9, 9); } TEST_F(MinidumpThreadIDMapTest, Truncation) { SetThreadID(0, 0x0000000000000000); SetThreadID(1, 0x9999999900000001); SetThreadID(2, 0x9999999980000001); SetThreadID(3, 0x99999999fffffffe); SetThreadID(4, 0x99999999ffffffff); MinidumpThreadIDMap thread_id_map; BuildMinidumpThreadIDMap(thread_snapshots(), &thread_id_map); EXPECT_EQ(thread_id_map.size(), 5u); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000000000000, 0x00000000); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x9999999900000001, 0x00000001); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x9999999980000001, 0x80000001); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x99999999fffffffe, 0xfffffffe); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x99999999ffffffff, 0xffffffff); } TEST_F(MinidumpThreadIDMapTest, DuplicateThreadID) { SetThreadID(0, 2); SetThreadID(1, 4); SetThreadID(2, 4); SetThreadID(3, 6); SetThreadID(4, 8); MinidumpThreadIDMap thread_id_map; BuildMinidumpThreadIDMap(thread_snapshots(), &thread_id_map); EXPECT_EQ(thread_id_map.size(), 4u); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 2, 2); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 4, 4); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 6, 6); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 8, 8); } TEST_F(MinidumpThreadIDMapTest, Collision) { SetThreadID(0, 0x0000000000000010); SetThreadID(1, 0x0000000000000020); SetThreadID(2, 0x0000000000000030); SetThreadID(3, 0x0000000000000040); SetThreadID(4, 0x0000000100000010); MinidumpThreadIDMap thread_id_map; BuildMinidumpThreadIDMap(thread_snapshots(), &thread_id_map); EXPECT_EQ(thread_id_map.size(), 5u); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000000000010, 0); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000000000020, 1); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000000000030, 2); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000000000040, 3); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000100000010, 4); } TEST_F(MinidumpThreadIDMapTest, DuplicateAndCollision) { SetThreadID(0, 0x0000000100000010); SetThreadID(1, 0x0000000000000010); SetThreadID(2, 0x0000000000000020); SetThreadID(3, 0x0000000000000030); SetThreadID(4, 0x0000000000000020); MinidumpThreadIDMap thread_id_map; BuildMinidumpThreadIDMap(thread_snapshots(), &thread_id_map); EXPECT_EQ(thread_id_map.size(), 4u); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000100000010, 0); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000000000010, 1); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000000000020, 2); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 0x0000000000000030, 3); } TEST_F(MinidumpThreadIDMapTest, AllDuplicates) { SetThreadID(0, 6); SetThreadID(1, 6); SetThreadID(2, 6); SetThreadID(3, 6); SetThreadID(4, 6); MinidumpThreadIDMap thread_id_map; BuildMinidumpThreadIDMap(thread_snapshots(), &thread_id_map); EXPECT_EQ(thread_id_map.size(), 1u); EXPECT_PRED3(MapHasKeyValue, &thread_id_map, 6, 6); } } // namespace } // namespace test } // namespace crashpad