From f247ce5bff025281d4a7e9fa76aa78eb8479ddfe Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 17:53:01 +0100 Subject: [PATCH] First cut of new AssertionHandler/ Decomposer - integrated into INTERNAL_CATCH_TEST. Needs more work to fully replace existing stuff --- CMakeLists.txt | 5 + include/internal/catch_assertionhandler.cpp | 135 ++++++++++++++++ include/internal/catch_assertionhandler.h | 61 +++++++ include/internal/catch_assertioninfo.h | 29 ++++ include/internal/catch_assertionresult.cpp | 36 +++-- include/internal/catch_assertionresult.h | 36 +++-- include/internal/catch_capture.hpp | 14 +- include/internal/catch_decomposer.cpp | 23 +++ include/internal/catch_decomposer.h | 149 ++++++++++++++++++ .../internal/catch_interfaces_reporter.cpp | 2 + include/internal/catch_result_builder.cpp | 4 +- include/internal/catch_result_builder.h | 6 +- include/internal/catch_run_context.cpp | 2 +- include/reporters/catch_reporter_bases.hpp | 6 +- 14 files changed, 469 insertions(+), 39 deletions(-) create mode 100644 include/internal/catch_assertionhandler.cpp create mode 100644 include/internal/catch_assertionhandler.h create mode 100644 include/internal/catch_assertioninfo.h create mode 100644 include/internal/catch_decomposer.cpp create mode 100644 include/internal/catch_decomposer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 211bfd9d..e454e330 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,8 @@ CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external) # Please keep these ordered alphabetically set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_approx.hpp + ${HEADER_DIR}/internal/catch_assertionhandler.h + ${HEADER_DIR}/internal/catch_assertioninfo.h ${HEADER_DIR}/internal/catch_assertionresult.h ${HEADER_DIR}/internal/catch_capture.hpp ${HEADER_DIR}/internal/catch_clara.h @@ -132,6 +134,7 @@ set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_console_colour.hpp ${HEADER_DIR}/internal/catch_context.h ${HEADER_DIR}/internal/catch_debugger.h + ${HEADER_DIR}/internal/catch_decomposer.h ${HEADER_DIR}/internal/catch_default_main.hpp ${HEADER_DIR}/internal/catch_enforce.h ${HEADER_DIR}/internal/catch_errno_guard.h @@ -198,6 +201,7 @@ set(INTERNAL_HEADERS ) set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_approx.cpp + ${HEADER_DIR}/internal/catch_assertionhandler.cpp ${HEADER_DIR}/internal/catch_assertionresult.cpp ${HEADER_DIR}/internal/catch_benchmark.cpp ${HEADER_DIR}/internal/catch_commandline.cpp @@ -206,6 +210,7 @@ set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_console_colour.cpp ${HEADER_DIR}/internal/catch_context.cpp ${HEADER_DIR}/internal/catch_debugger.cpp + ${HEADER_DIR}/internal/catch_decomposer.cpp ${HEADER_DIR}/internal/catch_errno_guard.cpp ${HEADER_DIR}/internal/catch_evaluate.cpp ${HEADER_DIR}/internal/catch_exception_translator_registry.cpp diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp new file mode 100644 index 00000000..a71a2dc2 --- /dev/null +++ b/include/internal/catch_assertionhandler.cpp @@ -0,0 +1,135 @@ +/* + * Created by Phil on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "catch_assertionhandler.h" +#include "catch_assertionresult.h" +#include "catch_interfaces_capture.h" +#include "catch_interfaces_runner.h" +#include "catch_context.h" +#include "catch_debugger.h" +#include "catch_interfaces_registry_hub.h" + +#include // !TBD + +namespace Catch { + + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } + + LazyExpression::LazyExpression( bool isNegated ) + : m_isNegated( isNegated ) + {} + + LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + + LazyExpression::operator bool() const { + return m_transientExpression != nullptr; + } + + auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { + if( lazyExpr.m_isNegated ) + os << "!"; + + if( lazyExpr ) { + if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) + os << "(" << *lazyExpr.m_transientExpression << ")"; + else + os << *lazyExpr.m_transientExpression; + } + else { + os << "{** error - unchecked empty expression requested **}"; + } + return os; + } + + AssertionHandler::AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } + { + getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); + } + + void AssertionHandler::handle( ITransientExpression const& expr ) { + + bool negated = isFalseTest( m_assertionInfo.resultDisposition ); + bool result = expr.getResult() != negated; + + AssertionResultData data( result ? ResultWas::Ok : ResultWas::ExpressionFailed, LazyExpression( negated ) ); + + // Deprecated +// data.negated = negated; +// data.parenthesized = negated && expr.isBinaryExpression(); // !TBD: needed? +// data.decomposedExpression = nullptr; // !TBD +// data.reconstructedExpression = ""; // !TBD + + + getResultCapture().assertionRun(); + + AssertionResult assertionResult{ m_assertionInfo, data }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = &expr; + + getResultCapture().assertionEnded( assertionResult ); + + if( !assertionResult.isOk() ) { + m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); + m_shouldThrow = + getCurrentContext().getRunner()->aborting() || + (m_assertionInfo.resultDisposition & ResultDisposition::Normal); + } + } + + auto AssertionHandler::shouldDebugBreak() const -> bool { + return m_shouldDebugBreak; + } + void AssertionHandler::reactWithDebugBreak() const { + if (m_shouldDebugBreak) { + /////////////////////////////////////////////////////////////////// + // To inspect the state during test, you need to go one level up the callstack + // To go back to the test and change execution, jump over the reactWithoutDebugBreak() call + /////////////////////////////////////////////////////////////////// + CATCH_BREAK_INTO_DEBUGGER(); + } + reactWithoutDebugBreak(); + } + void AssertionHandler::reactWithoutDebugBreak() const { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + void AssertionHandler::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + useActiveException(); + } + void AssertionHandler::useActiveException() { + bool negated = isFalseTest( m_assertionInfo.resultDisposition ); + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( negated ) ); + data.message = Catch::translateActiveException(); + + //data.decomposedExpression = &expr; // for lazy reconstruction + + AssertionResult result( m_assertionInfo, data ); + + getResultCapture().assertionEnded( result ); + + // !TBD: factor this out? handleResult()? + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + + } + +} // namespace Catch diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h new file mode 100644 index 00000000..8c8dff67 --- /dev/null +++ b/include/internal/catch_assertionhandler.h @@ -0,0 +1,61 @@ +/* + * Created by Phil on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED +#define TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED + +#include "catch_decomposer.h" +#include "catch_assertioninfo.h" + +namespace Catch { + + struct TestFailureException{}; + + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ); + LazyExpression( LazyExpression const& other ); + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const; + + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; + + class AssertionHandler { + AssertionInfo m_assertionInfo; + bool m_shouldDebugBreak = false; + bool m_shouldThrow = false; + public: + AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ); + + void handle( ITransientExpression const& expr ); + + template + void handle( ExprLhs const& expr ) { + handle( expr.makeUnaryExpr() ); + } + + auto shouldDebugBreak() const -> bool; + void reactWithDebugBreak() const; + void reactWithoutDebugBreak() const; + void useActiveException( ResultDisposition::Flags resultDisposition ); + void useActiveException(); + }; + +} // namespace Catch + +#endif // TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED diff --git a/include/internal/catch_assertioninfo.h b/include/internal/catch_assertioninfo.h new file mode 100644 index 00000000..21646b21 --- /dev/null +++ b/include/internal/catch_assertioninfo.h @@ -0,0 +1,29 @@ +/* + * Created by Phil on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED +#define TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED + +#include "catch_result_type.h" +#include "catch_common.h" +#include "catch_stringref.h" + +namespace Catch { + + struct AssertionInfo + { + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + + AssertionInfo() = delete; + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED diff --git a/include/internal/catch_assertionresult.cpp b/include/internal/catch_assertionresult.cpp index 6819cd63..877f53bf 100644 --- a/include/internal/catch_assertionresult.cpp +++ b/include/internal/catch_assertionresult.cpp @@ -24,17 +24,30 @@ namespace Catch { resultType = ResultWas::Ok; } - std::string const& AssertionResultData::reconstructExpression() const { - if( decomposedExpression != nullptr ) { - decomposedExpression->reconstructExpression( reconstructedExpression ); - if( parenthesized ) { - reconstructedExpression.insert( 0, 1, '(' ); - reconstructedExpression.append( 1, ')' ); + std::string AssertionResultData::reconstructExpression() const { + + if( reconstructedExpression.empty() ) { + + // Try new LazyExpression first... + if( lazyExpression ) { + // !TBD Use stringstream for now, but rework above to pass stream in + std::ostringstream oss; + oss << lazyExpression; + reconstructedExpression = oss.str(); } - if( negated ) { - reconstructedExpression.insert( 0, 1, '!' ); + + // ... if not, fall back to decomposedExpression + else if( decomposedExpression != nullptr ) { + decomposedExpression->reconstructExpression( reconstructedExpression ); + if( parenthesized ) { + reconstructedExpression.insert( 0, 1, '(' ); + reconstructedExpression.append( 1, ')' ); + } + if( negated ) { + reconstructedExpression.insert( 0, 1, '!' ); + } + decomposedExpression = nullptr; } - decomposedExpression = nullptr; } return reconstructedExpression; } @@ -85,7 +98,10 @@ namespace Catch { } std::string AssertionResult::getExpandedExpression() const { - return m_resultData.reconstructExpression(); + std::string expr = m_resultData.reconstructExpression(); + return expr.empty() + ? getExpression() + : expr; } std::string AssertionResult::getMessage() const { diff --git a/include/internal/catch_assertionresult.h b/include/internal/catch_assertionresult.h index 7e67faaa..9bd8e39d 100644 --- a/include/internal/catch_assertionresult.h +++ b/include/internal/catch_assertionresult.h @@ -9,9 +9,11 @@ #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED #include +#include "catch_assertioninfo.h" #include "catch_result_type.h" #include "catch_common.h" #include "catch_stringref.h" +#include "catch_assertionhandler.h" namespace Catch { @@ -37,28 +39,32 @@ namespace Catch { template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); }; +} - struct AssertionInfo - { - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - - AssertionInfo() = delete; - }; +namespace Catch { struct AssertionResultData { - void negate( bool parenthesize ); - std::string const& reconstructExpression() const; + AssertionResultData() = delete; + + // !TBD We won't need this constructor once the deprecated fields are removed + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ) + : resultType( _resultType ), + lazyExpression( _lazyExpression ) + {} - mutable DecomposedExpression const* decomposedExpression = nullptr; - mutable std::string reconstructedExpression; - std::string message; ResultWas::OfType resultType = ResultWas::Unknown; + std::string message; + + LazyExpression lazyExpression; + + // deprecated: bool negated = false; bool parenthesized = false; + void negate( bool parenthesize ); + std::string reconstructExpression() const; + mutable DecomposedExpression const* decomposedExpression = nullptr; + mutable std::string reconstructedExpression; }; class AssertionResult { @@ -81,7 +87,7 @@ namespace Catch { void discardDecomposedExpression() const; void expandDecomposedExpression() const; - protected: + //protected: AssertionInfo m_info; AssertionResultData m_resultData; }; diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index c5438266..aafafeef 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -8,6 +8,7 @@ #ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED +#include "catch_assertionhandler.h" #include "catch_result_builder.h" #include "catch_message.h" #include "catch_interfaces_capture.h" @@ -43,7 +44,10 @@ // source code rather than in Catch library code #define INTERNAL_CATCH_REACT( resultBuilder ) \ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - resultBuilder.react(); + resultBuilder.react(); +#define INTERNAL_CATCH_REACT2( handler ) \ + if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + handler.reactWithDebugBreak(); #define INTERNAL_CATCH_TRY try #define INTERNAL_CATCH_CATCH( capturer, disposition ) catch(...) { capturer.useActiveException( disposition ); } @@ -53,13 +57,13 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - ( __catchResult <= __VA_ARGS__ ).endExpression(); \ + catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } INTERNAL_CATCH_CATCH( __catchResult, resultDisposition ) \ - INTERNAL_CATCH_REACT( __catchResult ) \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler, resultDisposition ) \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. diff --git a/include/internal/catch_decomposer.cpp b/include/internal/catch_decomposer.cpp new file mode 100644 index 00000000..6e69bc43 --- /dev/null +++ b/include/internal/catch_decomposer.cpp @@ -0,0 +1,23 @@ +/* + * Created by Phil Nash on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "catch_decomposer.h" +#include "catch_config.hpp" + +namespace Catch { + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ) { + + if( lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ) + os << lhs << " " << op << " " << rhs; + else + os << lhs << "\n" << op << "\n" << rhs; + } +} \ No newline at end of file diff --git a/include/internal/catch_decomposer.h b/include/internal/catch_decomposer.h new file mode 100644 index 00000000..82e386a5 --- /dev/null +++ b/include/internal/catch_decomposer.h @@ -0,0 +1,149 @@ +/* + * Created by Phil Nash on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED +#define TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED + +#include "catch_tostring.h" +#include "catch_stringref.h" + +#include + +namespace Catch { + + struct ITransientExpression { + virtual auto isBinaryExpression() const -> bool = 0; + virtual auto getResult() const -> bool = 0; + virtual void streamReconstructedExpression( std::ostream &os ) const = 0; + }; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ); + + template + class BinaryExpr : public ITransientExpression { + bool m_result; + LhsT m_lhs; + std::string m_op; + RhsT m_rhs; + + auto isBinaryExpression() const -> bool override { return true; } + auto getResult() const -> bool override { return m_result; } + + void streamReconstructedExpression( std::ostream &os ) const override { + formatReconstructedExpression + ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); + } + + public: + BinaryExpr( bool comparisionResult, LhsT lhs, StringRef op, RhsT rhs ) + : m_result( comparisionResult ), + m_lhs( lhs ), + m_op( op.c_str() ), + m_rhs( rhs ) + {} + }; + + template + class UnaryExpr : public ITransientExpression { + LhsT m_lhs; + + auto isBinaryExpression() const -> bool override { return false; } + auto getResult() const -> bool override { return m_lhs ? true : false; } + + void streamReconstructedExpression( std::ostream &os ) const override { + os << Catch::Detail::stringify( m_lhs ); + } + + public: + UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} + }; + + + // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) + template + auto compareEqual( LhsT lhs, RhsT&& rhs ) -> bool { return lhs == rhs; }; + template + auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); }; + template + auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; }; + + template + auto compareNotEqual( LhsT lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; + template + auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); }; + template + auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; }; + + + template + class ExprLhs { + LhsT m_lhs; + public: + ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + + template + auto operator == ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); + } + auto operator == ( bool rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs ); + } + + template + auto operator != ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); + } + auto operator != ( bool rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs ); + } + + template + auto operator > ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs ); + } + template + auto operator < ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs ); + } + template + auto operator >= ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs ); + } + template + auto operator <= ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs ); + } + + auto makeUnaryExpr() const -> UnaryExpr { + return UnaryExpr( m_lhs ); + } + }; + + void handleExpression( ITransientExpression const& expr ); + + template + void handleExpression( ExprLhs const& expr ) { + handleExpression( expr.makeUnaryExpr() ); + } + + struct Decomposer { + template + auto operator <= ( T& lhs ) -> ExprLhs { + return ExprLhs( lhs ); + } + template + auto operator <= ( T const& lhs ) -> ExprLhs { + return ExprLhs( lhs ); + } + auto operator <=( bool value ) -> ExprLhs { + return ExprLhs( value ); + } + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED diff --git a/include/internal/catch_interfaces_reporter.cpp b/include/internal/catch_interfaces_reporter.cpp index 2f820bf8..05117f9e 100644 --- a/include/internal/catch_interfaces_reporter.cpp +++ b/include/internal/catch_interfaces_reporter.cpp @@ -37,6 +37,8 @@ namespace Catch { infoMessages( _infoMessages ), totals( _totals ) { + assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; + if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere diff --git a/include/internal/catch_result_builder.cpp b/include/internal/catch_result_builder.cpp index a908c359..db7dfb14 100644 --- a/include/internal/catch_result_builder.cpp +++ b/include/internal/catch_result_builder.cpp @@ -13,7 +13,6 @@ #include "catch_interfaces_capture.h" #include "catch_interfaces_registry_hub.h" #include "catch_matchers_string.h" -#include "catch_wildcard_pattern.hpp" #include "catch_debugger.h" #include @@ -34,7 +33,8 @@ namespace Catch { SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_data( ResultWas::Unknown, LazyExpression( false ) ) { getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); } diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h index 1ccdd9c0..6d3a9efc 100644 --- a/include/internal/catch_result_builder.h +++ b/include/internal/catch_result_builder.h @@ -8,8 +8,10 @@ #ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED -#include "catch_result_type.h" #include "catch_assertionresult.h" +#include "catch_decomposer.h" + +#include "catch_result_type.h" #include "catch_common.h" #include "catch_matchers.hpp" @@ -17,8 +19,6 @@ namespace Catch { - struct TestFailureException{}; - template class ExpressionLhs; struct CopyableStream { diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index 8b89df9c..509a18e6 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -192,7 +192,7 @@ namespace Catch { void RunContext::handleFatalErrorCondition(std::string const & message) { // Don't rebuild the result -- the stringification itself can cause more fatal errors // Instead, fake a result data. - AssertionResultData tempResult; + AssertionResultData tempResult( ResultWas::Unknown, { false } ); tempResult.resultType = ResultWas::FatalErrorCondition; tempResult.message = message; AssertionResult result(m_lastAssertionInfo, tempResult); diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp index 37cc4e00..2f9a8013 100644 --- a/include/reporters/catch_reporter_bases.hpp +++ b/include/reporters/catch_reporter_bases.hpp @@ -193,14 +193,14 @@ namespace Catch { bool assertionEnded(AssertionStats const& assertionStats) override { assert(!m_sectionStack.empty()); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back(assertionStats); // AssertionResult holds a pointer to a temporary DecomposedExpression, // which getExpandedExpression() calls to build the expression string. // Our section stack copy of the assertionResult will likely outlive the // temporary, so it must be expanded or discarded now to avoid calling // a destroyed object later. - prepareExpandedExpression(sectionNode.assertions.back().assertionResult); + prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back(assertionStats); return true; } void sectionEnded(SectionStats const& sectionStats) override {