Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
authorPhil Nash2017-08-08 17:53:01 +0100
committerPhil Nash2017-08-08 17:53:01 +0100
commitf247ce5bff025281d4a7e9fa76aa78eb8479ddfe (patch)
tree45de7761cc0a728936161d96e785ae397106c72c /include
parentf8148ebae1e07c5609ed0af5993694e2972d0dfd (diff)
downloadcatch3-f247ce5bff025281d4a7e9fa76aa78eb8479ddfe.tar.gz
First cut of new AssertionHandler/ Decomposer
- integrated into INTERNAL_CATCH_TEST. Needs more work to fully replace existing stuff
Diffstat (limited to 'include')
-rw-r--r--include/internal/catch_assertionhandler.cpp135
-rw-r--r--include/internal/catch_assertionhandler.h61
-rw-r--r--include/internal/catch_assertioninfo.h29
-rw-r--r--include/internal/catch_assertionresult.cpp36
-rw-r--r--include/internal/catch_assertionresult.h36
-rw-r--r--include/internal/catch_capture.hpp14
-rw-r--r--include/internal/catch_decomposer.cpp23
-rw-r--r--include/internal/catch_decomposer.h149
-rw-r--r--include/internal/catch_interfaces_reporter.cpp2
-rw-r--r--include/internal/catch_result_builder.cpp4
-rw-r--r--include/internal/catch_result_builder.h6
-rw-r--r--include/internal/catch_run_context.cpp2
-rw-r--r--include/reporters/catch_reporter_bases.hpp6
13 files changed, 464 insertions, 39 deletions
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 <iostream> // !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<typename T>
+ void handle( ExprLhs<T> 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 <string>
+#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<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
template<typename T> 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<bool>( !!(__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 <ostream>
+
+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<typename LhsT, typename RhsT>
+ 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<typename LhsT>
+ 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<typename LhsT, typename RhsT>
+ auto compareEqual( LhsT lhs, RhsT&& rhs ) -> bool { return lhs == rhs; };
+ template<typename T>
+ auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); };
+ template<typename T>
+ auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; };
+
+ template<typename LhsT, typename RhsT>
+ auto compareNotEqual( LhsT lhs, RhsT&& rhs ) -> bool { return lhs != rhs; };
+ template<typename T>
+ auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); };
+ template<typename T>
+ auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; };
+
+
+ template<typename LhsT>
+ class ExprLhs {
+ LhsT m_lhs;
+ public:
+ ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
+
+ template<typename RhsT>
+ auto operator == ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
+ return BinaryExpr<LhsT, RhsT&>( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs );
+ }
+ auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
+ return BinaryExpr<LhsT, bool>( m_lhs == rhs, m_lhs, "==", rhs );
+ }
+
+ template<typename RhsT>
+ auto operator != ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
+ return BinaryExpr<LhsT, RhsT&>( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs );
+ }
+ auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
+ return BinaryExpr<LhsT, bool>( m_lhs != rhs, m_lhs, "!=", rhs );
+ }
+
+ template<typename RhsT>
+ auto operator > ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
+ return BinaryExpr<LhsT, RhsT&>( m_lhs > rhs, m_lhs, ">", rhs );
+ }
+ template<typename RhsT>
+ auto operator < ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
+ return BinaryExpr<LhsT, RhsT&>( m_lhs < rhs, m_lhs, "<", rhs );
+ }
+ template<typename RhsT>
+ auto operator >= ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
+ return BinaryExpr<LhsT, RhsT&>( m_lhs >= rhs, m_lhs, ">=", rhs );
+ }
+ template<typename RhsT>
+ auto operator <= ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
+ return BinaryExpr<LhsT, RhsT&>( m_lhs <= rhs, m_lhs, "<=", rhs );
+ }
+
+ auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
+ return UnaryExpr<LhsT>( m_lhs );
+ }
+ };
+
+ void handleExpression( ITransientExpression const& expr );
+
+ template<typename T>
+ void handleExpression( ExprLhs<T> const& expr ) {
+ handleExpression( expr.makeUnaryExpr() );
+ }
+
+ struct Decomposer {
+ template<typename T>
+ auto operator <= ( T& lhs ) -> ExprLhs<T&> {
+ return ExprLhs<T&>( lhs );
+ }
+ template<typename T>
+ auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {
+ return ExprLhs<T const&>( lhs );
+ }
+ auto operator <=( bool value ) -> ExprLhs<bool> {
+ return ExprLhs<bool>( 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 <cassert>
@@ -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<typename T> 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<AssertionResult&>( assertionStats.assertionResult ) );
+ SectionNode& sectionNode = *m_sectionStack.back();
+ sectionNode.assertions.push_back(assertionStats);
return true;
}
void sectionEnded(SectionStats const& sectionStats) override {