Skip to content

Commit

Permalink
Googletest export
Browse files Browse the repository at this point in the history
Add --gtest_fail_fast support to googletest.

  - Analogous functionality to to golang -test.failfast and python --failfast
  - Stops test execution upon first test failure.
  - Also add support Bazel equivalent env var (TESTBRIDGE_TEST_RUNNER_FAIL_FAST)

PiperOrigin-RevId: 302488880
  • Loading branch information
Abseil Team authored and Xiaoyi Zhang committed Mar 24, 2020
1 parent 749148f commit 1ced315
Show file tree
Hide file tree
Showing 10 changed files with 784 additions and 54 deletions.
9 changes: 9 additions & 0 deletions googletest/docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -2116,6 +2116,15 @@ For example:
everything in test suite `FooTest` except `FooTest.Bar` and everything in
test suite `BarTest` except `BarTest.Foo`.

#### Stop test execution upon first failure

By default, a googletest program runs all tests the user has defined. In some
cases (e.g. iterative test development & execution) it may be desirable stop
test execution upon first failure (trading improved latency for completeness).
If `GTEST_FAIL_FAST` environment variable or `--gtest_fail_fast` flag is set,
the test runner will stop execution as soon as the first test failure is
found.

#### Temporarily Disabling Tests

If you have a broken test that you cannot fix right away, you can add the
Expand Down
10 changes: 10 additions & 0 deletions googletest/include/gtest/gtest.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ GTEST_DECLARE_bool_(catch_exceptions);
// to let Google Test decide.
GTEST_DECLARE_string_(color);

// This flag controls whether the test runner should continue execution past
// first failure.
GTEST_DECLARE_bool_(fail_fast);

