diff --git a/docs/reference/testing.md b/docs/reference/testing.md index 3ed5211117..1dbb2f3a24 100644 --- a/docs/reference/testing.md +++ b/docs/reference/testing.md @@ -1038,6 +1038,20 @@ int iteration)` Fired after each iteration of tests finishes. + +##### OnScopedTraceEnter {#TestEventListener::OnScopedTraceEnter} + +`virtual void TestEventListener::OnScopedTraceEnter(const UnitTest& unit_test, const char* file, +int line, std::string message)` + +Fired before the test scope enter. + +##### OnScopedTraceExit {#TestEventListener::OnScopedTraceExit} + +`virtual void TestEventListener::OnScopedTraceExit(const UnitTest& unit_test)` + +Fired after the test scope exit. + ##### OnTestProgramEnd {#TestEventListener::OnTestProgramEnd} `virtual void TestEventListener::OnTestProgramEnd(const UnitTest& unit_test)` diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index c899669520..cf20557381 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -982,6 +982,14 @@ class TestEventListener { // Fired after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; + + // Fired before the test scope enter. + virtual void OnScopedTraceEnter(const UnitTest& /*unit_test*/, + const char* /*file*/, int /*line*/, + std::string /*message*/) {} + + // Fired after the test scope exit. + virtual void OnScopedTraceExit(const UnitTest& /*unit_test*/) {} }; // The convenience class for users who need to override just one or two @@ -1061,6 +1069,7 @@ class GTEST_API_ TestEventListeners { private: friend class TestSuite; friend class TestInfo; + friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 6662a13ce1..168112765e 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -3817,6 +3817,9 @@ class TestEventRepeater : public TestEventListener { void OnEnvironmentsTearDownEnd(const UnitTest& parameter) override; void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; void OnTestProgramEnd(const UnitTest& parameter) override; + void OnScopedTraceEnter(const UnitTest& unit_test, const char* file, int line, + std::string message) override; + void OnScopedTraceExit(const UnitTest& unit_test) override; private: // Controls whether events will be forwarded to listeners_. Set to false @@ -3911,6 +3914,20 @@ void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, } } +void TestEventRepeater::OnScopedTraceEnter(const UnitTest& unit_test, + const char* file, int line, + std::string message) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnScopedTraceEnter(unit_test, file, line, message); + } +} + +void TestEventRepeater::OnScopedTraceExit(const UnitTest& unit_test) { + for (size_t i = listeners_.size(); i > 0; i--) { + listeners_[i - 1]->OnScopedTraceExit(unit_test); + } +} + // End TestEventRepeater #if GTEST_HAS_FILE_SYSTEM @@ -5603,12 +5620,15 @@ UnitTest::~UnitTest() { delete impl_; } // Google Test trace stack. void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_) { + impl_->listeners()->repeater()->OnScopedTraceEnter(*this, trace.file, + trace.line, trace.message); internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) { + impl_->listeners()->repeater()->OnScopedTraceExit(*this); internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } diff --git a/googletest/test/googletest-output-test_.cc b/googletest/test/googletest-output-test_.cc index e3560c0182..6152bdda45 100644 --- a/googletest/test/googletest-output-test_.cc +++ b/googletest/test/googletest-output-test_.cc @@ -250,6 +250,48 @@ TEST(SCOPED_TRACETest, CanBeRepeated) { << "contain trace point A, B, and D."; } +class MyScopedTraceTestListener : public ::testing::EmptyTestEventListener { + void OnScopedTraceEnter(const testing::UnitTest& unit_test, const char* file, + int line, std::string message) override { + const auto* test_info = unit_test.current_test_info(); + printf("scoped trace enter test: %s line: %d message: %s.\n", + test_info->name(), line, message.c_str()); + } + + void OnScopedTraceExit(const testing::UnitTest& unit_test) override { + printf("scoped trace exit test: %s.\n", + unit_test.current_test_info()->name()); + } +}; + +// Tests that multiple SCOPED_TRACEs can be used in the same scope. +TEST(SCOPED_TRACEWithListenerTest, CanBeRepeated) { + MyScopedTraceTestListener* listener = new MyScopedTraceTestListener; + ::testing::UnitTest::GetInstance()->listeners().Append(listener); + { + printf("(expected to fail)\n"); + SCOPED_TRACE("A"); + ADD_FAILURE() + << "This failure is expected, and should contain trace point A."; + + SCOPED_TRACE("B"); + ADD_FAILURE() + << "This failure is expected, and should contain trace point A and B."; + + { + SCOPED_TRACE("C"); + ADD_FAILURE() << "This failure is expected, and should " + << "contain trace point A, B, and C."; + } + + SCOPED_TRACE("D"); + ADD_FAILURE() << "This failure is expected, and should " + << "contain trace point A, B, and D."; + }; + ::testing::UnitTest::GetInstance()->listeners().Release(listener); + delete listener; +} + #ifdef GTEST_IS_THREADSAFE // Tests that SCOPED_TRACE()s can be used concurrently from multiple // threads. Namely, an assertion should be affected by