diff --git a/googletest/docs/AdvancedGuide.md b/googletest/docs/AdvancedGuide.md index e4dd94de..ccb087c0 100644 --- a/googletest/docs/AdvancedGuide.md +++ b/googletest/docs/AdvancedGuide.md @@ -787,15 +787,17 @@ If a test sub-routine is called from several places, when an assertion inside it fails, it can be hard to tell which invocation of the sub-routine the failure is from. You can alleviate this problem using extra logging or custom failure messages, but that usually clutters up -your tests. A better solution is to use the `SCOPED_TRACE` macro: +your tests. A better solution is to use the `SCOPED_TRACE` macro or +the `ScopedTrace` utility: -| `SCOPED_TRACE(`_message_`);` | -|:-----------------------------| +| `SCOPED_TRACE(`_message_`);` | `::testing::ScopedTrace trace(`_"file\_path"_`, `_line\_number_`, `_message_`);` | +|:-----------------------------|:---------------------------------------------------------------------------------| -where _message_ can be anything streamable to `std::ostream`. This -macro will cause the current file name, line number, and the given -message to be added in every failure message. The effect will be -undone when the control leaves the current lexical scope. +where `message` can be anything streamable to `std::ostream`. `SCOPED_TRACE` +macro will cause the current file name, line number, and the given message to be +added in every failure message. `ScopedTrace` accepts explicit file name and +line number in arguments, which is useful for writing test helpers. The effect +will be undone when the control leaves the current lexical scope. For example, diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index c4444cf6..4a8f6e0a 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -1299,9 +1299,9 @@ class GTEST_API_ UnitTest { // These classes and functions are friends as they need to access private // members of UnitTest. + friend class ScopedTrace; friend class Test; friend class internal::AssertHelper; - friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); @@ -2102,6 +2102,57 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) +// Causes a trace (including the given source file path and line number, +// and the given message) to be included in every test failure message generated +// by code in the scope of the lifetime of an instance of this class. The effect +// is undone with the destruction of the instance. +// +// The message argument can be anything streamable to std::ostream. +// +// Example: +// testing::ScopedTrace trace("file.cc", 123, "message"); +// +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + + // Template version. Uses Message() to convert the values into strings. + // Slow, but flexible. + template + ScopedTrace(const char* file, int line, const T& message) { + PushTrace(file, line, (Message() << message).GetString()); + } + + // Optimize for some known types. + ScopedTrace(const char* file, int line, const char* message) { + PushTrace(file, line, message ? message : "(null)"); + } + +#if GTEST_HAS_GLOBAL_STRING + ScopedTrace(const char* file, int line, const ::string& message) { + PushTrace(file, line, message); + } +#endif + + ScopedTrace(const char* file, int line, const std::string& message) { + PushTrace(file, line, message); + } + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + void PushTrace(const char* file, int line, std::string message); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is @@ -2118,7 +2169,7 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // Therefore, a SCOPED_TRACE() would (correctly) only affect the // assertions in its own thread. #define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, (message)) diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 88f94c4a..843058f3 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -95,7 +95,6 @@ template namespace internal { struct TraceInfo; // Information about a trace point. -class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest @@ -151,48 +150,6 @@ class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { #endif // GTEST_HAS_EXCEPTIONS -// A helper class for creating scoped traces in user programs. -class GTEST_API_ ScopedTrace { - public: - // The c'tor pushes the given source file location and message onto - // a trace stack maintained by Google Test. - - // Template version. Uses Message() to convert the values into strings. - // Slow, but flexible. - template - ScopedTrace(const char* file, int line, const T& message) { - PushTrace(file, line, (Message() << message).GetString()); - } - - // Optimize for some known types. - ScopedTrace(const char* file, int line, const char* message) { - PushTrace(file, line, message ? message : "(null)"); - } - -#if GTEST_HAS_GLOBAL_STRING - ScopedTrace(const char* file, int line, const ::string& message) { - PushTrace(file, line, message); - } -#endif - - ScopedTrace(const char* file, int line, const std::string& message) { - PushTrace(file, line, message); - } - - // The d'tor pops the info pushed by the c'tor. - // - // Note that the d'tor is not virtual in order to be efficient. - // Don't inherit from ScopedTrace! - ~ScopedTrace(); - - private: - void PushTrace(const char* file, int line, std::string message); - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); -} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its - // c'tor and d'tor. Therefore it doesn't - // need to be used otherwise. - namespace edit_distance { // Returns the optimal edits to go from 'left' to 'right'. // All edits cost the same, with replace having lower priority than diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 0aeeb8e7..ccaf99d2 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -3835,26 +3835,6 @@ void StreamingListener::SocketWriter::MakeConnection() { // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ -// Class ScopedTrace - -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -void ScopedTrace::PushTrace(const char* file, int line, std::string message) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message.swap(message); - - UnitTest::GetInstance()->PushGTestTrace(trace); -} - -// Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - UnitTest::GetInstance()->PopGTestTrace(); -} - - // class OsStackTraceGetter const char* const OsStackTraceGetterInterface::kElidedFramesMarker = @@ -5415,4 +5395,23 @@ std::string TempDir() { #endif // GTEST_OS_WINDOWS_MOBILE } +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +void ScopedTrace::PushTrace(const char* file, int line, std::string message) { + internal::TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message.swap(message); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); +} + } // namespace testing diff --git a/googletest/test/gtest_output_test.py b/googletest/test/gtest_output_test.py index 06dbee09..78a00156 100755 --- a/googletest/test/gtest_output_test.py +++ b/googletest/test/gtest_output_test.py @@ -99,7 +99,8 @@ def RemoveLocations(test_output): 'FILE_NAME:#: '. """ - return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output) + return re.sub(r'.*[/\\]((gtest_output_test_|gtest).cc)(\:\d+|\(\d+\))\: ', + r'\1:#: ', test_output) def RemoveStackTraceDetails(output): diff --git a/googletest/test/gtest_output_test_.cc b/googletest/test/gtest_output_test_.cc index 6aaba977..04ca5e5e 100644 --- a/googletest/test/gtest_output_test_.cc +++ b/googletest/test/gtest_output_test_.cc @@ -315,6 +315,13 @@ TEST(SCOPED_TRACETest, WorksConcurrently) { } #endif // GTEST_IS_THREADSAFE +// Tests basic functionality of the ScopedTrace utility (most of its features +// are already tested in SCOPED_TRACETest). +TEST(ScopedTraceTest, WithExplicitFileAndLine) { + testing::ScopedTrace trace("explicit_file.cc", 123, "expected trace message"); + ADD_FAILURE() << "Check that the trace is attached to a particular location."; +} + TEST(DisabledTestsWarningTest, DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) { // This test body is intentionally empty. Its sole purpose is for diff --git a/googletest/test/gtest_output_test_golden_lin.txt b/googletest/test/gtest_output_test_golden_lin.txt index 677d9f40..48f55932 100644 --- a/googletest/test/gtest_output_test_golden_lin.txt +++ b/googletest/test/gtest_output_test_golden_lin.txt @@ -8,7 +8,7 @@ gtest_output_test_.cc:#: Failure Expected equality of these values: 2 3 -[==========] Running 66 tests from 29 test cases. +[==========] Running 67 tests from 30 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. @@ -212,6 +212,14 @@ gtest_output_test_.cc:#: Failure Failed Expected failure #6 (in thread A, no trace alive). [ FAILED ] SCOPED_TRACETest.WorksConcurrently +[----------] 1 test from ScopedTraceTest +[ RUN ] ScopedTraceTest.WithExplicitFileAndLine +gtest_output_test_.cc:#: Failure +Failed +Check that the trace is attached to a particular location. +Google Test trace: +explicit_file.cc:123: expected trace message +[ FAILED ] ScopedTraceTest.WithExplicitFileAndLine [----------] 1 test from NonFatalFailureInFixtureConstructorTest [ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 5 failures) @@ -636,9 +644,9 @@ FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. -[==========] 66 tests from 29 test cases ran. +[==========] 67 tests from 30 test cases ran. [ PASSED ] 22 tests. -[ FAILED ] 44 tests, listed below: +[ FAILED ] 45 tests, listed below: [ FAILED ] NonfatalFailureTest.EscapesStringOperands [ FAILED ] NonfatalFailureTest.DiffForLongStrings [ FAILED ] FatalFailureTest.FatalFailureInSubroutine @@ -651,6 +659,7 @@ Expected fatal failure. [ FAILED ] SCOPED_TRACETest.CanBeNested [ FAILED ] SCOPED_TRACETest.CanBeRepeated [ FAILED ] SCOPED_TRACETest.WorksConcurrently +[ FAILED ] ScopedTraceTest.WithExplicitFileAndLine [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp @@ -684,7 +693,7 @@ Expected fatal failure. [ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 [ FAILED ] PrintingStrings/ParamTest.Failure/a, where GetParam() = "a" -44 FAILED TESTS +45 FAILED TESTS  YOU HAVE 1 DISABLED TEST Note: Google Test filter = FatalFailureTest.*:LoggingTest.*