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