test_suite.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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/debug/stack_trace.h" 14#include "base/file_path.h" 15#include "base/i18n/icu_util.h" 16#include "base/logging.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/mac/scoped_nsautorelease_pool.h" 28#if defined(OS_IOS) 29#include "base/test/test_listener_ios.h" 30#else 31#include "base/test/mock_chrome_application_mac.h" 32#endif // OS_IOS 33#endif // OS_MACOSX 34 35#if defined(OS_ANDROID) 36#include "base/test/test_support_android.h" 37#endif 38 39#if defined(OS_IOS) 40#include "base/test/test_support_ios.h" 41#endif 42 43#if defined(TOOLKIT_GTK) 44#include <gtk/gtk.h> 45#endif 46 47namespace { 48 49class MaybeTestDisabler : public testing::EmptyTestEventListener { 50 public: 51 virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE { 52 ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info)) 53 << "Probably the OS #ifdefs don't include all of the necessary " 54 "platforms.\nPlease ensure that no tests have the MAYBE_ prefix " 55 "after the code is preprocessed."; 56 } 57}; 58 59class TestClientInitializer : public testing::EmptyTestEventListener { 60 public: 61 TestClientInitializer() 62 : old_command_line_(CommandLine::NO_PROGRAM) { 63 } 64 65 virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE { 66 old_command_line_ = *CommandLine::ForCurrentProcess(); 67 } 68 69 virtual void OnTestEnd(const testing::TestInfo& test_info) OVERRIDE { 70 *CommandLine::ForCurrentProcess() = old_command_line_; 71 } 72 73 private: 74 CommandLine old_command_line_; 75 76 DISALLOW_COPY_AND_ASSIGN(TestClientInitializer); 77}; 78 79} // namespace 80 81const char TestSuite::kStrictFailureHandling[] = "strict_failure_handling"; 82 83TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) { 84 PreInitialize(argc, argv, true); 85} 86 87TestSuite::TestSuite(int argc, char** argv, bool create_at_exit_manager) 88 : initialized_command_line_(false) { 89 PreInitialize(argc, argv, create_at_exit_manager); 90} 91 92TestSuite::~TestSuite() { 93 if (initialized_command_line_) 94 CommandLine::Reset(); 95} 96 97void TestSuite::PreInitialize(int argc, char** argv, 98 bool create_at_exit_manager) { 99#if defined(OS_WIN) 100 testing::GTEST_FLAG(catch_exceptions) = false; 101#endif 102 base::EnableTerminationOnHeapCorruption(); 103 initialized_command_line_ = CommandLine::Init(argc, argv); 104 testing::InitGoogleTest(&argc, argv); 105#if defined(OS_LINUX) && defined(USE_AURA) 106 // When calling native char conversion functions (e.g wrctomb) we need to 107 // have the locale set. In the absence of such a call the "C" locale is the 108 // default. In the gtk code (below) gtk_init() implicitly sets a locale. 109 setlocale(LC_ALL, ""); 110#elif defined(TOOLKIT_GTK) 111 gtk_init_check(&argc, &argv); 112#endif // defined(TOOLKIT_GTK) 113 114 // On Android, AtExitManager is created in 115 // testing/android/native_test_wrapper.cc before main() is called. 116#if !defined(OS_ANDROID) 117 if (create_at_exit_manager) 118 at_exit_manager_.reset(new base::AtExitManager); 119#endif 120 121 // Don't add additional code to this function. Instead add it to 122 // Initialize(). See bug 6436. 123} 124 125 126// static 127bool TestSuite::IsMarkedFlaky(const testing::TestInfo& test) { 128 return strncmp(test.name(), "FLAKY_", 6) == 0; 129} 130 131// static 132bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) { 133 return strncmp(test.name(), "MAYBE_", 6) == 0; 134} 135 136// static 137bool TestSuite::ShouldIgnoreFailure(const testing::TestInfo& test) { 138 if (CommandLine::ForCurrentProcess()->HasSwitch(kStrictFailureHandling)) 139 return false; 140 return IsMarkedFlaky(test); 141} 142 143// static 144bool TestSuite::NonIgnoredFailures(const testing::TestInfo& test) { 145 return test.should_run() && test.result()->Failed() && 146 !ShouldIgnoreFailure(test); 147} 148 149int TestSuite::GetTestCount(TestMatch test_match) { 150 testing::UnitTest* instance = testing::UnitTest::GetInstance(); 151 int count = 0; 152 153 for (int i = 0; i < instance->total_test_case_count(); ++i) { 154 const testing::TestCase& test_case = *instance->GetTestCase(i); 155 for (int j = 0; j < test_case.total_test_count(); ++j) { 156 if (test_match(*test_case.GetTestInfo(j))) { 157 count++; 158 } 159 } 160 } 161 162 return count; 163} 164 165void TestSuite::CatchMaybeTests() { 166 testing::TestEventListeners& listeners = 167 testing::UnitTest::GetInstance()->listeners(); 168 listeners.Append(new MaybeTestDisabler); 169} 170 171void TestSuite::ResetCommandLine() { 172 testing::TestEventListeners& listeners = 173 testing::UnitTest::GetInstance()->listeners(); 174 listeners.Append(new TestClientInitializer); 175} 176 177// Don't add additional code to this method. Instead add it to 178// Initialize(). See bug 6436. 179int TestSuite::Run() { 180#if defined(OS_MACOSX) 181 base::mac::ScopedNSAutoreleasePool scoped_pool; 182#endif 183 184 Initialize(); 185 std::string client_func = 186 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 187 switches::kTestChildProcess); 188 189 // Check to see if we are being run as a client process. 190 if (!client_func.empty()) 191 return multi_process_function_list::InvokeChildProcessTest(client_func); 192#if defined(OS_IOS) 193 base::test_listener_ios::RegisterTestEndListener(); 194#endif 195 int result = RUN_ALL_TESTS(); 196 197 // If there are failed tests, see if we should ignore the failures. 198 if (result != 0 && GetTestCount(&TestSuite::NonIgnoredFailures) == 0) 199 result = 0; 200 201 // Display the number of flaky tests. 202 int flaky_count = GetTestCount(&TestSuite::IsMarkedFlaky); 203 if (flaky_count) { 204 printf(" YOU HAVE %d FLAKY %s\n\n", flaky_count, 205 flaky_count == 1 ? "TEST" : "TESTS"); 206 } 207 208#if defined(OS_MACOSX) 209 // This MUST happen before Shutdown() since Shutdown() tears down 210 // objects (such as NotificationService::current()) that Cocoa 211 // objects use to remove themselves as observers. 212 scoped_pool.Recycle(); 213#endif 214 215 Shutdown(); 216 217 return result; 218} 219 220// static 221void TestSuite::UnitTestAssertHandler(const std::string& str) { 222 RAW_LOG(FATAL, str.c_str()); 223} 224 225void TestSuite::SuppressErrorDialogs() { 226#if defined(OS_WIN) 227 UINT new_flags = SEM_FAILCRITICALERRORS | 228 SEM_NOGPFAULTERRORBOX | 229 SEM_NOOPENFILEERRORBOX; 230 231 // Preserve existing error mode, as discussed at 232 // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx 233 UINT existing_flags = SetErrorMode(new_flags); 234 SetErrorMode(existing_flags | new_flags); 235 236#if defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1) 237 // Suppress the "Debug Assertion Failed" dialog. 238 // TODO(hbono): remove this code when gtest has it. 239 // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion 240 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); 241 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); 242#endif // defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1) 243#endif // defined(OS_WIN) 244} 245 246void TestSuite::Initialize() { 247#if defined(OS_MACOSX) && !defined(OS_IOS) 248 // Some of the app unit tests spin runloops. 249 mock_cr_app::RegisterMockCrApp(); 250#endif 251 252#if defined(OS_IOS) 253 InitIOSTestMessageLoop(); 254#endif // OS_IOS 255 256#if defined(OS_ANDROID) 257 InitAndroidTest(); 258#else 259 // Initialize logging. 260 FilePath exe; 261 PathService::Get(base::FILE_EXE, &exe); 262 FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); 263 logging::InitLogging( 264 log_filename.value().c_str(), 265 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, 266 logging::LOCK_LOG_FILE, 267 logging::DELETE_OLD_LOG_FILE, 268 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); 269 // We want process and thread IDs because we may have multiple processes. 270 // Note: temporarily enabled timestamps in an effort to catch bug 6361. 271 logging::SetLogItems(true, true, true, true); 272#endif // else defined(OS_ANDROID) 273 274 CHECK(base::debug::EnableInProcessStackDumping()); 275#if defined(OS_WIN) 276 // Make sure we run with high resolution timer to minimize differences 277 // between production code and test code. 278 base::Time::EnableHighResolutionTimer(true); 279#endif // defined(OS_WIN) 280 281 // In some cases, we do not want to see standard error dialogs. 282 if (!base::debug::BeingDebugged() && 283 !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) { 284 SuppressErrorDialogs(); 285 base::debug::SetSuppressDebugUI(true); 286 logging::SetLogAssertHandler(UnitTestAssertHandler); 287 } 288 289 icu_util::Initialize(); 290 291 CatchMaybeTests(); 292 ResetCommandLine(); 293 294 TestTimeouts::Initialize(); 295} 296 297void TestSuite::Shutdown() { 298} 299