mirror of
https://github.com/catchorg/Catch2.git
synced 2024-12-23 03:43:28 +01:00
First cut of new AssertionHandler/ Decomposer
- integrated into INTERNAL_CATCH_TEST. Needs more work to fully replace existing stuff
This commit is contained in:
parent
f8148ebae1
commit
f247ce5bff
@ -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
|
||||
|
135
include/internal/catch_assertionhandler.cpp
Normal file
135
include/internal/catch_assertionhandler.cpp
Normal file
@ -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
|
61
include/internal/catch_assertionhandler.h
Normal file
61
include/internal/catch_assertionhandler.h
Normal file
@ -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
|
29
include/internal/catch_assertioninfo.h
Normal file
29
include/internal/catch_assertioninfo.h
Normal file
@ -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
|
@ -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 {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 &&.
|
||||
|
||||
|
23
include/internal/catch_decomposer.cpp
Normal file
23
include/internal/catch_decomposer.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
149
include/internal/catch_decomposer.h
Normal file
149
include/internal/catch_decomposer.h
Normal file
@ -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
|
@ -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
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user