• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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