More Single Evaluation work

This commit is contained in:
Phil Nash 2011-03-10 14:09:32 +00:00
parent b708789ee9
commit e0e74774e2
6 changed files with 196 additions and 193 deletions

View File

@ -20,7 +20,7 @@ TEST_CASE( "selftest/main", "Runs all Catch self tests and checks their results"
runner.runMatching( "./succeeding/*" ); runner.runMatching( "./succeeding/*" );
INFO( runner.getOutput() ); INFO( runner.getOutput() );
CHECK( runner.getSuccessCount() == 212 ); CHECK( runner.getSuccessCount() == 213 );
CHECK( runner.getFailureCount() == 0 ); CHECK( runner.getFailureCount() == 0 );
runner.runMatching( "./failing/*" ); runner.runMatching( "./failing/*" );

View File

@ -24,7 +24,12 @@ namespace Catch
} }
} }
TEST_CASE( "./succeeding/Tricky/std::pair", "Parsing a std::pair" ) ///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"./succeeding/Tricky/std::pair",
"Parsing a std::pair"
)
{ {
std::pair<int, int> aNicePair( 1, 2 ); std::pair<int, int> aNicePair( 1, 2 );
@ -33,7 +38,12 @@ TEST_CASE( "./succeeding/Tricky/std::pair", "Parsing a std::pair" )
} }
TEST_CASE( "./succeeding/Tricky/complex lhs", "Where the LHS is not a simple value" ) ///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"./inprogress/succeeding/Tricky/complex lhs",
"Where the LHS is not a simple value"
)
{ {
int a = 1; int a = 1;
int b = 2; int b = 2;
@ -45,13 +55,18 @@ TEST_CASE( "./succeeding/Tricky/complex lhs", "Where the LHS is not a simple val
struct Opaque struct Opaque
{ {
int val; int val;
bool operator ==( const Opaque& o ) bool operator ==( const Opaque& o ) const
{ {
return val == o.val; return val == o.val;
} }
}; };
TEST_CASE( "./failing/Tricky/non streamable type", "A failing expression with a non streamable type is still captured" ) ///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"./failing/Tricky/non streamable type",
"A failing expression with a non streamable type is still captured"
)
{ {
Opaque o1, o2; Opaque o1, o2;
@ -61,3 +76,28 @@ TEST_CASE( "./failing/Tricky/non streamable type", "A failing expression with a
CHECK( &o1 == &o2 ); CHECK( &o1 == &o2 );
CHECK( o1 == o2 ); CHECK( o1 == o2 );
} }
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"./failing/string literals",
"string literals of different sizes can be compared"
)
{
REQUIRE( std::string( "first" ) == "second" );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"./succeeding/side-effects",
"An expression with side-effects should only be evaluated once"
)
{
int i = 7;
REQUIRE( i++ == 7 );
REQUIRE( i++ == 8 );
}

View File

@ -145,6 +145,15 @@ inline std::string toString
oss << value; oss << value;
return oss.str(); return oss.str();
} }
///////////////////////////////////////////////////////////////////////////////
inline std::string toString
(
bool value
)
{
return value ? "true" : "false";
}
class TestFailureException class TestFailureException
{ {
@ -169,9 +178,10 @@ public:
bool isNot, bool isNot,
const char* filename, const char* filename,
std::size_t line, std::size_t line,
const char* macroName const char* macroName,
const char* message = ""
) )
: ResultInfo( expr, ResultWas::Unknown, isNot, filename, line, macroName ) : ResultInfo( expr, ResultWas::Unknown, isNot, filename, line, macroName, message )
{ {
} }
@ -216,127 +226,119 @@ private:
friend class Expression; friend class Expression;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
void setLhs MutableResultInfo& captureBoolExpression
( (
const std::string& lhs bool result
) )
{ {
m_lhs = lhs; m_lhs = toString( result );
} m_op = m_isNot ? "!" : "";
setResultType( result ? ResultWas::Ok : ResultWas::ExpressionFailed );
///////////////////////////////////////////////////////////////////////////
MutableResultInfo& setRhs
(
const std::string& op,
const std::string& rhs
)
{
m_op = op;
m_rhs = rhs;
return *this; return *this;
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template<Operator Op, typename T1, typename T2> template<Operator Op, typename T1, typename T2>
MutableResultInfo& setExpressionComponents MutableResultInfo& captureExpression
( (
const T1& lhs, const T1& lhs,
const T2& rhs const T2& rhs
) )
{ {
setResultType( compare<Op>( lhs, rhs ) ? ResultWas::Ok : ResultWas::ExpressionFailed ); setResultType( compare<Op>( lhs, rhs ) ? ResultWas::Ok : ResultWas::ExpressionFailed );
m_lhs = toString( lhs );
m_rhs = toString( rhs ); m_rhs = toString( rhs );
m_op = OperatorTraits<Op>::getName(); m_op = OperatorTraits<Op>::getName();
return *this; return *this;
} }
}; };
template<typename T> template<typename T>
class Expression class Expression
{
public:
///////////////////////////////////////////////////////////////////////////
Expression
(
MutableResultInfo& result,
const T& lhs
)
: m_result( result ),
m_lhs( lhs )
{ {
public: }
///////////////////////////////////////////////////////////////////////////
Expression ///////////////////////////////////////////////////////////////////////////
( template<typename RhsT>
MutableResultInfo& result, MutableResultInfo& operator ==
const T& lhs (
) const RhsT& rhs
: m_result( result ), )
m_lhs( lhs ) {
{ return m_result.captureExpression<IsEqualTo>( m_lhs, rhs );
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template<typename RhsT> template<typename RhsT>
MutableResultInfo& operator == MutableResultInfo& operator !=
( (
const RhsT& rhs const RhsT& rhs
) )
{ {
return m_result.setExpressionComponents<IsEqualTo>( m_lhs, rhs ); return m_result.captureExpression<IsNotEqualTo>( m_lhs, rhs );
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template<typename RhsT> template<typename RhsT>
MutableResultInfo& operator != MutableResultInfo& operator <
( (
const RhsT& rhs const RhsT& rhs
) )
{ {
return m_result.setExpressionComponents<IsEqualTo>( m_lhs, rhs ); return m_result.captureExpression<IsLessThan>( m_lhs, rhs );
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template<typename RhsT> template<typename RhsT>
MutableResultInfo& operator < MutableResultInfo& operator >
( (
const RhsT& rhs const RhsT& rhs
) )
{ {
return m_result.setExpressionComponents<IsLessThan>( m_lhs, rhs ); return m_result.captureExpression<IsGreaterThan>( m_lhs, rhs );
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template<typename RhsT> template<typename RhsT>
MutableResultInfo& operator > MutableResultInfo& operator <=
( (
const RhsT& rhs const RhsT& rhs
) )
{ {
return m_result.setExpressionComponents<IsGreaterThan>( m_lhs, rhs ); return m_result.captureExpression<IsLessThanOrEqualTo>( m_lhs, rhs );
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template<typename RhsT> template<typename RhsT>
MutableResultInfo& operator <= MutableResultInfo& operator >=
( (
const RhsT& rhs const RhsT& rhs
) )
{ {
return m_result.setExpressionComponents<IsLessThanOrEqualTo>( m_lhs, rhs ); return m_result.captureExpression<IsGreaterThanOrEqualTo>( m_lhs, rhs );
} }
///////////////////////////////////////////////////////////////////////////
template<typename RhsT>
MutableResultInfo& operator >=
(
const RhsT& rhs
)
{
return m_result.setExpressionComponents<IsGreaterThanOrEqualTo>( m_lhs, rhs );
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
operator MutableResultInfo& operator MutableResultInfo&
() ()
{ {
return m_result; return m_result.captureBoolExpression( m_lhs );
} }
private: private:
MutableResultInfo& m_result; MutableResultInfo& m_result;
const T& m_lhs; const T& m_lhs;
}; };
class ResultBuilder class ResultBuilder
{ {
@ -345,11 +347,11 @@ public:
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
ResultBuilder ResultBuilder
( (
const char* expr,
bool isNot,
const char* filename, const char* filename,
std::size_t line, std::size_t line,
const char* macroName const char* macroName,
const char* expr = "",
bool isNot = false
) )
: m_result( expr, isNot, filename, line, macroName ) : m_result( expr, isNot, filename, line, macroName )
{} {}
@ -363,90 +365,41 @@ public:
{ {
Expression<T> expr( m_result, operand ); Expression<T> expr( m_result, operand );
m_result.setLhs( toString( operand ) );
return expr; return expr;
} }
/*
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template<typename T> template<typename T>
ResultBuilder& operator->* ResultBuilder& operator <<
( (
const T & operand const T & value
) )
{ {
m_result.setLhs( toString( operand ) ); m_messageStream << value;
return *this; return *this;
} }
*/
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template<typename RhsT> ResultBuilder& setResultType
MutableResultInfo& operator ==
( (
const RhsT& rhs ResultWas::OfType resultType
) )
{ {
return m_result.setRhs( "==", toString( rhs ) ); m_result.setResultType( resultType );
} return *this;
}
///////////////////////////////////////////////////////////////////////////
template<typename RhsT>
MutableResultInfo& operator !=
(
const RhsT& rhs
)
{
return m_result.setRhs( "!=", toString( rhs ) );
}
///////////////////////////////////////////////////////////////////////////
template<typename RhsT>
MutableResultInfo& operator <
(
const RhsT& rhs
)
{
return m_result.setRhs( "<", toString( rhs ) );
}
///////////////////////////////////////////////////////////////////////////
template<typename RhsT>
MutableResultInfo& operator >
(
const RhsT& rhs
)
{
return m_result.setRhs( ">", toString( rhs ) );
}
///////////////////////////////////////////////////////////////////////////
template<typename RhsT>
MutableResultInfo& operator <=
(
const RhsT& rhs
)
{
return m_result.setRhs( "<=", toString( rhs ) );
}
///////////////////////////////////////////////////////////////////////////
template<typename RhsT>
MutableResultInfo& operator >=
(
const RhsT& rhs
)
{
return m_result.setRhs( ">=", toString( rhs ) );
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
operator MutableResultInfo& operator MutableResultInfo&
() ()
{ {
m_result.setMessage( m_messageStream.str() );
return m_result; return m_result;
} }
private: private:
MutableResultInfo m_result; MutableResultInfo m_result;
std::ostringstream m_messageStream;
}; };
@ -565,7 +518,7 @@ inline bool isTrue
} // end namespace Catch } // end namespace Catch
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ACCEPT_RESULT( result, stopOnFailure ) \ #define INTERNAL_CATCH_ACCEPT_RESULT2( result, stopOnFailure ) \
if( Catch::ResultAction::Value action = Catch::Hub::getResultCapture().acceptResult( result ) ) \ if( Catch::ResultAction::Value action = Catch::Hub::getResultCapture().acceptResult( result ) ) \
{ \ { \
if( action == Catch::ResultAction::DebugFailed ) BreakIntoDebugger(); \ if( action == Catch::ResultAction::DebugFailed ) BreakIntoDebugger(); \
@ -574,22 +527,22 @@ inline bool isTrue
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ) \
{ \ Catch::Hub::getResultCapture().acceptExpression( Catch::ResultBuilder( __FILE__, __LINE__, macroName, #expr, isNot )->*expr );
Catch::Hub::getResultCapture().acceptExpression( Catch::ResultBuilder( #expr, isNot, __FILE__, __LINE__, macroName )->*expr ); \
INTERNAL_CATCH_ACCEPT_RESULT( expr, stopOnFailure ) \
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_THROWS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \
Catch::Hub::getResultCapture().acceptExpression( Catch::ResultBuilder( #expr, false, __FILE__, __LINE__, macroName ) ); \
try \ try \
{ \ { \
using namespace Catch; \
expr; \ expr; \
INTERNAL_CATCH_ACCEPT_RESULT( nothrow, stopOnFailure ) \ ResultWas::OfType resultType = ( nothrow ) ? ResultWas::Ok : ResultWas::DidntThrowException; \
Hub::getResultCapture().acceptExpression( ResultBuilder( __FILE__, __LINE__, macroName, #expr ).setResultType( resultType ) ); \
} \ } \
catch( exceptionType ) \ catch( exceptionType ) \
{ \ { \
INTERNAL_CATCH_ACCEPT_RESULT( !(nothrow), stopOnFailure ) \ using namespace Catch; \
ResultWas::OfType resultType = ( nothrow ) ? ResultWas::ThrewException : ResultWas::Ok; \
Hub::getResultCapture().acceptExpression( ResultBuilder( __FILE__, __LINE__, macroName, #expr ).setResultType( resultType ) ); \
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -597,20 +550,18 @@ inline bool isTrue
INTERNAL_CATCH_THROWS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \ INTERNAL_CATCH_THROWS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \
catch( ... ) \ catch( ... ) \
{ \ { \
INTERNAL_CATCH_ACCEPT_RESULT( false, stopOnFailure ) \ using namespace Catch; \
ResultWas::OfType resultType = ( nothrow ) ? ResultWas::ThrewException : ResultWas::Ok; \
Hub::getResultCapture().acceptExpression( ResultBuilder( __FILE__, __LINE__, macroName, #expr ).setResultType( resultType ) ); \
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \
{ \ Catch::Hub::getResultCapture().acceptExpression( ( Catch::ResultBuilder( __FILE__, __LINE__, macroName ) << reason ).setResultType( resultType ) );
std::ostringstream INTERNAL_CATCH_UNIQUE_NAME( strm ); \
INTERNAL_CATCH_UNIQUE_NAME( strm ) << reason; \
Catch::Hub::getResultCapture().acceptExpression( Catch::MutableResultInfo( "", false, __FILE__, __LINE__, macroName ) ); \
Catch::Hub::getResultCapture().acceptMessage( INTERNAL_CATCH_UNIQUE_NAME( strm ).str() ); \
INTERNAL_CATCH_ACCEPT_RESULT( resultType, stopOnFailure ) \
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_SCOPED_INFO( log ) Catch::ScopedInfo INTERNAL_CATCH_UNIQUE_NAME( info ); INTERNAL_CATCH_UNIQUE_NAME( info ) << log #define INTERNAL_CATCH_SCOPED_INFO( log ) \
Catch::ScopedInfo INTERNAL_CATCH_UNIQUE_NAME( info ); \
INTERNAL_CATCH_UNIQUE_NAME( info ) << log
#endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED

View File

@ -56,7 +56,7 @@ namespace Catch
virtual ResultAction::Value acceptResult virtual ResultAction::Value acceptResult
( ResultWas::OfType result ( ResultWas::OfType result
) = 0; ) = 0;
virtual void acceptExpression virtual ResultAction::Value acceptExpression
( const MutableResultInfo& resultInfo ( const MutableResultInfo& resultInfo
) = 0; ) = 0;
virtual void acceptMessage virtual void acceptMessage

View File

@ -38,13 +38,15 @@ namespace Catch
bool isNot, bool isNot,
const char* filename, const char* filename,
std::size_t line, std::size_t line,
const char* macroName const char* macroName,
const char* message
) )
: m_macroName( macroName ), : m_macroName( macroName ),
m_filename( filename ), m_filename( filename ),
m_line( line ), m_line( line ),
m_expr( expr ), m_expr( expr ),
m_op( isNotExpression( expr ) ? "!" : "" ), m_op( isNotExpression( expr ) ? "!" : "" ),
m_message( message ),
m_result( result ), m_result( result ),
m_isNot( isNot ), m_isNot( isNot ),
m_expressionIncomplete( false ) m_expressionIncomplete( false )

View File

@ -458,12 +458,22 @@ namespace Catch
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void acceptExpression virtual ResultAction::Value acceptExpression
( (
const MutableResultInfo& resultInfo const MutableResultInfo& resultInfo
) )
{ {
m_currentResult = resultInfo; m_currentResult = resultInfo;
testEnded( m_currentResult );
bool ok = m_currentResult.ok();
m_currentResult = MutableResultInfo();
if( ok )
return ResultAction::None;
else if( shouldDebugBreak() )
return ResultAction::DebugFailed;
else
return ResultAction::Failed;
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////