summaryrefslogtreecommitdiffstats
path: root/chrome/test/test_launcher/test_runner.cc
blob: 5c3cf251ee55fc9d5ce5d00755b6a99e323173dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/test_launcher/test_runner.h"

#include <vector>

#include "base/command_line.h"
#include "base/logging.h"
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"

namespace {

const char kGTestListTestsFlag[] = "gtest_list_tests";
const char kGTestRunDisabledTestsFlag[] = "gtest_also_run_disabled_tests";

// Retrieves the list of tests to run by running gtest with the
// --gtest_list_tests flag in a forked process and parsing its output.
// |command_line| should contain the command line used to start the browser
// test launcher, it is expected that it does not contain the
// --gtest_list_tests flag already.
// Note: we cannot implement this in-process for InProcessTestRunner as GTest
// prints to the stdout and there are no good way of temporarily redirecting
// outputs.
bool GetTestList(const CommandLine& command_line,
                 std::vector<std::string>* test_list) {
  DCHECK(!command_line.HasSwitch(kGTestListTestsFlag));

  // Run ourselves with the --gtest_list_tests option and read the output.
  CommandLine new_command_line(command_line);
  new_command_line.AppendSwitch(kGTestListTestsFlag);
  std::string output;
  if (!base::GetAppOutput(new_command_line, &output))
    return false;

  // The output looks like:
  // TestCase.
  //   Test1
  //   Test2
  // OtherTestCase.
  //   FooTest
  // ...
  std::vector<std::string> lines;
  SplitString(output, '\n', &lines);

  std::string test_case;
  for (std::vector<std::string>::const_iterator iter = lines.begin();
       iter != lines.end(); ++iter) {
    std::string line = *iter;

    // Ignore empty and metadata lines (like "YOU HAVE x FLAKY TESTS").
    if (line.empty() || line.find(' ') != std::string::npos)
      continue;

    if (line[line.size() - 1] == '.') {
      // This is a new test case.
      test_case = line;
      continue;
    }

    if (!command_line.HasSwitch(kGTestRunDisabledTestsFlag) &&
        line.find("DISABLED") != std::string::npos)
      continue;  // Skip disabled tests.

    // We are dealing with a test.
    test_list->push_back(test_case + line);
  }
  return true;
}

}  // namespace

namespace tests {

TestRunner::TestRunner() {
}

TestRunner::~TestRunner() {
}

bool RunTests(const TestRunnerFactory& test_runner_factory) {
  const CommandLine* command_line = CommandLine::ForCurrentProcess();

  DCHECK(!command_line->HasSwitch(kGTestListTestsFlag));

  // First let's get the list of tests we need to run.
  std::vector<std::string> test_list;
  if (!GetTestList(*command_line, &test_list)) {
    printf("Failed to retrieve the tests to run.\n");
    return false;
  }

  if (test_list.empty()) {
    printf("No tests to run.\n");
    return false;
  }

  int test_run_count = 0;
  std::vector<std::string> failed_tests;
  for (std::vector<std::string>::const_iterator iter = test_list.begin();
       iter != test_list.end(); ++iter) {
    std::string test_name = *iter;
    scoped_ptr<TestRunner> test_runner(test_runner_factory.CreateTestRunner());
    if (!test_runner.get() || !test_runner->Init())
      return false;
    test_run_count++;
    if (!test_runner->RunTest(test_name.c_str())) {
      if (std::find(failed_tests.begin(), failed_tests.end(), test_name) ==
          failed_tests.end()) {
        failed_tests.push_back(*iter);
      }
    }
  }

  printf("%d test%s run\n", test_run_count, test_run_count > 1 ? "s" : "");
  printf("%d test%s failed\n", static_cast<int>(failed_tests.size()),
                               failed_tests.size() > 1 ? "s" : "");
  if (failed_tests.empty())
    return true;

  printf("Failing tests:\n");
  for (std::vector<std::string>::const_iterator iter = failed_tests.begin();
       iter != failed_tests.end(); ++iter) {
    printf("%s\n", iter->c_str());
  }

  return false;
}

}  // namespace