// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/common/child_process_logging.h" #include #include #import #include "base/debug/crash_logging.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" typedef PlatformTest ChildProcessLoggingTest; namespace { // Class to mock breakpad's setkeyvalue/clearkeyvalue functions needed for // SetActiveRendererURLImpl. // The Keys are stored in a static dictionary and methods are provided to // verify correctness. class MockBreakpadKeyValueStore { public: MockBreakpadKeyValueStore() { // Only one of these objects can be active at once. DCHECK(dict == NULL); dict = new std::map; } ~MockBreakpadKeyValueStore() { // Only one of these objects can be active at once. DCHECK(dict != NULL); delete dict; dict = NULL; } static void SetKeyValue(const base::StringPiece& key, const base::StringPiece& value) { DCHECK(dict != NULL); (*dict)[key.as_string()] = value.as_string(); } static void ClearKeyValue(const base::StringPiece& key) { DCHECK(dict != NULL); dict->erase(key.as_string()); } size_t CountDictionaryEntries() { return dict->size(); } bool VerifyDictionaryContents(const std::string& url) { using child_process_logging::kMaxNumCrashURLChunks; using child_process_logging::kMaxNumURLChunkValueLength; using child_process_logging::kUrlChunkFormatStr; size_t num_url_chunks = CountDictionaryEntries(); EXPECT_LE(num_url_chunks, kMaxNumCrashURLChunks); std::string accumulated_url; for (size_t i = 0; i < num_url_chunks; ++i) { // URL chunk names are 1-based. std::string key = base::StringPrintf(kUrlChunkFormatStr, i + 1); std::string value = (*dict)[key]; EXPECT_GT(value.length(), 0u); EXPECT_LE(value.length(), static_cast(kMaxNumURLChunkValueLength)); accumulated_url += value; } return url == accumulated_url; } private: static std::map* dict; DISALLOW_COPY_AND_ASSIGN(MockBreakpadKeyValueStore); }; // static std::map* MockBreakpadKeyValueStore::dict; } // namespace // Call through to SetActiveURLImpl using the functions from // MockBreakpadKeyValueStore. void SetActiveURLWithMock(const GURL& url) { using child_process_logging::SetActiveURLImpl; base::debug::SetCrashKeyValueFuncT setFunc = MockBreakpadKeyValueStore::SetKeyValue; base::debug::ClearCrashKeyValueFuncT clearFunc = MockBreakpadKeyValueStore::ClearKeyValue; SetActiveURLImpl(url, setFunc, clearFunc); } TEST_F(ChildProcessLoggingTest, TestUrlSplitting) { using child_process_logging::kMaxNumCrashURLChunks; using child_process_logging::kMaxNumURLChunkValueLength; const std::string short_url("http://abc/"); std::string long_url("http://"); std::string overflow_url("http://"); long_url += std::string(kMaxNumURLChunkValueLength * 2, 'a'); long_url += "/"; int max_num_chars_stored_in_dump = kMaxNumURLChunkValueLength * kMaxNumCrashURLChunks; overflow_url += std::string(max_num_chars_stored_in_dump + 1, 'a'); overflow_url += "/"; // Check that Clearing NULL URL works. MockBreakpadKeyValueStore mock; SetActiveURLWithMock(GURL()); EXPECT_EQ(0u, mock.CountDictionaryEntries()); // Check that we can set a URL. SetActiveURLWithMock(GURL(short_url.c_str())); EXPECT_TRUE(mock.VerifyDictionaryContents(short_url)); EXPECT_EQ(1u, mock.CountDictionaryEntries()); SetActiveURLWithMock(GURL()); EXPECT_EQ(0u, mock.CountDictionaryEntries()); // Check that we can replace a long url with a short url. SetActiveURLWithMock(GURL(long_url.c_str())); EXPECT_TRUE(mock.VerifyDictionaryContents(long_url)); SetActiveURLWithMock(GURL(short_url.c_str())); EXPECT_TRUE(mock.VerifyDictionaryContents(short_url)); SetActiveURLWithMock(GURL()); EXPECT_EQ(0u, mock.CountDictionaryEntries()); // Check that overflow works correctly. SetActiveURLWithMock(GURL(overflow_url.c_str())); EXPECT_TRUE(mock.VerifyDictionaryContents( overflow_url.substr(0, max_num_chars_stored_in_dump))); SetActiveURLWithMock(GURL()); EXPECT_EQ(0u, mock.CountDictionaryEntries()); }