test_suite.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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/command_line.h"
11#include "base/debug/debug_on_start_win.h"
12#include "base/debug/debugger.h"
13#include "base/debug/stack_trace.h"
14#include "base/file_util.h"
15#include "base/files/file_path.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_util.h"
22#include "base/test/multiprocess_test.h"
23#include "base/test/test_switches.h"
24#include "base/test/test_timeouts.h"
25#include "base/time/time.h"
26#include "testing/gtest/include/gtest/gtest.h"
27#include "testing/multiprocess_func_list.h"
28
29#if defined(OS_MACOSX)
30#include "base/mac/scoped_nsautorelease_pool.h"
31#if defined(OS_IOS)
32#include "base/test/test_listener_ios.h"
33#else
34#include "base/test/mock_chrome_application_mac.h"
35#endif  // OS_IOS
36#endif  // OS_MACOSX
37
38#if defined(OS_ANDROID)
39#include "base/test/test_support_android.h"
40#endif
41
42#if defined(OS_IOS)
43#include "base/test/test_support_ios.h"
44#endif
45
46#if defined(TOOLKIT_GTK)
47#include <gtk/gtk.h>
48#endif
49
50namespace {
51
52class MaybeTestDisabler : public testing::EmptyTestEventListener {
53 public:
54  virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE {
55    ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info))
56        << "Probably the OS #ifdefs don't include all of the necessary "
57           "platforms.\nPlease ensure that no tests have the MAYBE_ prefix "
58           "after the code is preprocessed.";
59  }
60};
61
62class TestClientInitializer : public testing::EmptyTestEventListener {
63 public:
64  TestClientInitializer()
65      : old_command_line_(CommandLine::NO_PROGRAM) {
66  }
67
68  virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE {
69    old_command_line_ = *CommandLine::ForCurrentProcess();
70  }
71
72  virtual void OnTestEnd(const testing::TestInfo& test_info) OVERRIDE {
73    *CommandLine::ForCurrentProcess() = old_command_line_;
74  }
75
76 private:
77  CommandLine old_command_line_;
78
79  DISALLOW_COPY_AND_ASSIGN(TestClientInitializer);
80};
81
82}  // namespace
83
84TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) {
85  PreInitialize(argc, argv, true);
86}
87
88TestSuite::TestSuite(int argc, char** argv, bool create_at_exit_manager)
89    : initialized_command_line_(false) {
90  PreInitialize(argc, argv, create_at_exit_manager);
91}
92
93TestSuite::~TestSuite() {
94  if (initialized_command_line_)
95    CommandLine::Reset();
96}
97
98void TestSuite::PreInitialize(int argc, char** argv,
99                              bool create_at_exit_manager) {
100#if defined(OS_WIN)
101  testing::GTEST_FLAG(catch_exceptions) = false;
102  base::TimeTicks::SetNowIsHighResNowIfSupported();
103#endif
104  base::EnableTerminationOnHeapCorruption();
105  initialized_command_line_ = CommandLine::Init(argc, argv);
106  testing::InitGoogleTest(&argc, argv);
107#if defined(OS_LINUX) && defined(USE_AURA)
108  // When calling native char conversion functions (e.g wrctomb) we need to
109  // have the locale set. In the absence of such a call the "C" locale is the
110  // default. In the gtk code (below) gtk_init() implicitly sets a locale.
111  setlocale(LC_ALL, "");
112#elif defined(TOOLKIT_GTK)
113  gtk_init_check(&argc, &argv);
114#endif  // defined(TOOLKIT_GTK)
115
116  // On Android, AtExitManager is created in
117  // testing/android/native_test_wrapper.cc before main() is called.
118#if !defined(OS_ANDROID)
119  if (create_at_exit_manager)
120    at_exit_manager_.reset(new base::AtExitManager);
121#endif
122
123#if defined(OS_IOS)
124  InitIOSRunHook(this, argc, argv);
125#endif
126
127  // Don't add additional code to this function.  Instead add it to
128  // Initialize().  See bug 6436.
129}
130
131
132// static
133bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) {
134  return strncmp(test.name(), "MAYBE_", 6) == 0;
135}
136
137void TestSuite::CatchMaybeTests() {
138  testing::TestEventListeners& listeners =
139      testing::UnitTest::GetInstance()->listeners();
140  listeners.Append(new MaybeTestDisabler);
141}
142
143void TestSuite::ResetCommandLine() {
144  testing::TestEventListeners& listeners =
145      testing::UnitTest::GetInstance()->listeners();
146  listeners.Append(new TestClientInitializer);
147}
148
149#if !defined(OS_IOS)
150void TestSuite::AddTestLauncherResultPrinter() {
151  // Only add the custom printer if requested.
152  if (!CommandLine::ForCurrentProcess()->HasSwitch(
153          switches::kTestLauncherOutput)) {
154    return;
155  }
156
157  FilePath output_path(CommandLine::ForCurrentProcess()->GetSwitchValuePath(
158                           switches::kTestLauncherOutput));
159
160  // Do not add the result printer if output path already exists. It's an
161  // indicator there is a process printing to that file, and we're likely
162  // its child. Do not clobber the results in that case.
163  if (PathExists(output_path)) {
164    LOG(WARNING) << "Test launcher output path " << output_path.AsUTF8Unsafe()
165                 << " exists. Not adding test launcher result printer.";
166    return;
167  }
168
169  XmlUnitTestResultPrinter* printer = new XmlUnitTestResultPrinter;
170  CHECK(printer->Initialize(output_path));
171  testing::TestEventListeners& listeners =
172      testing::UnitTest::GetInstance()->listeners();
173  listeners.Append(printer);
174}
175#endif  // !defined(OS_IOS)
176
177// Don't add additional code to this method.  Instead add it to
178// Initialize().  See bug 6436.
179int TestSuite::Run() {
180#if defined(OS_IOS)
181  RunTestsFromIOSApp();
182#endif
183
184#if defined(OS_MACOSX)
185  base::mac::ScopedNSAutoreleasePool scoped_pool;
186#endif
187
188  Initialize();
189  std::string client_func =
190      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
191          switches::kTestChildProcess);
192
193  // Check to see if we are being run as a client process.
194  if (!client_func.empty())
195    return multi_process_function_list::InvokeChildProcessTest(client_func);
196#if defined(OS_IOS)
197  base::test_listener_ios::RegisterTestEndListener();
198#endif
199  int result = RUN_ALL_TESTS();
200
201#if defined(OS_MACOSX)
202  // This MUST happen before Shutdown() since Shutdown() tears down
203  // objects (such as NotificationService::current()) that Cocoa
204  // objects use to remove themselves as observers.
205  scoped_pool.Recycle();
206#endif
207
208  Shutdown();
209
210  return result;
211}
212
213// static
214void TestSuite::UnitTestAssertHandler(const std::string& str) {
215  RAW_LOG(FATAL, str.c_str());
216}
217
218void TestSuite::SuppressErrorDialogs() {
219#if defined(OS_WIN)
220  UINT new_flags = SEM_FAILCRITICALERRORS |
221                   SEM_NOGPFAULTERRORBOX |
222                   SEM_NOOPENFILEERRORBOX;
223
224  // Preserve existing error mode, as discussed at
225  // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
226  UINT existing_flags = SetErrorMode(new_flags);
227  SetErrorMode(existing_flags | new_flags);
228
229#if defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1)
230  // Suppress the "Debug Assertion Failed" dialog.
231  // TODO(hbono): remove this code when gtest has it.
232  // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion
233  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
234  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
235#endif  // defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1)
236#endif  // defined(OS_WIN)
237}
238
239void TestSuite::Initialize() {
240#if defined(OS_MACOSX) && !defined(OS_IOS)
241  // Some of the app unit tests spin runloops.
242  mock_cr_app::RegisterMockCrApp();
243#endif
244
245#if defined(OS_IOS)
246  InitIOSTestMessageLoop();
247#endif  // OS_IOS
248
249#if defined(OS_ANDROID)
250  InitAndroidTest();
251#else
252  // Initialize logging.
253  base::FilePath exe;
254  PathService::Get(base::FILE_EXE, &exe);
255  base::FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
256  logging::LoggingSettings settings;
257  settings.logging_dest = logging::LOG_TO_ALL;
258  settings.log_file = log_filename.value().c_str();
259  settings.delete_old = logging::DELETE_OLD_LOG_FILE;
260  logging::InitLogging(settings);
261  // We want process and thread IDs because we may have multiple processes.
262  // Note: temporarily enabled timestamps in an effort to catch bug 6361.
263  logging::SetLogItems(true, true, true, true);
264#endif  // else defined(OS_ANDROID)
265
266  CHECK(base::debug::EnableInProcessStackDumping());
267#if defined(OS_WIN)
268  // Make sure we run with high resolution timer to minimize differences
269  // between production code and test code.
270  base::Time::EnableHighResolutionTimer(true);
271#endif  // defined(OS_WIN)
272
273  // In some cases, we do not want to see standard error dialogs.
274  if (!base::debug::BeingDebugged() &&
275      !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
276    SuppressErrorDialogs();
277    base::debug::SetSuppressDebugUI(true);
278    logging::SetLogAssertHandler(UnitTestAssertHandler);
279  }
280
281  base::i18n::InitializeICU();
282
283  CatchMaybeTests();
284  ResetCommandLine();
285#if !defined(OS_IOS)
286  AddTestLauncherResultPrinter();
287#endif  // !defined(OS_IOS)
288
289  TestTimeouts::Initialize();
290}
291
292void TestSuite::Shutdown() {
293}
294