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