// This flag sets up the filter to select by name using a glob pattern
// the tests to run. If the filter is not given all tests are executed.
GTEST_DECLARE_string_(filter);
Expand Down Expand Up @@ -795,6 +799,9 @@ class GTEST_API_ TestInfo {
// deletes it.
void Run();

// Skip and records the test result for this object.
void Skip();

static void ClearTestResult(TestInfo* test_info) {
test_info->result_.Clear();
}
Expand Down Expand Up @@ -943,6 +950,9 @@ class GTEST_API_ TestSuite {
// Runs every test in this TestSuite.
void Run();

// Skips the execution of tests under this TestSuite
void Skip();

// Runs SetUpTestSuite() for this TestSuite. This wrapper is needed
// for catching exceptions thrown from SetUpTestSuite().
void RunSetUpTestSuite() {
Expand Down
4 changes: 4 additions & 0 deletions googletest/src/gtest-internal-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
const char kBreakOnFailureFlag[] = "break_on_failure";
const char kCatchExceptionsFlag[] = "catch_exceptions";
const char kColorFlag[] = "color";
const char kFailFast[] = "fail_fast";
const char kFilterFlag[] = "filter";
const char kListTestsFlag[] = "list_tests";
const char kOutputFlag[] = "output";
Expand Down Expand Up @@ -164,6 +165,7 @@ class GTestFlagSaver {
color_ = GTEST_FLAG(color);
death_test_style_ = GTEST_FLAG(death_test_style);
death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
fail_fast_ = GTEST_FLAG(fail_fast);
filter_ = GTEST_FLAG(filter);
internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
list_tests_ = GTEST_FLAG(list_tests);
Expand All @@ -187,6 +189,7 @@ class GTestFlagSaver {
GTEST_FLAG(death_test_style) = death_test_style_;
GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
GTEST_FLAG(filter) = filter_;
GTEST_FLAG(fail_fast) = fail_fast_;
GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
GTEST_FLAG(list_tests) = list_tests_;
GTEST_FLAG(output) = output_;
Expand All @@ -208,6 +211,7 @@ class GTestFlagSaver {
std::string color_;
std::string death_test_style_;
bool death_test_use_fork_;
bool fail_fast_;
std::string filter_;
std::string internal_run_death_test_;
bool list_tests_;
Expand Down
130 changes: 105 additions & 25 deletions googletest/src/gtest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,21 @@ static const char* GetDefaultFilter() {
return kUniversalFilter;
}

// Bazel passes in the argument to '--test_runner_fail_fast' via the
// TESTBRIDGE_TEST_RUNNER_FAIL_FAST environment variable.
static bool GetDefaultFailFast() {
const char* const testbridge_test_runner_fail_fast =
internal::posix::GetEnv("TESTBRIDGE_TEST_RUNNER_FAIL_FAST");
if (testbridge_test_runner_fail_fast != nullptr) {
return strcmp(testbridge_test_runner_fail_fast, "1") == 0;
}
return false;
}

GTEST_DEFINE_bool_(
fail_fast, internal::BoolFromGTestEnv("fail_fast", GetDefaultFailFast()),
"True if and only if a test failure should stop further test execution.");

GTEST_DEFINE_bool_(
also_run_disabled_tests,
internal::BoolFromGTestEnv("also_run_disabled_tests", false),
Expand Down Expand Up @@ -2863,6 +2878,28 @@ void TestInfo::Run() {
impl->set_current_test_info(nullptr);
}

// Skip and records a skipped test result for this object.
void TestInfo::Skip() {
if (!should_run_) return;

internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
impl->set_current_test_info(this);

TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();

// Notifies the unit test event listeners that a test is about to start.
repeater->OnTestStart(*this);

const TestPartResult test_part_result =
TestPartResult(TestPartResult::kSkip, this->file(), this->line(), "");
impl->GetTestPartResultReporterForCurrentThread()->ReportTestPartResult(
test_part_result);

// Notifies the unit test event listener that a test has just finished.
repeater->OnTestEnd(*this);
impl->set_current_test_info(nullptr);
}

// class TestSuite

// Gets the number of successful tests in this test suite.
Expand Down Expand Up @@ -2975,6 +3012,12 @@ void TestSuite::Run() {
start_timestamp_ = internal::GetTimeInMillis();
for (int i = 0; i < total_test_count(); i++) {
GetMutableTestInfo(i)->Run();
if (GTEST_FLAG(fail_fast) && GetMutableTestInfo(i)->result()->Failed()) {
for (int j = i + 1; j < total_test_count(); j++) {
GetMutableTestInfo(j)->Skip();
}
break;
}
}
elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_;

Expand All @@ -2992,6 +3035,36 @@ void TestSuite::Run() {
impl->set_current_test_suite(nullptr);
}

// Skips all tests under this TestSuite.
void TestSuite::Skip() {
if (!should_run_) return;

internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
impl->set_current_test_suite(this);

TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();

// Call both legacy and the new API
repeater->OnTestSuiteStart(*this);
// Legacy API is deprecated but still available
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
repeater->OnTestCaseStart(*this);
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI

for (int i = 0; i < total_test_count(); i++) {
GetMutableTestInfo(i)->Skip();
}

// Call both legacy and the new API
repeater->OnTestSuiteEnd(*this);
// Legacy API is deprecated but still available
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
repeater->OnTestCaseEnd(*this);
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI

impl->set_current_test_suite(nullptr);
}

// Clears the results of all tests in this test suite.
void TestSuite::ClearResult() {
ad_hoc_test_result_.Clear();
Expand Down Expand Up @@ -5523,6 +5596,13 @@ bool UnitTestImpl::RunAllTests() {
for (int test_index = 0; test_index < total_test_suite_count();
test_index++) {
GetMutableSuiteCase(test_index)->Run();
if (GTEST_FLAG(fail_fast) &&
GetMutableSuiteCase(test_index)->Failed()) {
for (int j = test_index + 1; j < total_test_suite_count(); j++) {
GetMutableSuiteCase(j)->Skip();
}
break;
}
}
}

Expand Down Expand Up @@ -6127,31 +6207,31 @@ static const char kColorEncodedHelpMessage[] =
static bool ParseGoogleTestFlag(const char* const arg) {
return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
&GTEST_FLAG(also_run_disabled_tests)) ||
ParseBoolFlag(arg, kBreakOnFailureFlag,
&GTEST_FLAG(break_on_failure)) ||
ParseBoolFlag(arg, kCatchExceptionsFlag,
&GTEST_FLAG(catch_exceptions)) ||
ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
ParseStringFlag(arg, kDeathTestStyleFlag,
&GTEST_FLAG(death_test_style)) ||
ParseBoolFlag(arg, kDeathTestUseFork,
&GTEST_FLAG(death_test_use_fork)) ||
ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
ParseStringFlag(arg, kInternalRunDeathTestFlag,
&GTEST_FLAG(internal_run_death_test)) ||
ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
ParseBoolFlag(arg, kPrintUTF8Flag, &GTEST_FLAG(print_utf8)) ||
ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
ParseInt32Flag(arg, kStackTraceDepthFlag,
&GTEST_FLAG(stack_trace_depth)) ||
ParseStringFlag(arg, kStreamResultToFlag,
&GTEST_FLAG(stream_result_to)) ||
ParseBoolFlag(arg, kThrowOnFailureFlag,
&GTEST_FLAG(throw_on_failure));
ParseBoolFlag(arg, kBreakOnFailureFlag,
&GTEST_FLAG(break_on_failure)) ||
ParseBoolFlag(arg, kCatchExceptionsFlag,
&GTEST_FLAG(catch_exceptions)) ||
ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
ParseStringFlag(arg, kDeathTestStyleFlag,
&GTEST_FLAG(death_test_style)) ||
ParseBoolFlag(arg, kDeathTestUseFork,
&GTEST_FLAG(death_test_use_fork)) ||
ParseBoolFlag(arg, kFailFast, &GTEST_FLAG(fail_fast)) ||
ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
ParseStringFlag(arg, kInternalRunDeathTestFlag,
&GTEST_FLAG(internal_run_death_test)) ||
ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
ParseBoolFlag(arg, kPrintUTF8Flag, &GTEST_FLAG(print_utf8)) ||
ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
ParseInt32Flag(arg, kStackTraceDepthFlag,
&GTEST_FLAG(stack_trace_depth)) ||
ParseStringFlag(arg, kStreamResultToFlag,
&GTEST_FLAG(stream_result_to)) ||
ParseBoolFlag(arg, kThrowOnFailureFlag, &GTEST_FLAG(throw_on_failure));
}

#if GTEST_USE_OWN_FLAGFILE_FLAG_
Expand Down
16 changes: 16 additions & 0 deletions googletest/test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ cc_test(
"googletest-catch-exceptions-test_.cc",
"googletest-color-test_.cc",
"googletest-env-var-test_.cc",
"googletest-failfast-unittest_.cc",
"googletest-filter-unittest_.cc",
"googletest-break-on-failure-unittest_.cc",
"googletest-listener-test.cc",
Expand Down Expand Up @@ -222,6 +223,21 @@ py_test(
deps = [":gtest_test_utils"],
)

cc_binary(
name = "googletest-failfast-unittest_",
testonly = 1,
srcs = ["googletest-failfast-unittest_.cc"],
deps = ["//:gtest"],
)

py_test(
name = "googletest-failfast-unittest",
size = "medium",
srcs = ["googletest-failfast-unittest.py"],
data = [":googletest-failfast-unittest_"],
deps = [":gtest_test_utils"],
)

cc_binary(
name = "googletest-filter-unittest_",
testonly = 1,
Expand Down
2 changes: 2 additions & 0 deletions googletest/test/googletest-env-var-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ def testEnvVarAffectsFlag(self):

TestFlag('break_on_failure', '1', '0')
TestFlag('color', 'yes', 'auto')
SetEnvVar('TESTBRIDGE_TEST_RUNNER_FAIL_FAST', None) # For 'fail_fast' test
TestFlag('fail_fast', '1', '0')
TestFlag('filter', 'FooTest.Bar', '*')
SetEnvVar('XML_OUTPUT_FILE', None) # For 'output' test
TestFlag('output', 'xml:tmp/foo.xml', '')
Expand Down
5 changes: 5 additions & 0 deletions googletest/test/googletest-env-var-test_.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ void PrintFlag(const char* flag) {
return;
}

if (strcmp(flag, "fail_fast") == 0) {
cout << GTEST_FLAG(fail_fast);
return;
}

if (strcmp(flag, "filter") == 0) {
cout << GTEST_FLAG(filter);
return;
Expand Down
Loading

0 comments on commit 1ced315

Please sign in to comment.