mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-26 15:26:11 +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
|
# Please keep these ordered alphabetically
|
||||||
set(INTERNAL_HEADERS
|
set(INTERNAL_HEADERS
|
||||||
${HEADER_DIR}/internal/catch_approx.hpp
|
${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_assertionresult.h
|
||||||
${HEADER_DIR}/internal/catch_capture.hpp
|
${HEADER_DIR}/internal/catch_capture.hpp
|
||||||
${HEADER_DIR}/internal/catch_clara.h
|
${HEADER_DIR}/internal/catch_clara.h
|
||||||
@ -132,6 +134,7 @@ set(INTERNAL_HEADERS
|
|||||||
${HEADER_DIR}/internal/catch_console_colour.hpp
|
${HEADER_DIR}/internal/catch_console_colour.hpp
|
||||||
${HEADER_DIR}/internal/catch_context.h
|
${HEADER_DIR}/internal/catch_context.h
|
||||||
${HEADER_DIR}/internal/catch_debugger.h
|
${HEADER_DIR}/internal/catch_debugger.h
|
||||||
|
${HEADER_DIR}/internal/catch_decomposer.h
|
||||||
${HEADER_DIR}/internal/catch_default_main.hpp
|
${HEADER_DIR}/internal/catch_default_main.hpp
|
||||||
${HEADER_DIR}/internal/catch_enforce.h
|
${HEADER_DIR}/internal/catch_enforce.h
|
||||||
${HEADER_DIR}/internal/catch_errno_guard.h
|
${HEADER_DIR}/internal/catch_errno_guard.h
|
||||||
@ -198,6 +201,7 @@ set(INTERNAL_HEADERS
|
|||||||
)
|
)
|
||||||
set(IMPL_SOURCES
|
set(IMPL_SOURCES
|
||||||
${HEADER_DIR}/internal/catch_approx.cpp
|
${HEADER_DIR}/internal/catch_approx.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_assertionhandler.cpp
|
||||||
${HEADER_DIR}/internal/catch_assertionresult.cpp
|
${HEADER_DIR}/internal/catch_assertionresult.cpp
|
||||||
${HEADER_DIR}/internal/catch_benchmark.cpp
|
${HEADER_DIR}/internal/catch_benchmark.cpp
|
||||||
${HEADER_DIR}/internal/catch_commandline.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_console_colour.cpp
|
||||||
${HEADER_DIR}/internal/catch_context.cpp
|
${HEADER_DIR}/internal/catch_context.cpp
|
||||||
${HEADER_DIR}/internal/catch_debugger.cpp
|
${HEADER_DIR}/internal/catch_debugger.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_decomposer.cpp
|
||||||
${HEADER_DIR}/internal/catch_errno_guard.cpp
|
${HEADER_DIR}/internal/catch_errno_guard.cpp
|
||||||
${HEADER_DIR}/internal/catch_evaluate.cpp
|
${HEADER_DIR}/internal/catch_evaluate.cpp
|
||||||
${HEADER_DIR}/internal/catch_exception_translator_registry.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,8 +24,20 @@ namespace Catch {
|
|||||||
resultType = ResultWas::Ok;
|
resultType = ResultWas::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& AssertionResultData::reconstructExpression() const {
|
std::string AssertionResultData::reconstructExpression() const {
|
||||||
if( decomposedExpression != nullptr ) {
|
|
||||||
|
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 not, fall back to decomposedExpression
|
||||||
|
else if( decomposedExpression != nullptr ) {
|
||||||
decomposedExpression->reconstructExpression( reconstructedExpression );
|
decomposedExpression->reconstructExpression( reconstructedExpression );
|
||||||
if( parenthesized ) {
|
if( parenthesized ) {
|
||||||
reconstructedExpression.insert( 0, 1, '(' );
|
reconstructedExpression.insert( 0, 1, '(' );
|
||||||
@ -36,6 +48,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
decomposedExpression = nullptr;
|
decomposedExpression = nullptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return reconstructedExpression;
|
return reconstructedExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +98,10 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string AssertionResult::getExpandedExpression() const {
|
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 {
|
std::string AssertionResult::getMessage() const {
|
||||||
|
@ -9,9 +9,11 @@
|
|||||||
#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "catch_assertioninfo.h"
|
||||||
#include "catch_result_type.h"
|
#include "catch_result_type.h"
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
#include "catch_stringref.h"
|
#include "catch_stringref.h"
|
||||||
|
#include "catch_assertionhandler.h"
|
||||||
|
|
||||||
namespace Catch {
|
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& );
|
||||||
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
|
namespace Catch {
|
||||||
{
|
|
||||||
StringRef macroName;
|
|
||||||
SourceLineInfo lineInfo;
|
|
||||||
StringRef capturedExpression;
|
|
||||||
ResultDisposition::Flags resultDisposition;
|
|
||||||
|
|
||||||
AssertionInfo() = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AssertionResultData
|
struct AssertionResultData
|
||||||
{
|
{
|
||||||
void negate( bool parenthesize );
|
AssertionResultData() = delete;
|
||||||
std::string const& reconstructExpression() const;
|
|
||||||
|
// !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;
|
ResultWas::OfType resultType = ResultWas::Unknown;
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
LazyExpression lazyExpression;
|
||||||
|
|
||||||
|
// deprecated:
|
||||||
bool negated = false;
|
bool negated = false;
|
||||||
bool parenthesized = false;
|
bool parenthesized = false;
|
||||||
|
void negate( bool parenthesize );
|
||||||
|
std::string reconstructExpression() const;
|
||||||
|
mutable DecomposedExpression const* decomposedExpression = nullptr;
|
||||||
|
mutable std::string reconstructedExpression;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AssertionResult {
|
class AssertionResult {
|
||||||
@ -81,7 +87,7 @@ namespace Catch {
|
|||||||
void discardDecomposedExpression() const;
|
void discardDecomposedExpression() const;
|
||||||
void expandDecomposedExpression() const;
|
void expandDecomposedExpression() const;
|
||||||
|
|
||||||
protected:
|
//protected:
|
||||||
AssertionInfo m_info;
|
AssertionInfo m_info;
|
||||||
AssertionResultData m_resultData;
|
AssertionResultData m_resultData;
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_assertionhandler.h"
|
||||||
#include "catch_result_builder.h"
|
#include "catch_result_builder.h"
|
||||||
#include "catch_message.h"
|
#include "catch_message.h"
|
||||||
#include "catch_interfaces_capture.h"
|
#include "catch_interfaces_capture.h"
|
||||||
@ -44,6 +45,9 @@
|
|||||||
#define INTERNAL_CATCH_REACT( resultBuilder ) \
|
#define INTERNAL_CATCH_REACT( resultBuilder ) \
|
||||||
if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
|
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_TRY try
|
||||||
#define INTERNAL_CATCH_CATCH( capturer, disposition ) catch(...) { capturer.useActiveException( disposition ); }
|
#define INTERNAL_CATCH_CATCH( capturer, disposition ) catch(...) { capturer.useActiveException( disposition ); }
|
||||||
@ -53,13 +57,13 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \
|
||||||
INTERNAL_CATCH_TRY { \
|
INTERNAL_CATCH_TRY { \
|
||||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||||
( __catchResult <= __VA_ARGS__ ).endExpression(); \
|
catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \
|
||||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||||
} INTERNAL_CATCH_CATCH( __catchResult, resultDisposition ) \
|
} INTERNAL_CATCH_CATCH( catchAssertionHandler, resultDisposition ) \
|
||||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
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
|
} 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 &&.
|
// 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 ),
|
infoMessages( _infoMessages ),
|
||||||
totals( _totals )
|
totals( _totals )
|
||||||
{
|
{
|
||||||
|
assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;
|
||||||
|
|
||||||
if( assertionResult.hasMessage() ) {
|
if( assertionResult.hasMessage() ) {
|
||||||
// Copy message into messages list.
|
// Copy message into messages list.
|
||||||
// !TBD This should have been done earlier, somewhere
|
// !TBD This should have been done earlier, somewhere
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "catch_interfaces_capture.h"
|
#include "catch_interfaces_capture.h"
|
||||||
#include "catch_interfaces_registry_hub.h"
|
#include "catch_interfaces_registry_hub.h"
|
||||||
#include "catch_matchers_string.h"
|
#include "catch_matchers_string.h"
|
||||||
#include "catch_wildcard_pattern.hpp"
|
|
||||||
#include "catch_debugger.h"
|
#include "catch_debugger.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -34,7 +33,8 @@ namespace Catch {
|
|||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
StringRef capturedExpression,
|
StringRef capturedExpression,
|
||||||
ResultDisposition::Flags resultDisposition )
|
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 );
|
getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo );
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
||||||
|
|
||||||
#include "catch_result_type.h"
|
|
||||||
#include "catch_assertionresult.h"
|
#include "catch_assertionresult.h"
|
||||||
|
#include "catch_decomposer.h"
|
||||||
|
|
||||||
|
#include "catch_result_type.h"
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
#include "catch_matchers.hpp"
|
#include "catch_matchers.hpp"
|
||||||
|
|
||||||
@ -17,8 +19,6 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
struct TestFailureException{};
|
|
||||||
|
|
||||||
template<typename T> class ExpressionLhs;
|
template<typename T> class ExpressionLhs;
|
||||||
|
|
||||||
struct CopyableStream {
|
struct CopyableStream {
|
||||||
|
@ -192,7 +192,7 @@ namespace Catch {
|
|||||||
void RunContext::handleFatalErrorCondition(std::string const & message) {
|
void RunContext::handleFatalErrorCondition(std::string const & message) {
|
||||||
// Don't rebuild the result -- the stringification itself can cause more fatal errors
|
// Don't rebuild the result -- the stringification itself can cause more fatal errors
|
||||||
// Instead, fake a result data.
|
// Instead, fake a result data.
|
||||||
AssertionResultData tempResult;
|
AssertionResultData tempResult( ResultWas::Unknown, { false } );
|
||||||
tempResult.resultType = ResultWas::FatalErrorCondition;
|
tempResult.resultType = ResultWas::FatalErrorCondition;
|
||||||
tempResult.message = message;
|
tempResult.message = message;
|
||||||
AssertionResult result(m_lastAssertionInfo, tempResult);
|
AssertionResult result(m_lastAssertionInfo, tempResult);
|
||||||
|
@ -193,14 +193,14 @@ namespace Catch {
|
|||||||
|
|
||||||
bool assertionEnded(AssertionStats const& assertionStats) override {
|
bool assertionEnded(AssertionStats const& assertionStats) override {
|
||||||
assert(!m_sectionStack.empty());
|
assert(!m_sectionStack.empty());
|
||||||
SectionNode& sectionNode = *m_sectionStack.back();
|
|
||||||
sectionNode.assertions.push_back(assertionStats);
|
|
||||||
// AssertionResult holds a pointer to a temporary DecomposedExpression,
|
// AssertionResult holds a pointer to a temporary DecomposedExpression,
|
||||||
// which getExpandedExpression() calls to build the expression string.
|
// which getExpandedExpression() calls to build the expression string.
|
||||||
// Our section stack copy of the assertionResult will likely outlive the
|
// Our section stack copy of the assertionResult will likely outlive the
|
||||||
// temporary, so it must be expanded or discarded now to avoid calling
|
// temporary, so it must be expanded or discarded now to avoid calling
|
||||||
// a destroyed object later.
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
void sectionEnded(SectionStats const& sectionStats) override {
|
void sectionEnded(SectionStats const& sectionStats) override {
|
||||||
|
Loading…
Reference in New Issue
Block a user