1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/debug/crash_logging.h" 6 7 #include <map> 8 #include <string> 9 10 #include "base/bind.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 namespace { 14 15 std::map<std::string, std::string>* key_values_ = NULL; 16 17 } // namespace 18 19 class CrashLoggingTest : public testing::Test { 20 public: 21 virtual void SetUp() { 22 key_values_ = new std::map<std::string, std::string>; 23 base::debug::SetCrashKeyReportingFunctions( 24 &CrashLoggingTest::SetKeyValue, 25 &CrashLoggingTest::ClearKeyValue); 26 } 27 28 virtual void TearDown() { 29 base::debug::ResetCrashLoggingForTesting(); 30 31 delete key_values_; 32 key_values_ = NULL; 33 } 34 35 private: 36 static void SetKeyValue(const base::StringPiece& key, 37 const base::StringPiece& value) { 38 (*key_values_)[key.as_string()] = value.as_string(); 39 } 40 41 static void ClearKeyValue(const base::StringPiece& key) { 42 key_values_->erase(key.as_string()); 43 } 44 }; 45 46 TEST_F(CrashLoggingTest, SetClearSingle) { 47 const char* kTestKey = "test-key"; 48 base::debug::CrashKey keys[] = { { kTestKey, 255 } }; 49 base::debug::InitCrashKeys(keys, arraysize(keys), 255); 50 51 base::debug::SetCrashKeyValue(kTestKey, "value"); 52 EXPECT_EQ("value", (*key_values_)[kTestKey]); 53 54 base::debug::ClearCrashKey(kTestKey); 55 EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey)); 56 } 57 58 TEST_F(CrashLoggingTest, SetChunked) { 59 const char* kTestKey = "chunky"; 60 const char* kChunk1 = "chunky-1"; 61 const char* kChunk2 = "chunky-2"; 62 const char* kChunk3 = "chunky-3"; 63 base::debug::CrashKey keys[] = { { kTestKey, 15 } }; 64 base::debug::InitCrashKeys(keys, arraysize(keys), 5); 65 66 std::map<std::string, std::string>& values = *key_values_; 67 68 // Fill only the first chunk. 69 base::debug::SetCrashKeyValue(kTestKey, "foo"); 70 EXPECT_EQ(1u, values.size()); 71 EXPECT_EQ("foo", values[kChunk1]); 72 EXPECT_TRUE(values.end() == values.find(kChunk2)); 73 EXPECT_TRUE(values.end() == values.find(kChunk3)); 74 75 // Fill three chunks with truncation (max length is 15, this string is 20). 76 base::debug::SetCrashKeyValue(kTestKey, "five four three two"); 77 EXPECT_EQ(3u, values.size()); 78 EXPECT_EQ("five ", values[kChunk1]); 79 EXPECT_EQ("four ", values[kChunk2]); 80 EXPECT_EQ("three", values[kChunk3]); 81 82 // Clear everything. 83 base::debug::ClearCrashKey(kTestKey); 84 EXPECT_EQ(0u, values.size()); 85 EXPECT_TRUE(values.end() == values.find(kChunk1)); 86 EXPECT_TRUE(values.end() == values.find(kChunk2)); 87 EXPECT_TRUE(values.end() == values.find(kChunk3)); 88 89 // Refill all three chunks with truncation, then test that setting a smaller 90 // value clears the third chunk. 91 base::debug::SetCrashKeyValue(kTestKey, "five four three two"); 92 base::debug::SetCrashKeyValue(kTestKey, "allays"); 93 EXPECT_EQ(2u, values.size()); 94 EXPECT_EQ("allay", values[kChunk1]); 95 EXPECT_EQ("s", values[kChunk2]); 96 EXPECT_TRUE(values.end() == values.find(kChunk3)); 97 98 // Clear everything. 99 base::debug::ClearCrashKey(kTestKey); 100 EXPECT_EQ(0u, values.size()); 101 EXPECT_TRUE(values.end() == values.find(kChunk1)); 102 EXPECT_TRUE(values.end() == values.find(kChunk2)); 103 EXPECT_TRUE(values.end() == values.find(kChunk3)); 104 } 105 106 TEST_F(CrashLoggingTest, ScopedCrashKey) { 107 const char* kTestKey = "test-key"; 108 base::debug::CrashKey keys[] = { { kTestKey, 255 } }; 109 base::debug::InitCrashKeys(keys, arraysize(keys), 255); 110 111 EXPECT_EQ(0u, key_values_->size()); 112 EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey)); 113 { 114 base::debug::ScopedCrashKey scoped_crash_key(kTestKey, "value"); 115 EXPECT_EQ("value", (*key_values_)[kTestKey]); 116 EXPECT_EQ(1u, key_values_->size()); 117 } 118 EXPECT_EQ(0u, key_values_->size()); 119 EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey)); 120 } 121 122 TEST_F(CrashLoggingTest, InitSize) { 123 base::debug::CrashKey keys[] = { 124 { "chunked-3", 15 }, 125 { "single", 5 }, 126 { "chunked-6", 30 }, 127 }; 128 129 size_t num_keys = base::debug::InitCrashKeys(keys, arraysize(keys), 5); 130 131 EXPECT_EQ(10u, num_keys); 132 133 EXPECT_TRUE(base::debug::LookupCrashKey("chunked-3")); 134 EXPECT_TRUE(base::debug::LookupCrashKey("single")); 135 EXPECT_TRUE(base::debug::LookupCrashKey("chunked-6")); 136 EXPECT_FALSE(base::debug::LookupCrashKey("chunked-6-4")); 137 } 138 139 TEST_F(CrashLoggingTest, ChunkValue) { 140 using base::debug::ChunkCrashKeyValue; 141 142 // Test truncation. 143 base::debug::CrashKey key = { "chunky", 10 }; 144 std::vector<std::string> results = 145 ChunkCrashKeyValue(key, "hello world", 64); 146 ASSERT_EQ(1u, results.size()); 147 EXPECT_EQ("hello worl", results[0]); 148 149 // Test short string. 150 results = ChunkCrashKeyValue(key, "hi", 10); 151 ASSERT_EQ(1u, results.size()); 152 EXPECT_EQ("hi", results[0]); 153 154 // Test chunk pair. 155 key.max_length = 6; 156 results = ChunkCrashKeyValue(key, "foobar", 3); 157 ASSERT_EQ(2u, results.size()); 158 EXPECT_EQ("foo", results[0]); 159 EXPECT_EQ("bar", results[1]); 160 161 // Test chunk pair truncation. 162 results = ChunkCrashKeyValue(key, "foobared", 3); 163 ASSERT_EQ(2u, results.size()); 164 EXPECT_EQ("foo", results[0]); 165 EXPECT_EQ("bar", results[1]); 166 167 // Test extra chunks. 168 key.max_length = 100; 169 results = ChunkCrashKeyValue(key, "hello world", 3); 170 ASSERT_EQ(4u, results.size()); 171 EXPECT_EQ("hel", results[0]); 172 EXPECT_EQ("lo ", results[1]); 173 EXPECT_EQ("wor", results[2]); 174 EXPECT_EQ("ld", results[3]); 175 } 176 177 TEST_F(CrashLoggingTest, ChunkRounding) { 178 // If max_length=12 and max_chunk_length=5, there should be 3 chunks, 179 // not 2. 180 base::debug::CrashKey key = { "round", 12 }; 181 EXPECT_EQ(3u, base::debug::InitCrashKeys(&key, 1, 5)); 182 } 183