| // Copyright (c) 2009 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. |
| |
| #ifndef BASE_TEST_TEST_SUITE_H_ |
| #define BASE_TEST_TEST_SUITE_H_ |
| |
| // Defines a basic test suite framework for running gtest based tests. You can |
| // instantiate this class in your main function and call its Run method to run |
| // any gtest based tests that are linked into your executable. |
| |
| #include "base/at_exit.h" |
| #include "base/base_paths.h" |
| #include "base/debug_on_start.h" |
| #include "base/i18n/icu_util.h" |
| #include "base/multiprocess_test.h" |
| #include "base/nss_util.h" |
| #include "base/path_service.h" |
| #include "base/process_util.h" |
| #include "base/scoped_nsautorelease_pool.h" |
| #include "base/scoped_ptr.h" |
| #include "base/time.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/multiprocess_func_list.h" |
| |
| #if defined(OS_POSIX) && !defined(OS_MACOSX) |
| #include <gtk/gtk.h> |
| #endif |
| |
| // Match function used by the GetTestCount method. |
| typedef bool (*TestMatch)(const testing::TestInfo&); |
| |
| // By setting up a shadow AtExitManager, this test event listener ensures that |
| // no state is carried between tests (like singletons, lazy instances, etc). |
| // Of course it won't help if the code under test corrupts memory. |
| class TestIsolationEnforcer : public testing::EmptyTestEventListener { |
| public: |
| virtual void OnTestStart(const testing::TestInfo& test_info) { |
| ASSERT_FALSE(exit_manager_.get()); |
| exit_manager_.reset(new base::ShadowingAtExitManager()); |
| } |
| |
| virtual void OnTestEnd(const testing::TestInfo& test_info) { |
| ASSERT_TRUE(exit_manager_.get()); |
| exit_manager_.reset(); |
| } |
| |
| private: |
| scoped_ptr<base::ShadowingAtExitManager> exit_manager_; |
| }; |
| |
| class TestSuite { |
| public: |
| TestSuite(int argc, char** argv) { |
| base::EnableTerminationOnHeapCorruption(); |
| CommandLine::Init(argc, argv); |
| testing::InitGoogleTest(&argc, argv); |
| #if defined(OS_POSIX) && !defined(OS_MACOSX) |
| g_thread_init(NULL); |
| gtk_init_check(&argc, &argv); |
| #endif // defined(OS_LINUX) |
| // Don't add additional code to this constructor. Instead add it to |
| // Initialize(). See bug 6436. |
| } |
| |
| virtual ~TestSuite() { |
| CommandLine::Reset(); |
| } |
| |
| // Returns true if a string starts with FLAKY_. |
| static bool IsFlaky(const char* name) { |
| return strncmp(name, "FLAKY_", 6) == 0; |
| } |
| |
| // Returns true if the test is marked as flaky. |
| static bool FlakyTest(const testing::TestInfo& test) { |
| return IsFlaky(test.name()) || IsFlaky(test.test_case_name()); |
| } |
| |
| // Returns true if the test failed and is not marked as flaky. |
| static bool NonFlakyFailures(const testing::TestInfo& test) { |
| return test.should_run() && test.result()->Failed() && !FlakyTest(test); |
| } |
| |
| // Returns the number of tests where the match function returns true. |
| int GetTestCount(TestMatch test_match) { |
| testing::UnitTest* instance = testing::UnitTest::GetInstance(); |
| int count = 0; |
| |
| for (int i = 0; i < instance->total_test_case_count(); ++i) { |
| const testing::TestCase& test_case = *instance->GetTestCase(i); |
| for (int j = 0; j < test_case.total_test_count(); ++j) { |
| if (test_match(*test_case.GetTestInfo(j))) { |
| count++; |
| } |
| } |
| } |
| |
| return count; |
| } |
| |
| // TODO(phajdan.jr): Enforce isolation for all tests once it's stable. |
| void EnforceTestIsolation() { |
| testing::TestEventListeners& listeners = |
| testing::UnitTest::GetInstance()->listeners(); |
| listeners.Append(new TestIsolationEnforcer); |
| } |
| |
| // Don't add additional code to this method. Instead add it to |
| // Initialize(). See bug 6436. |
| int Run() { |
| base::ScopedNSAutoreleasePool scoped_pool; |
| |
| Initialize(); |
| std::wstring client_func = |
| CommandLine::ForCurrentProcess()->GetSwitchValue(kRunClientProcess); |
| // Check to see if we are being run as a client process. |
| if (!client_func.empty()) { |
| // Convert our function name to a usable string for GetProcAddress. |
| std::string func_name(client_func.begin(), client_func.end()); |
| |
| return multi_process_function_list::InvokeChildProcessTest(func_name); |
| } |
| int result = RUN_ALL_TESTS(); |
| |
| // Reset the result code if only flaky test failed. |
| if (result != 0 && GetTestCount(&TestSuite::NonFlakyFailures) == 0) { |
| result = 0; |
| } |
| |
| // Display the number of flaky tests. |
| int flaky_count = GetTestCount(&TestSuite::FlakyTest); |
| if (flaky_count) { |
| printf(" YOU HAVE %d FLAKY %s\n\n", flaky_count, |
| flaky_count == 1 ? "TEST" : "TESTS"); |
| } |
| |
| // This MUST happen before Shutdown() since Shutdown() tears down |
| // objects (such as NotificationService::current()) that Cocoa |
| // objects use to remove themselves as observers. |
| scoped_pool.Recycle(); |
| |
| Shutdown(); |
| |
| return result; |
| } |
| |
| protected: |
| #if defined(OS_WIN) |
| // TODO(phajdan.jr): Clean up the windows-specific hacks. |
| // See http://crbug.com/29997 |
| |
| // By default, base::LogMessage::~LogMessage calls DebugUtil::BreakDebugger() |
| // when severity is LOG_FATAL. On Windows, this results in error dialogs |
| // which are not friendly to buildbots. |
| // To avoid these problems, we override the LogMessage behaviour by |
| // replacing the assert handler with UnitTestAssertHandler. |
| static void UnitTestAssertHandler(const std::string& str) { |
| // FAIL is a googletest macro, it marks the current test as failed. |
| // If throw_on_failure is set to true, it also ends the process. |
| ::testing::FLAGS_gtest_throw_on_failure = true; |
| FAIL() << str; |
| } |
| |
| // Disable crash dialogs so that it doesn't gum up the buildbot |
| virtual void SuppressErrorDialogs() { |
| UINT new_flags = SEM_FAILCRITICALERRORS | |
| SEM_NOGPFAULTERRORBOX | |
| SEM_NOOPENFILEERRORBOX; |
| |
| // Preserve existing error mode, as discussed at |
| // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx |
| UINT existing_flags = SetErrorMode(new_flags); |
| SetErrorMode(existing_flags | new_flags); |
| } |
| #endif // defined(OS_WIN) |
| |
| // Override these for custom initialization and shutdown handling. Use these |
| // instead of putting complex code in your constructor/destructor. |
| |
| virtual void Initialize() { |
| // Initialize logging. |
| FilePath exe; |
| PathService::Get(base::FILE_EXE, &exe); |
| FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); |
| logging::InitLogging(log_filename.value().c_str(), |
| logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, |
| logging::LOCK_LOG_FILE, |
| logging::DELETE_OLD_LOG_FILE); |
| // We want process and thread IDs because we may have multiple processes. |
| // Note: temporarily enabled timestamps in an effort to catch bug 6361. |
| logging::SetLogItems(true, true, true, true); |
| |
| CHECK(base::EnableInProcessStackDumping()); |
| #if defined(OS_WIN) |
| // Make sure we run with high resolution timer to minimize differences |
| // between production code and test code. |
| bool result = base::Time::UseHighResolutionTimer(true); |
| CHECK(result); |
| |
| // In some cases, we do not want to see standard error dialogs. |
| if (!IsDebuggerPresent() && |
| !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) { |
| SuppressErrorDialogs(); |
| #if !defined(PURIFY) |
| // When the code in this file moved around, bug 6436 resurfaced. |
| // As a hack workaround, just #ifdef out this code for Purify builds. |
| logging::SetLogAssertHandler(UnitTestAssertHandler); |
| #endif // !defined(PURIFY) |
| } |
| #endif // defined(OS_WIN) |
| |
| icu_util::Initialize(); |
| |
| #if defined(USE_NSS) |
| // Trying to repeatedly initialize and cleanup NSS and NSPR may result in |
| // a deadlock. Such repeated initialization will happen when using test |
| // isolation. Prevent problems by initializing NSS here, so that the cleanup |
| // will be done only on process exit. |
| base::EnsureNSSInit(); |
| #endif // defined(USE_NSS) |
| } |
| |
| virtual void Shutdown() { |
| } |
| |
| // Make sure that we setup an AtExitManager so Singleton objects will be |
| // destroyed. |
| base::AtExitManager at_exit_manager_; |
| }; |
| |
| #endif // BASE_TEST_TEST_SUITE_H_ |