1 // Copyright (c) 2011 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/test/test_suite.h" 6 7 #include "base/at_exit.h" 8 #include "base/base_paths.h" 9 #include "base/base_switches.h" 10 #include "base/command_line.h" 11 #include "base/debug/debug_on_start_win.h" 12 #include "base/debug/debugger.h" 13 #include "base/file_path.h" 14 #include "base/i18n/icu_util.h" 15 #include "base/logging.h" 16 #include "base/mac/scoped_nsautorelease_pool.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "base/path_service.h" 19 #include "base/process_util.h" 20 #include "base/test/multiprocess_test.h" 21 #include "base/test/test_timeouts.h" 22 #include "base/time.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/multiprocess_func_list.h" 25 26 #if defined(OS_MACOSX) 27 #include "base/test/mock_chrome_application_mac.h" 28 #endif 29 30 #if defined(TOOLKIT_USES_GTK) 31 #include <gtk/gtk.h> 32 #endif 33 34 namespace { 35 36 class MaybeTestDisabler : public testing::EmptyTestEventListener { 37 public: 38 virtual void OnTestStart(const testing::TestInfo& test_info) { 39 ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info)) 40 << "Probably the OS #ifdefs don't include all of the necessary " 41 "platforms.\nPlease ensure that no tests have the MAYBE_ prefix " 42 "after the code is preprocessed."; 43 } 44 }; 45 46 } // namespace 47 48 const char TestSuite::kStrictFailureHandling[] = "strict_failure_handling"; 49 50 TestSuite::TestSuite(int argc, char** argv) { 51 #if defined(OS_WIN) 52 testing::GTEST_FLAG(catch_exceptions) = false; 53 #endif 54 base::EnableTerminationOnHeapCorruption(); 55 CommandLine::Init(argc, argv); 56 testing::InitGoogleTest(&argc, argv); 57 #if defined(TOOLKIT_USES_GTK) 58 g_thread_init(NULL); 59 gtk_init_check(&argc, &argv); 60 #endif // defined(TOOLKIT_USES_GTK) 61 // Don't add additional code to this constructor. Instead add it to 62 // Initialize(). See bug 6436. 63 } 64 65 TestSuite::~TestSuite() { 66 CommandLine::Reset(); 67 } 68 69 // static 70 bool TestSuite::IsMarkedFlaky(const testing::TestInfo& test) { 71 return strncmp(test.name(), "FLAKY_", 6) == 0; 72 } 73 74 // static 75 bool TestSuite::IsMarkedFailing(const testing::TestInfo& test) { 76 return strncmp(test.name(), "FAILS_", 6) == 0; 77 } 78 79 // static 80 bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) { 81 return strncmp(test.name(), "MAYBE_", 6) == 0; 82 } 83 84 // static 85 bool TestSuite::ShouldIgnoreFailure(const testing::TestInfo& test) { 86 if (CommandLine::ForCurrentProcess()->HasSwitch(kStrictFailureHandling)) 87 return false; 88 return IsMarkedFlaky(test) || IsMarkedFailing(test); 89 } 90 91 // static 92 bool TestSuite::NonIgnoredFailures(const testing::TestInfo& test) { 93 return test.should_run() && test.result()->Failed() && 94 !ShouldIgnoreFailure(test); 95 } 96 97 int TestSuite::GetTestCount(TestMatch test_match) { 98 testing::UnitTest* instance = testing::UnitTest::GetInstance(); 99 int count = 0; 100 101 for (int i = 0; i < instance->total_test_case_count(); ++i) { 102 const testing::TestCase& test_case = *instance->GetTestCase(i); 103 for (int j = 0; j < test_case.total_test_count(); ++j) { 104 if (test_match(*test_case.GetTestInfo(j))) { 105 count++; 106 } 107 } 108 } 109 110 return count; 111 } 112 113 void TestSuite::CatchMaybeTests() { 114 testing::TestEventListeners& listeners = 115 testing::UnitTest::GetInstance()->listeners(); 116 listeners.Append(new MaybeTestDisabler); 117 } 118 119 // Don't add additional code to this method. Instead add it to 120 // Initialize(). See bug 6436. 121 int TestSuite::Run() { 122 base::mac::ScopedNSAutoreleasePool scoped_pool; 123 124 Initialize(); 125 std::string client_func = 126 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 127 switches::kTestChildProcess); 128 // Check to see if we are being run as a client process. 129 if (!client_func.empty()) 130 return multi_process_function_list::InvokeChildProcessTest(client_func); 131 int result = RUN_ALL_TESTS(); 132 133 // If there are failed tests, see if we should ignore the failures. 134 if (result != 0 && GetTestCount(&TestSuite::NonIgnoredFailures) == 0) 135 result = 0; 136 137 // Display the number of flaky tests. 138 int flaky_count = GetTestCount(&TestSuite::IsMarkedFlaky); 139 if (flaky_count) { 140 printf(" YOU HAVE %d FLAKY %s\n\n", flaky_count, 141 flaky_count == 1 ? "TEST" : "TESTS"); 142 } 143 144 // Display the number of tests with ignored failures (FAILS). 145 int failing_count = GetTestCount(&TestSuite::IsMarkedFailing); 146 if (failing_count) { 147 printf(" YOU HAVE %d %s with ignored failures (FAILS prefix)\n\n", 148 failing_count, failing_count == 1 ? "test" : "tests"); 149 } 150 151 // This MUST happen before Shutdown() since Shutdown() tears down 152 // objects (such as NotificationService::current()) that Cocoa 153 // objects use to remove themselves as observers. 154 scoped_pool.Recycle(); 155 156 Shutdown(); 157 158 return result; 159 } 160 161 // static 162 void TestSuite::UnitTestAssertHandler(const std::string& str) { 163 RAW_LOG(FATAL, str.c_str()); 164 } 165 166 void TestSuite::SuppressErrorDialogs() { 167 #if defined(OS_WIN) 168 UINT new_flags = SEM_FAILCRITICALERRORS | 169 SEM_NOGPFAULTERRORBOX | 170 SEM_NOOPENFILEERRORBOX; 171 172 // Preserve existing error mode, as discussed at 173 // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx 174 UINT existing_flags = SetErrorMode(new_flags); 175 SetErrorMode(existing_flags | new_flags); 176 #endif // defined(OS_WIN) 177 } 178 179 void TestSuite::Initialize() { 180 #if defined(OS_MACOSX) 181 // Some of the app unit tests spin runloops. 182 mock_cr_app::RegisterMockCrApp(); 183 #endif 184 185 // Initialize logging. 186 FilePath exe; 187 PathService::Get(base::FILE_EXE, &exe); 188 FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); 189 logging::InitLogging( 190 log_filename.value().c_str(), 191 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, 192 logging::LOCK_LOG_FILE, 193 logging::DELETE_OLD_LOG_FILE, 194 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); 195 // We want process and thread IDs because we may have multiple processes. 196 // Note: temporarily enabled timestamps in an effort to catch bug 6361. 197 logging::SetLogItems(true, true, true, true); 198 199 CHECK(base::EnableInProcessStackDumping()); 200 #if defined(OS_WIN) 201 // Make sure we run with high resolution timer to minimize differences 202 // between production code and test code. 203 base::Time::EnableHighResolutionTimer(true); 204 #endif // defined(OS_WIN) 205 206 // In some cases, we do not want to see standard error dialogs. 207 if (!base::debug::BeingDebugged() && 208 !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) { 209 SuppressErrorDialogs(); 210 base::debug::SetSuppressDebugUI(true); 211 logging::SetLogAssertHandler(UnitTestAssertHandler); 212 } 213 214 icu_util::Initialize(); 215 216 CatchMaybeTests(); 217 218 TestTimeouts::Initialize(); 219 } 220 221 void TestSuite::Shutdown() { 222 } 223