David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 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 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 7 | #ifndef STARBOARD |
| 8 | #include <signal.h> |
| 9 | #endif |
| 10 | |
| 11 | #include <memory> |
| 12 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 13 | #include "base/at_exit.h" |
| 14 | #include "base/base_paths.h" |
| 15 | #include "base/base_switches.h" |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 16 | #include "base/bind.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 17 | #include "base/command_line.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 18 | #include "base/debug/debugger.h" |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 19 | #include "base/debug/profiler.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 20 | #include "base/debug/stack_trace.h" |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 21 | #include "base/feature_list.h" |
| 22 | #include "base/files/file_path.h" |
| 23 | #include "base/files/file_util.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 24 | #include "base/i18n/icu_util.h" |
| 25 | #include "base/logging.h" |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 26 | #include "base/macros.h" |
| 27 | #include "base/memory/ptr_util.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 28 | #include "base/path_service.h" |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 29 | #include "base/process/launch.h" |
| 30 | #include "base/process/memory.h" |
| 31 | #include "base/task/task_scheduler/task_scheduler.h" |
| 32 | #include "base/test/gtest_xml_unittest_result_printer.h" |
| 33 | #include "base/test/gtest_xml_util.h" |
| 34 | #include "base/test/icu_test_util.h" |
| 35 | #include "base/test/launcher/unit_test_launcher.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 36 | #include "base/test/multiprocess_test.h" |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 37 | #include "base/test/test_switches.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 38 | #include "base/test/test_timeouts.h" |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 39 | #include "base/time/time.h" |
| 40 | #include "build/build_config.h" |
| 41 | #include "testing/gmock/include/gmock/gmock.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 42 | #include "testing/gtest/include/gtest/gtest.h" |
| 43 | #include "testing/multiprocess_func_list.h" |
| 44 | |
| 45 | #if defined(OS_MACOSX) |
| 46 | #include "base/mac/scoped_nsautorelease_pool.h" |
| 47 | #if defined(OS_IOS) |
| 48 | #include "base/test/test_listener_ios.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 49 | #endif // OS_IOS |
| 50 | #endif // OS_MACOSX |
| 51 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 52 | #if !defined(OS_WIN) |
| 53 | #include "base/i18n/rtl.h" |
| 54 | #if !defined(OS_IOS) |
| 55 | #include "base/strings/string_util.h" |
| 56 | #include "third_party/icu/source/common/unicode/uloc.h" |
| 57 | #endif |
| 58 | #endif |
| 59 | |
| 60 | #if defined(OS_ANDROID) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 61 | #include "base/test/test_support_android.h" |
| 62 | #endif |
| 63 | |
| 64 | #if defined(OS_IOS) |
| 65 | #include "base/test/test_support_ios.h" |
| 66 | #endif |
| 67 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 68 | #if defined(OS_LINUX) |
| 69 | #include "base/test/fontconfig_util_linux.h" |
| 70 | #include "starboard/types.h" |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 71 | #endif |
| 72 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 73 | namespace base { |
| 74 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 75 | namespace { |
| 76 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 77 | // Returns true if the test is marked as "MAYBE_". |
| 78 | // When using different prefixes depending on platform, we use MAYBE_ and |
| 79 | // preprocessor directives to replace MAYBE_ with the target prefix. |
| 80 | bool IsMarkedMaybe(const testing::TestInfo& test) { |
| 81 | return strncmp(test.name(), "MAYBE_", 6) == 0; |
| 82 | } |
| 83 | |
| 84 | class DisableMaybeTests : public testing::EmptyTestEventListener { |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 85 | public: |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 86 | void OnTestStart(const testing::TestInfo& test_info) override { |
| 87 | ASSERT_FALSE(IsMarkedMaybe(test_info)) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 88 | << "Probably the OS #ifdefs don't include all of the necessary " |
| 89 | "platforms.\nPlease ensure that no tests have the MAYBE_ prefix " |
| 90 | "after the code is preprocessed."; |
| 91 | } |
| 92 | }; |
| 93 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 94 | class ResetCommandLineBetweenTests : public testing::EmptyTestEventListener { |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 95 | public: |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 96 | ResetCommandLineBetweenTests() : old_command_line_(CommandLine::NO_PROGRAM) {} |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 97 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 98 | void OnTestStart(const testing::TestInfo& test_info) override { |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 99 | old_command_line_ = *CommandLine::ForCurrentProcess(); |
| 100 | } |
| 101 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 102 | void OnTestEnd(const testing::TestInfo& test_info) override { |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 103 | *CommandLine::ForCurrentProcess() = old_command_line_; |
| 104 | } |
| 105 | |
| 106 | private: |
| 107 | CommandLine old_command_line_; |
| 108 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 109 | DISALLOW_COPY_AND_ASSIGN(ResetCommandLineBetweenTests); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 110 | }; |
| 111 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 112 | class CheckForLeakedGlobals : public testing::EmptyTestEventListener { |
| 113 | public: |
| 114 | CheckForLeakedGlobals() = default; |
| 115 | |
| 116 | // Check for leaks in individual tests. |
| 117 | void OnTestStart(const testing::TestInfo& test) override { |
| 118 | scheduler_set_before_test_ = TaskScheduler::GetInstance(); |
| 119 | } |
| 120 | void OnTestEnd(const testing::TestInfo& test) override { |
| 121 | auto* task_scheduler = TaskScheduler::GetInstance(); |
| 122 | DCHECK_EQ(scheduler_set_before_test_, task_scheduler) |
| 123 | << " in test " << test.test_case_name() << "." << test.name(); |
| 124 | } |
| 125 | |
| 126 | // Check for leaks in test cases (consisting of one or more tests). |
| 127 | void OnTestCaseStart(const testing::TestCase& test_case) override { |
| 128 | scheduler_set_before_case_ = TaskScheduler::GetInstance(); |
| 129 | } |
| 130 | void OnTestCaseEnd(const testing::TestCase& test_case) override { |
| 131 | DCHECK_EQ(scheduler_set_before_case_, TaskScheduler::GetInstance()) |
| 132 | << " in case " << test_case.name(); |
| 133 | } |
| 134 | |
| 135 | private: |
| 136 | TaskScheduler* scheduler_set_before_test_ = nullptr; |
| 137 | TaskScheduler* scheduler_set_before_case_ = nullptr; |
| 138 | |
| 139 | DISALLOW_COPY_AND_ASSIGN(CheckForLeakedGlobals); |
| 140 | }; |
| 141 | |
| 142 | std::string GetProfileName() { |
| 143 | static const char kDefaultProfileName[] = "test-profile-{pid}"; |
| 144 | CR_DEFINE_STATIC_LOCAL(std::string, profile_name, ()); |
| 145 | if (profile_name.empty()) { |
| 146 | const base::CommandLine& command_line = |
| 147 | *base::CommandLine::ForCurrentProcess(); |
| 148 | if (command_line.HasSwitch(switches::kProfilingFile)) |
| 149 | profile_name = command_line.GetSwitchValueASCII(switches::kProfilingFile); |
| 150 | else |
| 151 | profile_name = std::string(kDefaultProfileName); |
| 152 | } |
| 153 | return profile_name; |
| 154 | } |
| 155 | |
| 156 | void InitializeLogging() { |
| 157 | #if defined(OS_ANDROID) |
| 158 | InitAndroidTestLogging(); |
| 159 | #else |
| 160 | FilePath exe; |
| 161 | PathService::Get(FILE_EXE, &exe); |
| 162 | FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); |
| 163 | logging::LoggingSettings settings; |
| 164 | settings.logging_dest = logging::LOG_TO_ALL; |
| 165 | settings.log_file = log_filename.value().c_str(); |
| 166 | settings.delete_old = logging::DELETE_OLD_LOG_FILE; |
| 167 | logging::InitLogging(settings); |
| 168 | // We want process and thread IDs because we may have multiple processes. |
| 169 | // Note: temporarily enabled timestamps in an effort to catch bug 6361. |
| 170 | logging::SetLogItems(true, true, true, true); |
| 171 | #endif // !defined(OS_ANDROID) |
| 172 | } |
| 173 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 174 | } // namespace |
| 175 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 176 | #if !defined(STARBOARD) |
| 177 | int RunUnitTestsUsingBaseTestSuite(int argc, char **argv) { |
| 178 | TestSuite test_suite(argc, argv); |
| 179 | return LaunchUnitTests(argc, argv, |
| 180 | Bind(&TestSuite::Run, Unretained(&test_suite))); |
| 181 | } |
| 182 | #endif |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 183 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 184 | TestSuite::TestSuite(int argc, char** argv) { |
| 185 | PreInitialize(); |
| 186 | InitializeFromCommandLine(argc, argv); |
| 187 | // Logging must be initialized before any thread has a chance to call logging |
| 188 | // functions. |
| 189 | InitializeLogging(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 190 | } |
| 191 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 192 | #if defined(OS_WIN) |
| 193 | TestSuite::TestSuite(int argc, wchar_t** argv) { |
| 194 | PreInitialize(); |
| 195 | InitializeFromCommandLine(argc, argv); |
| 196 | // Logging must be initialized before any thread has a chance to call logging |
| 197 | // functions. |
| 198 | InitializeLogging(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 199 | } |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 200 | #endif // defined(OS_WIN) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 201 | |
| 202 | TestSuite::~TestSuite() { |
| 203 | if (initialized_command_line_) |
| 204 | CommandLine::Reset(); |
Andrew Top | cab7770 | 2019-09-17 13:14:36 -0700 | [diff] [blame] | 205 | logging::CloseLogFile(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 206 | } |
| 207 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 208 | void TestSuite::InitializeFromCommandLine(int argc, char** argv) { |
| 209 | initialized_command_line_ = CommandLine::Init(argc, argv); |
| 210 | testing::InitGoogleTest(&argc, argv); |
| 211 | testing::InitGoogleMock(&argc, argv); |
| 212 | |
| 213 | #if defined(OS_IOS) |
| 214 | InitIOSRunHook(this, argc, argv); |
| 215 | #endif |
| 216 | } |
| 217 | |
| 218 | #if defined(OS_WIN) |
| 219 | void TestSuite::InitializeFromCommandLine(int argc, wchar_t** argv) { |
| 220 | // Windows CommandLine::Init ignores argv anyway. |
| 221 | initialized_command_line_ = CommandLine::Init(argc, NULL); |
| 222 | testing::InitGoogleTest(&argc, argv); |
| 223 | testing::InitGoogleMock(&argc, argv); |
| 224 | } |
| 225 | #endif // defined(OS_WIN) |
| 226 | |
| 227 | void TestSuite::PreInitialize() { |
| 228 | DCHECK(!is_initialized_); |
| 229 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 230 | #if defined(OS_WIN) |
| 231 | testing::GTEST_FLAG(catch_exceptions) = false; |
| 232 | #endif |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 233 | EnableTerminationOnHeapCorruption(); |
| 234 | #if defined(OS_LINUX) && defined(USE_AURA) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 235 | // When calling native char conversion functions (e.g wrctomb) we need to |
| 236 | // have the locale set. In the absence of such a call the "C" locale is the |
| 237 | // default. In the gtk code (below) gtk_init() implicitly sets a locale. |
| 238 | setlocale(LC_ALL, ""); |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 239 | #endif // defined(OS_LINUX) && defined(USE_AURA) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 240 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 241 | // On Android, AtExitManager is created in |
| 242 | // testing/android/native_test_wrapper.cc before main() is called. |
| 243 | // For Cobalt, at_exit_manager some times need to be created earlier than the |
| 244 | // start of test case. |
| 245 | #if !defined(OS_ANDROID) && !defined(STARBOARD) |
| 246 | at_exit_manager_.reset(new AtExitManager); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 247 | #endif |
| 248 | |
| 249 | // Don't add additional code to this function. Instead add it to |
| 250 | // Initialize(). See bug 6436. |
| 251 | } |
| 252 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 253 | void TestSuite::AddTestLauncherResultPrinter() { |
| 254 | // Only add the custom printer if requested. |
| 255 | if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| 256 | switches::kTestLauncherOutput)) { |
| 257 | return; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 258 | } |
| 259 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 260 | FilePath output_path(CommandLine::ForCurrentProcess()->GetSwitchValuePath( |
| 261 | switches::kTestLauncherOutput)); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 262 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 263 | // Do not add the result printer if output path already exists. It's an |
| 264 | // indicator there is a process printing to that file, and we're likely |
| 265 | // its child. Do not clobber the results in that case. |
| 266 | if (PathExists(output_path)) { |
| 267 | LOG(WARNING) << "Test launcher output path " << output_path.AsUTF8Unsafe() |
| 268 | << " exists. Not adding test launcher result printer."; |
| 269 | return; |
| 270 | } |
| 271 | |
| 272 | #if !defined(STARBOARD) |
| 273 | printer_ = new XmlUnitTestResultPrinter; |
| 274 | CHECK(printer_->Initialize(output_path)) |
| 275 | << "Output path is " << output_path.AsUTF8Unsafe() |
| 276 | << " and PathExists(output_path) is " << PathExists(output_path); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 277 | testing::TestEventListeners& listeners = |
| 278 | testing::UnitTest::GetInstance()->listeners(); |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 279 | listeners.Append(printer_); |
| 280 | #endif |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 281 | } |
| 282 | |
| 283 | // Don't add additional code to this method. Instead add it to |
| 284 | // Initialize(). See bug 6436. |
| 285 | int TestSuite::Run() { |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 286 | #if defined(OS_IOS) |
| 287 | RunTestsFromIOSApp(); |
| 288 | #endif |
| 289 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 290 | #if defined(OS_MACOSX) |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 291 | mac::ScopedNSAutoreleasePool scoped_pool; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 292 | #endif |
| 293 | |
| 294 | Initialize(); |
| 295 | std::string client_func = |
| 296 | CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 297 | switches::kTestChildProcess); |
| 298 | |
| 299 | // Check to see if we are being run as a client process. |
| 300 | if (!client_func.empty()) |
| 301 | return multi_process_function_list::InvokeChildProcessTest(client_func); |
| 302 | #if defined(OS_IOS) |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 303 | test_listener_ios::RegisterTestEndListener(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 304 | #endif |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 305 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 306 | int result = RUN_ALL_TESTS(); |
| 307 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 308 | #if defined(OS_MACOSX) |
| 309 | // This MUST happen before Shutdown() since Shutdown() tears down |
| 310 | // objects (such as NotificationService::current()) that Cocoa |
| 311 | // objects use to remove themselves as observers. |
| 312 | scoped_pool.Recycle(); |
| 313 | #endif |
| 314 | |
| 315 | Shutdown(); |
| 316 | |
| 317 | return result; |
| 318 | } |
| 319 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 320 | void TestSuite::DisableCheckForLeakedGlobals() { |
| 321 | DCHECK(!is_initialized_); |
| 322 | check_for_leaked_globals_ = false; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 323 | } |
| 324 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 325 | void TestSuite::UnitTestAssertHandler(const char* file, |
| 326 | int line, |
| 327 | const base::StringPiece summary, |
| 328 | const base::StringPiece stack_trace) { |
| 329 | #if defined(OS_ANDROID) |
| 330 | // Correlating test stdio with logcat can be difficult, so we emit this |
| 331 | // helpful little hint about what was running. Only do this for Android |
| 332 | // because other platforms don't separate out the relevant logs in the same |
| 333 | // way. |
| 334 | const ::testing::TestInfo* const test_info = |
| 335 | ::testing::UnitTest::GetInstance()->current_test_info(); |
| 336 | if (test_info) { |
| 337 | LOG(ERROR) << "Currently running: " << test_info->test_case_name() << "." |
| 338 | << test_info->name(); |
| 339 | fflush(stderr); |
| 340 | } |
| 341 | #endif // defined(OS_ANDROID) |
| 342 | |
| 343 | #if !defined(STARBOARD) |
| 344 | // XmlUnitTestResultPrinter inherits gtest format, where assert has summary |
| 345 | // and message. In GTest, summary is just a logged text, and message is a |
| 346 | // logged text, concatenated with stack trace of assert. |
| 347 | // Concatenate summary and stack_trace here, to pass it as a message. |
| 348 | if (printer_) { |
| 349 | const std::string summary_str = summary.as_string(); |
| 350 | const std::string stack_trace_str = summary_str + stack_trace.as_string(); |
| 351 | printer_->OnAssert(file, line, summary_str, stack_trace_str); |
| 352 | } |
| 353 | #endif |
| 354 | |
| 355 | #if defined(STARBOARD) |
| 356 | SbSystemRequestStop(1); |
| 357 | #else |
| 358 | // The logging system actually prints the message before calling the assert |
| 359 | // handler. Just exit now to avoid printing too many stack traces. |
| 360 | _exit(1); |
| 361 | #endif |
| 362 | } |
| 363 | |
| 364 | #if defined(OS_WIN) |
| 365 | namespace { |
| 366 | |
| 367 | // Disable optimizations to prevent function folding or other transformations |
| 368 | // that will make the call stacks on failures more confusing. |
| 369 | #pragma optimize("", off) |
| 370 | // Handlers for invalid parameter, pure call, and abort. They generate a |
| 371 | // breakpoint to ensure that we get a call stack on these failures. |
| 372 | void InvalidParameter(const wchar_t* expression, |
| 373 | const wchar_t* function, |
| 374 | const wchar_t* file, |
| 375 | unsigned int line, |
| 376 | uintptr_t reserved) { |
| 377 | // CRT printed message is sufficient. |
| 378 | __debugbreak(); |
| 379 | _exit(1); |
| 380 | } |
| 381 | |
| 382 | void PureCall() { |
| 383 | fprintf(stderr, "Pure-virtual function call. Terminating.\n"); |
| 384 | __debugbreak(); |
| 385 | _exit(1); |
| 386 | } |
| 387 | |
| 388 | void AbortHandler(int signal) { |
| 389 | // Print EOL after the CRT abort message. |
| 390 | fprintf(stderr, "\n"); |
| 391 | __debugbreak(); |
| 392 | } |
| 393 | #pragma optimize("", on) |
| 394 | |
| 395 | } // namespace |
| 396 | #endif |
| 397 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 398 | void TestSuite::SuppressErrorDialogs() { |
| 399 | #if defined(OS_WIN) |
| 400 | UINT new_flags = SEM_FAILCRITICALERRORS | |
| 401 | SEM_NOGPFAULTERRORBOX | |
| 402 | SEM_NOOPENFILEERRORBOX; |
| 403 | |
| 404 | // Preserve existing error mode, as discussed at |
| 405 | // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx |
| 406 | UINT existing_flags = SetErrorMode(new_flags); |
| 407 | SetErrorMode(existing_flags | new_flags); |
| 408 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 409 | #if defined(_DEBUG) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 410 | // Suppress the "Debug Assertion Failed" dialog. |
| 411 | // TODO(hbono): remove this code when gtest has it. |
| 412 | // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 413 | _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 414 | _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); |
| 415 | _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); |
| 416 | _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); |
| 417 | #endif // defined(_DEBUG) |
| 418 | |
| 419 | // See crbug.com/783040 for test code to trigger all of these failures. |
| 420 | _set_invalid_parameter_handler(InvalidParameter); |
| 421 | _set_purecall_handler(PureCall); |
| 422 | signal(SIGABRT, AbortHandler); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 423 | #endif // defined(OS_WIN) |
| 424 | } |
| 425 | |
| 426 | void TestSuite::Initialize() { |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 427 | DCHECK(!is_initialized_); |
| 428 | |
| 429 | const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 430 | #if !defined(OS_IOS) |
| 431 | if (command_line->HasSwitch(switches::kWaitForDebugger)) { |
| 432 | debug::WaitForDebugger(60, true); |
| 433 | } |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 434 | #endif |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 435 | // Set up a FeatureList instance, so that code using that API will not hit a |
| 436 | // an error that it's not set. It will be cleared automatically. |
| 437 | // TestFeatureForBrowserTest1 and TestFeatureForBrowserTest2 used in |
| 438 | // ContentBrowserTestScopedFeatureListTest to ensure ScopedFeatureList keeps |
| 439 | // features from command line. |
| 440 | std::string enabled = |
| 441 | command_line->GetSwitchValueASCII(switches::kEnableFeatures); |
| 442 | std::string disabled = |
| 443 | command_line->GetSwitchValueASCII(switches::kDisableFeatures); |
| 444 | enabled += ",TestFeatureForBrowserTest1"; |
| 445 | disabled += ",TestFeatureForBrowserTest2"; |
| 446 | #if !defined(STARBOARD) |
| 447 | scoped_feature_list_.InitFromCommandLine(enabled, disabled); |
| 448 | #endif |
| 449 | |
| 450 | // The enable-features and disable-features flags were just slurped into a |
| 451 | // FeatureList, so remove them from the command line. Tests should enable and |
| 452 | // disable features via the ScopedFeatureList API rather than command-line |
| 453 | // flags. |
| 454 | CommandLine new_command_line(command_line->GetProgram()); |
| 455 | CommandLine::SwitchMap switches = command_line->GetSwitches(); |
| 456 | |
| 457 | switches.erase(switches::kEnableFeatures); |
| 458 | switches.erase(switches::kDisableFeatures); |
| 459 | |
| 460 | for (const auto& iter : switches) |
| 461 | new_command_line.AppendSwitchNative(iter.first, iter.second); |
| 462 | |
| 463 | *CommandLine::ForCurrentProcess() = new_command_line; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 464 | |
| 465 | #if defined(OS_IOS) |
| 466 | InitIOSTestMessageLoop(); |
| 467 | #endif // OS_IOS |
| 468 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 469 | #if defined(OS_ANDROID) |
| 470 | InitAndroidTestMessageLoop(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 471 | #endif // else defined(OS_ANDROID) |
| 472 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 473 | CHECK(debug::EnableInProcessStackDumping()); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 474 | #if defined(OS_WIN) |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 475 | RouteStdioToConsole(true); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 476 | // Make sure we run with high resolution timer to minimize differences |
| 477 | // between production code and test code. |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 478 | Time::EnableHighResolutionTimer(true); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 479 | #endif // defined(OS_WIN) |
| 480 | |
| 481 | // In some cases, we do not want to see standard error dialogs. |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 482 | if (!debug::BeingDebugged() && |
| 483 | !command_line->HasSwitch("show-error-dialogs")) { |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 484 | SuppressErrorDialogs(); |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 485 | debug::SetSuppressDebugUI(true); |
| 486 | assert_handler_ = std::make_unique<logging::ScopedLogAssertHandler>( |
| 487 | base::Bind(&TestSuite::UnitTestAssertHandler, base::Unretained(this))); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 488 | } |
| 489 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 490 | base::test::InitializeICUForTesting(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 491 | |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 492 | // On the Mac OS X command line, the default locale is *_POSIX. In Chromium, |
| 493 | // the locale is set via an OS X locale API and is never *_POSIX. |
| 494 | // Some tests (such as those involving word break iterator) will behave |
| 495 | // differently and fail if we use *POSIX locale. Setting it to en_US here |
| 496 | // does not affect tests that explicitly overrides the locale for testing. |
| 497 | // This can be an issue on all platforms other than Windows. |
| 498 | // TODO(jshin): Should we set the locale via an OS X locale API here? |
| 499 | #if !defined(OS_WIN) |
| 500 | #if defined(OS_IOS) |
| 501 | i18n::SetICUDefaultLocale("en_US"); |
| 502 | #else |
| 503 | std::string default_locale(uloc_getDefault()); |
| 504 | if (EndsWith(default_locale, "POSIX", CompareCase::INSENSITIVE_ASCII)) |
| 505 | i18n::SetICUDefaultLocale("en_US"); |
| 506 | #endif |
| 507 | #endif |
| 508 | |
| 509 | #if defined(OS_LINUX) |
| 510 | // TODO(thomasanderson): Call TearDownFontconfig() in Shutdown(). It would |
| 511 | // currently crash because of leaked FcFontSet's in font_fallback_linux.cc. |
| 512 | SetUpFontconfig(); |
| 513 | #endif |
| 514 | |
| 515 | // Add TestEventListeners to enforce certain properties across tests. |
| 516 | testing::TestEventListeners& listeners = |
| 517 | testing::UnitTest::GetInstance()->listeners(); |
| 518 | listeners.Append(new DisableMaybeTests); |
| 519 | listeners.Append(new ResetCommandLineBetweenTests); |
| 520 | if (check_for_leaked_globals_) |
| 521 | listeners.Append(new CheckForLeakedGlobals); |
| 522 | |
| 523 | AddTestLauncherResultPrinter(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 524 | |
| 525 | TestTimeouts::Initialize(); |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 526 | |
| 527 | trace_to_file_.BeginTracingFromCommandLineOptions(); |
| 528 | |
| 529 | base::debug::StartProfiling(GetProfileName()); |
| 530 | |
| 531 | is_initialized_ = true; |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 532 | } |
| 533 | |
| 534 | void TestSuite::Shutdown() { |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 535 | DCHECK(is_initialized_); |
| 536 | base::debug::StopProfiling(); |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 537 | } |
Andrew Top | 0d1858f | 2019-05-15 22:01:47 -0700 | [diff] [blame] | 538 | |
| 539 | } // namespace base |