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 53 namespace { 54 55 class 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 65 class 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 87 namespace base { 88 89 int 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 97 TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) { 98 PreInitialize(argc, argv, true); 99 } 100 101 TestSuite::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 106 TestSuite::~TestSuite() { 107 if (initialized_command_line_) 108 CommandLine::Reset(); 109 } 110 111 void 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 147 bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) { 148 return strncmp(test.name(), "MAYBE_", 6) == 0; 149 } 150 151 void TestSuite::CatchMaybeTests() { 152 testing::TestEventListeners& listeners = 153 testing::UnitTest::GetInstance()->listeners(); 154 listeners.Append(new MaybeTestDisabler); 155 } 156 157 void TestSuite::ResetCommandLine() { 158 testing::TestEventListeners& listeners = 159 testing::UnitTest::GetInstance()->listeners(); 160 listeners.Append(new TestClientInitializer); 161 } 162 163 #if !defined(OS_IOS) 164 void 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. 193 int 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 228 void TestSuite::UnitTestAssertHandler(const std::string& str) { 229 RAW_LOG(FATAL, str.c_str()); 230 } 231 232 void 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 253 void 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 306 void TestSuite::Shutdown() { 307 } 308