| // 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 <map> |
| #include <string> |
| |
| #import <Foundation/Foundation.h> |
| |
| #include "base/debug/crash_logging.h" |
| #include "base/logging.h" |
| #include "base/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<std::string, std::string>; |
| } |
| |
| ~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<size_t>(kMaxNumURLChunkValueLength)); |
| accumulated_url += value; |
| } |
| |
| return url == accumulated_url; |
| } |
| |
| private: |
| static std::map<std::string, std::string>* dict; |
| DISALLOW_COPY_AND_ASSIGN(MockBreakpadKeyValueStore); |
| }; |
| |
| // static |
| std::map<std::string, std::string>* 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()); |
| } |