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 RAW_LOG(FATAL, str.c_str()); 230} 231 232void TestSuite::SuppressErrorDialogs() { 233#if defined(OS_WIN) 234 UINT new_flags = SEM_FAILCRITICALERRORS | 235 SEM_NOGPFAULTERRORBOX | 236 SEM_NOOPENFILEERRORBOX; 237 238 // Preserve existing error mode, as discussed at 239 // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx 240 UINT existing_flags = SetErrorMode(new_flags); 241 SetErrorMode(existing_flags | new_flags); 242 243#if defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1) 244 // Suppress the "Debug Assertion Failed" dialog. 245 // TODO(hbono): remove this code when gtest has it. 246 // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion 247 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); 248 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); 249#endif // defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1) 250#endif // defined(OS_WIN) 251} 252 253void TestSuite::Initialize() { 254#if defined(OS_MACOSX) && !defined(OS_IOS) 255 // Some of the app unit tests spin runloops. 256 mock_cr_app::RegisterMockCrApp(); 257#endif 258 259#if defined(OS_IOS) 260 InitIOSTestMessageLoop(); 261#endif // OS_IOS 262 263#if defined(OS_ANDROID) 264 InitAndroidTest(); 265#else 266 // Initialize logging. 267 base::FilePath exe; 268 PathService::Get(base::FILE_EXE, &exe); 269 base::FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); 270 logging::LoggingSettings settings; 271 settings.logging_dest = logging::LOG_TO_ALL; 272 settings.log_file = log_filename.value().c_str(); 273 settings.delete_old = logging::DELETE_OLD_LOG_FILE; 274 logging::InitLogging(settings); 275 // We want process and thread IDs because we may have multiple processes. 276 // Note: temporarily enabled timestamps in an effort to catch bug 6361. 277 logging::SetLogItems(true, true, true, true); 278#endif // else defined(OS_ANDROID) 279 280 CHECK(base::debug::EnableInProcessStackDumping()); 281#if defined(OS_WIN) 282 // Make sure we run with high resolution timer to minimize differences 283 // between production code and test code. 284 base::Time::EnableHighResolutionTimer(true); 285#endif // defined(OS_WIN) 286 287 // In some cases, we do not want to see standard error dialogs. 288 if (!base::debug::BeingDebugged() && 289 !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) { 290 SuppressErrorDialogs(); 291 base::debug::SetSuppressDebugUI(true); 292 logging::SetLogAssertHandler(UnitTestAssertHandler); 293 } 294 295 base::i18n::InitializeICU(); 296 297 CatchMaybeTests(); 298 ResetCommandLine(); 299#if !defined(OS_IOS) 300 AddTestLauncherResultPrinter(); 301#endif // !defined(OS_IOS) 302 303 TestTimeouts::Initialize(); 304} 305 306void TestSuite::Shutdown() { 307} 308