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