test_suite.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/bind.h" 11#include "base/command_line.h" 12#include "base/debug/debug_on_start_win.h" 13#include "base/debug/debugger.h" 14#include "base/debug/stack_trace.h" 15#include "base/file_util.h" 16#include "base/files/file_path.h" 17#include "base/i18n/icu_util.h" 18#include "base/logging.h" 19#include "base/memory/scoped_ptr.h" 20#include "base/path_service.h" 21#include "base/process/memory.h" 22#include "base/test/gtest_xml_util.h" 23#include "base/test/launcher/unit_test_launcher.h" 24#include "base/test/multiprocess_test.h" 25#include "base/test/test_switches.h" 26#include "base/test/test_timeouts.h" 27#include "base/time/time.h" 28#include "testing/gmock/include/gmock/gmock.h" 29#include "testing/gtest/include/gtest/gtest.h" 30#include "testing/multiprocess_func_list.h" 31 32#if defined(OS_MACOSX) 33#include "base/mac/scoped_nsautorelease_pool.h" 34#if defined(OS_IOS) 35#include "base/test/test_listener_ios.h" 36#else 37#include "base/test/mock_chrome_application_mac.h" 38#endif // OS_IOS 39#endif // OS_MACOSX 40 41#if defined(OS_ANDROID) 42#include "base/test/test_support_android.h" 43#endif 44 45#if defined(OS_IOS) 46#include "base/test/test_support_ios.h" 47#endif 48 49#if defined(TOOLKIT_GTK) 50#include <gtk/gtk.h> 51#endif 52 53namespace { 54 55class MaybeTestDisabler : public testing::EmptyTestEventListener { 56 public: 57 virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE { 58 ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info)) 59 << "Probably the OS #ifdefs don't include all of the necessary " 60 "platforms.\nPlease ensure that no tests have the MAYBE_ prefix " 61 "after the code is preprocessed."; 62 } 63}; 64 65class TestClientInitializer : public testing::EmptyTestEventListener { 66 public: 67 TestClientInitializer() 68 : old_command_line_(CommandLine::NO_PROGRAM) { 69 } 70 71 virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE { 72 old_command_line_ = *CommandLine::ForCurrentProcess(); 73 } 74 75 virtual void OnTestEnd(const testing::TestInfo& test_info) OVERRIDE { 76 *CommandLine::ForCurrentProcess() = old_command_line_; 77 } 78 79 private: 80 CommandLine old_command_line_; 81 82 DISALLOW_COPY_AND_ASSIGN(TestClientInitializer); 83}; 84 85} // namespace 86 87namespace base { 88 89int RunUnitTestsUsingBaseTestSuite(int argc, char **argv) { 90 TestSuite test_suite(argc, argv); 91 return base::LaunchUnitTests( 92 argc, argv, Bind(&TestSuite::Run, Unretained(&test_suite))); 93} 94 95} // namespace base 96 97TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) { 98 PreInitialize(argc, argv, true); 99} 100 101TestSuite::TestSuite(int argc, char** argv, bool create_at_exit_manager) 102 : initialized_command_line_(false) { 103 PreInitialize(argc, argv, create_at_exit_manager); 104} 105 106TestSuite::~TestSuite() { 107 if (initialized_command_line_) 108 CommandLine::Reset(); 109} 110 111void TestSuite::PreInitialize(int argc, char** argv, 112 bool create_at_exit_manager) { 113#if defined(OS_WIN) 114 testing::GTEST_FLAG(catch_exceptions) = false; 115 base::TimeTicks::SetNowIsHighResNowIfSupported(); 116#endif 117 base::EnableTerminationOnHeapCorruption(); 118 initialized_command_line_ = CommandLine::Init(argc, argv); 119 testing::InitGoogleTest(&argc, argv); 120 testing::InitGoogleMock(&argc, argv); 121#if defined(OS_LINUX) && defined(USE_AURA) 122 // When calling native char conversion functions (e.g wrctomb) we need to 123 // have the locale set. In the absence of such a call the "C" locale is the 124 // default. In the gtk code (below) gtk_init() implicitly sets a locale. 125 setlocale(LC_ALL, ""); 126#elif defined(TOOLKIT_GTK) 127 gtk_init_check(&argc, &argv); 128#endif // defined(TOOLKIT_GTK) 129 130 // On Android, AtExitManager is created in 131 // testing/android/native_test_wrapper.cc before main() is called. 132#if !defined(OS_ANDROID) 133 if (create_at_exit_manager) 134 at_exit_manager_.reset(new base::AtExitManager); 135#endif 136 137#if defined(OS_IOS) 138 InitIOSRunHook(this, argc, argv); 139#endif 140 141 // Don't add additional code to this function. Instead add it to 142 // Initialize(). See bug 6436. 143} 144 145 146// static 147bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) { 148 return strncmp(test.name(), "MAYBE_", 6) == 0; 149} 150 151void TestSuite::CatchMaybeTests() { 152 testing::TestEventListeners& listeners = 153 testing::UnitTest::GetInstance()->listeners(); 154 listeners.Append(new MaybeTestDisabler); 155} 156 157void TestSuite::ResetCommandLine() { 158 testing::TestEventListeners& listeners = 159 testing::UnitTest::GetInstance()->listeners(); 160 listeners.Append(new TestClientInitializer); 161} 162 163#if !defined(OS_IOS) 164void TestSuite::AddTestLauncherResultPrinter() { 165 // Only add the custom printer if requested. 166 if (!CommandLine::ForCurrentProcess()->HasSwitch( 167 switches::kTestLauncherOutput)) { 168 return; 169 } 170 171 FilePath output_path(CommandLine::ForCurrentProcess()->GetSwitchValuePath( 172 switches::kTestLauncherOutput)); 173 174 // Do not add the result printer if output path already exists. It's an 175 // indicator there is a process printing to that file, and we're likely 176 // its child. Do not clobber the results in that case. 177 if (PathExists(output_path)) { 178 LOG(WARNING) << "Test launcher output path " << output_path.AsUTF8Unsafe() 179 << " exists. Not adding test launcher result printer."; 180 return; 181 } 182 183 XmlUnitTestResultPrinter* printer = new XmlUnitTestResultPrinter; 184 CHECK(printer->Initialize(output_path)); 185 testing::TestEventListeners& listeners = 186 testing::UnitTest::GetInstance()->listeners(); 187 listeners.Append(printer); 188} 189#endif // !defined(OS_IOS) 190 191// Don't add additional code to this method. Instead add it to 192// Initialize(). See bug 6436. 193int TestSuite::Run() { 194#if defined(OS_IOS) 195 RunTestsFromIOSApp(); 196#endif 197 198#if defined(OS_MACOSX) 199 base::mac::ScopedNSAutoreleasePool scoped_pool; 200#endif 201 202 Initialize(); 203 std::string client_func = 204 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 205 switches::kTestChildProcess); 206 207 // Check to see if we are being run as a client process. 208 if (!client_func.empty()) 209 return multi_process_function_list::InvokeChildProcessTest(client_func); 210#if defined(OS_IOS) 211 base::test_listener_ios::RegisterTestEndListener(); 212#endif 213 int result = RUN_ALL_TESTS(); 214 215#if defined(OS_MACOSX) 216 // This MUST happen before Shutdown() since Shutdown() tears down 217 // objects (such as NotificationService::current()) that Cocoa 218 // objects use to remove themselves as observers. 219 scoped_pool.Recycle(); 220#endif 221 222 Shutdown(); 223 224 return result; 225} 226 227// static 228void TestSuite::UnitTestAssertHandler(const std::string& str) { 229#if defined(OS_ANDROID) 230 // Correlating test stdio with logcat can be difficult, so we emit this 231 // helpful little hint about what was running. Only do this for Android 232 // because other platforms don't separate out the relevant logs in the same 233 // way. 234 const ::testing::TestInfo* const test_info = 235 ::testing::UnitTest::GetInstance()->current_test_info(); 236 if (test_info) { 237 LOG(ERROR) << "Currently running: " << test_info->test_case_name() << "." 238 << test_info->name(); 239 fflush(stderr); 240 } 241#endif // defined(OS_ANDROID) 242 243 // The logging system actually prints the message before calling the assert 244 // handler. Just exit now to avoid printing too many stack traces. 245 _exit(1); 246} 247 248void TestSuite::SuppressErrorDialogs() { 249#if defined(OS_WIN) 250 UINT new_flags = SEM_FAILCRITICALERRORS | 251 SEM_NOGPFAULTERRORBOX | 252 SEM_NOOPENFILEERRORBOX; 253 254 // Preserve existing error mode, as discussed at 255 // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx 256 UINT existing_flags = SetErrorMode(new_flags); 257 SetErrorMode(existing_flags | new_flags); 258 259#if defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1) 260 // Suppress the "Debug Assertion Failed" dialog. 261 // TODO(hbono): remove this code when gtest has it. 262 // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion 263 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); 264 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); 265#endif // defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1) 266#endif // defined(OS_WIN) 267} 268 269void TestSuite::Initialize() { 270#if defined(OS_MACOSX) && !defined(OS_IOS) 271 // Some of the app unit tests spin runloops. 272 mock_cr_app::RegisterMockCrApp(); 273#endif 274 275#if defined(OS_IOS) 276 InitIOSTestMessageLoop(); 277#endif // OS_IOS 278 279#if defined(OS_ANDROID) 280 InitAndroidTest(); 281#else 282 // Initialize logging. 283 base::FilePath exe; 284 PathService::Get(base::FILE_EXE, &exe); 285 base::FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); 286 logging::LoggingSettings settings; 287 settings.logging_dest = logging::LOG_TO_ALL; 288 settings.log_file = log_filename.value().c_str(); 289 settings.delete_old = logging::DELETE_OLD_LOG_FILE; 290 logging::InitLogging(settings); 291 // We want process and thread IDs because we may have multiple processes. 292 // Note: temporarily enabled timestamps in an effort to catch bug 6361. 293 logging::SetLogItems(true, true, true, true); 294#endif // else defined(OS_ANDROID) 295 296 CHECK(base::debug::EnableInProcessStackDumping()); 297#if defined(OS_WIN) 298 // Make sure we run with high resolution timer to minimize differences 299 // between production code and test code. 300 base::Time::EnableHighResolutionTimer(true); 301#endif // defined(OS_WIN) 302 303 // In some cases, we do not want to see standard error dialogs. 304 if (!base::debug::BeingDebugged() && 305 !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) { 306 SuppressErrorDialogs(); 307 base::debug::SetSuppressDebugUI(true); 308 logging::SetLogAssertHandler(UnitTestAssertHandler); 309 } 310 311 base::i18n::InitializeICU(); 312 313 CatchMaybeTests(); 314 ResetCommandLine(); 315#if !defined(OS_IOS) 316 AddTestLauncherResultPrinter(); 317#endif // !defined(OS_IOS) 318 319 TestTimeouts::Initialize(); 320} 321 322void TestSuite::Shutdown() { 323} 324