test_suite.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2009 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_on_start.h"
12#include "base/debug_util.h"
13#include "base/debug/debugger.h"
14#include "base/debug/debugger.h"
15#include "base/file_path.h"
16#include "base/i18n/icu_util.h"
17#include "base/logging.h"
18#include "base/mac/scoped_nsautorelease_pool.h"
19#include "base/nss_util.h"
20#include "base/path_service.h"
21#include "base/process_util.h"
22#include "base/scoped_ptr.h"
23#include "base/test/multiprocess_test.h"
24#include "base/test/test_timeouts.h"
25#include "base/time.h"
26#include "testing/gtest/include/gtest/gtest.h"
27#include "testing/multiprocess_func_list.h"
28
29#if defined(TOOLKIT_USES_GTK)
30#include <gtk/gtk.h>
31#endif
32
33namespace {
34
35class MaybeTestDisabler : public testing::EmptyTestEventListener {
36 public:
37  virtual void OnTestStart(const testing::TestInfo& test_info) {
38    ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info))
39        << "Probably the OS #ifdefs don't include all of the necessary "
40           "platforms.\nPlease ensure that no tests have the MAYBE_ prefix "
41           "after the code is preprocessed.";
42  }
43};
44
45}  // namespace
46
47const char TestSuite::kStrictFailureHandling[] = "strict_failure_handling";
48
49TestSuite::TestSuite(int argc, char** argv) {
50  base::EnableTerminationOnHeapCorruption();
51  CommandLine::Init(argc, argv);
52  testing::InitGoogleTest(&argc, argv);
53#if defined(TOOLKIT_USES_GTK)
54  g_thread_init(NULL);
55  gtk_init_check(&argc, &argv);
56#endif  // defined(TOOLKIT_USES_GTK)
57  // Don't add additional code to this constructor.  Instead add it to
58  // Initialize().  See bug 6436.
59}
60
61TestSuite::~TestSuite() {
62  CommandLine::Reset();
63}
64
65// static
66bool TestSuite::IsMarkedFlaky(const testing::TestInfo& test) {
67  return strncmp(test.name(), "FLAKY_", 6) == 0;
68}
69
70// static
71bool TestSuite::IsMarkedFailing(const testing::TestInfo& test) {
72  return strncmp(test.name(), "FAILS_", 6) == 0;
73}
74
75// static
76bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) {
77  return strncmp(test.name(), "MAYBE_", 6) == 0;
78}
79
80// static
81bool TestSuite::ShouldIgnoreFailure(const testing::TestInfo& test) {
82  if (CommandLine::ForCurrentProcess()->HasSwitch(kStrictFailureHandling))
83    return false;
84  return IsMarkedFlaky(test) || IsMarkedFailing(test);
85}
86
87// static
88bool TestSuite::NonIgnoredFailures(const testing::TestInfo& test) {
89  return test.should_run() && test.result()->Failed() &&
90      !ShouldIgnoreFailure(test);
91}
92
93int TestSuite::GetTestCount(TestMatch test_match) {
94  testing::UnitTest* instance = testing::UnitTest::GetInstance();
95  int count = 0;
96
97  for (int i = 0; i < instance->total_test_case_count(); ++i) {
98    const testing::TestCase& test_case = *instance->GetTestCase(i);
99    for (int j = 0; j < test_case.total_test_count(); ++j) {
100      if (test_match(*test_case.GetTestInfo(j))) {
101        count++;
102      }
103    }
104  }
105
106  return count;
107}
108
109void TestSuite::CatchMaybeTests() {
110  testing::TestEventListeners& listeners =
111      testing::UnitTest::GetInstance()->listeners();
112  listeners.Append(new MaybeTestDisabler);
113}
114
115// Don't add additional code to this method.  Instead add it to
116// Initialize().  See bug 6436.
117int TestSuite::Run() {
118  base::mac::ScopedNSAutoreleasePool scoped_pool;
119
120  Initialize();
121  std::string client_func =
122      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
123          switches::kTestChildProcess);
124  // Check to see if we are being run as a client process.
125  if (!client_func.empty())
126    return multi_process_function_list::InvokeChildProcessTest(client_func);
127  int result = RUN_ALL_TESTS();
128
129  // If there are failed tests, see if we should ignore the failures.
130  if (result != 0 && GetTestCount(&TestSuite::NonIgnoredFailures) == 0)
131    result = 0;
132
133  // Display the number of flaky tests.
134  int flaky_count = GetTestCount(&TestSuite::IsMarkedFlaky);
135  if (flaky_count) {
136    printf("  YOU HAVE %d FLAKY %s\n\n", flaky_count,
137           flaky_count == 1 ? "TEST" : "TESTS");
138  }
139
140  // Display the number of tests with ignored failures (FAILS).
141  int failing_count = GetTestCount(&TestSuite::IsMarkedFailing);
142  if (failing_count) {
143    printf("  YOU HAVE %d %s with ignored failures (FAILS prefix)\n\n",
144           failing_count, failing_count == 1 ? "test" : "tests");
145  }
146
147  // This MUST happen before Shutdown() since Shutdown() tears down
148  // objects (such as NotificationService::current()) that Cocoa
149  // objects use to remove themselves as observers.
150  scoped_pool.Recycle();
151
152  Shutdown();
153
154  return result;
155}
156
157// static
158void TestSuite::UnitTestAssertHandler(const std::string& str) {
159  RAW_LOG(FATAL, str.c_str());
160}
161
162void TestSuite::SuppressErrorDialogs() {
163#if defined(OS_WIN)
164  UINT new_flags = SEM_FAILCRITICALERRORS |
165                   SEM_NOGPFAULTERRORBOX |
166                   SEM_NOOPENFILEERRORBOX;
167
168  // Preserve existing error mode, as discussed at
169  // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
170  UINT existing_flags = SetErrorMode(new_flags);
171  SetErrorMode(existing_flags | new_flags);
172#endif  // defined(OS_WIN)
173}
174
175void TestSuite::Initialize() {
176  // Initialize logging.
177  FilePath exe;
178  PathService::Get(base::FILE_EXE, &exe);
179  FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
180  logging::InitLogging(log_filename.value().c_str(),
181                       logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
182                       logging::LOCK_LOG_FILE,
183                       logging::DELETE_OLD_LOG_FILE);
184  // We want process and thread IDs because we may have multiple processes.
185  // Note: temporarily enabled timestamps in an effort to catch bug 6361.
186  logging::SetLogItems(true, true, true, true);
187
188  CHECK(base::EnableInProcessStackDumping());
189#if defined(OS_WIN)
190  // Make sure we run with high resolution timer to minimize differences
191  // between production code and test code.
192  base::Time::EnableHighResolutionTimer(true);
193#endif  // defined(OS_WIN)
194
195  // In some cases, we do not want to see standard error dialogs.
196  if (!base::debug::BeingDebugged() &&
197      !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
198    SuppressErrorDialogs();
199    DebugUtil::SuppressDialogs();
200    logging::SetLogAssertHandler(UnitTestAssertHandler);
201  }
202
203  icu_util::Initialize();
204
205#if defined(USE_NSS)
206  // Trying to repeatedly initialize and cleanup NSS and NSPR may result in
207  // a deadlock. Such repeated initialization will happen when using test
208  // isolation. Prevent problems by initializing NSS here, so that the cleanup
209  // will be done only on process exit.
210  base::EnsureNSSInit();
211#endif  // defined(USE_NSS)
212
213  CatchMaybeTests();
214
215  TestTimeouts::Initialize();
216}
217
218void TestSuite::Shutdown() {
219}
220