2014-05-28 19:53:01 +02:00
|
|
|
/*
|
|
|
|
* Created by Phil on 28/5/2014.
|
|
|
|
* Copyright 2014 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_result_builder.h"
|
|
|
|
#include "catch_context.h"
|
|
|
|
#include "catch_interfaces_config.h"
|
|
|
|
#include "catch_interfaces_runner.h"
|
|
|
|
#include "catch_interfaces_capture.h"
|
|
|
|
#include "catch_interfaces_registry_hub.h"
|
2017-07-06 22:28:42 +02:00
|
|
|
#include "catch_matchers_string.h"
|
2015-07-13 16:03:04 +02:00
|
|
|
#include "catch_wildcard_pattern.hpp"
|
2017-08-07 01:09:54 +02:00
|
|
|
#include "catch_debugger.h"
|
2014-05-28 19:53:01 +02:00
|
|
|
|
2017-07-06 22:28:42 +02:00
|
|
|
#include <cassert>
|
|
|
|
|
2014-05-28 19:53:01 +02:00
|
|
|
namespace Catch {
|
|
|
|
|
2017-07-19 10:13:47 +02:00
|
|
|
CopyableStream::CopyableStream( CopyableStream const& other ) {
|
|
|
|
oss << other.oss.str();
|
|
|
|
}
|
|
|
|
CopyableStream& CopyableStream::operator=( CopyableStream const& other ) {
|
|
|
|
oss.str(std::string());
|
|
|
|
oss << other.oss.str();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-08-08 02:22:21 +02:00
|
|
|
ResultBuilder::ResultBuilder( StringRef macroName,
|
2014-05-28 19:53:01 +02:00
|
|
|
SourceLineInfo const& lineInfo,
|
2017-08-08 02:22:21 +02:00
|
|
|
StringRef capturedExpression,
|
2017-06-26 20:48:41 +02:00
|
|
|
ResultDisposition::Flags resultDisposition )
|
2017-08-08 02:08:07 +02:00
|
|
|
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }
|
2017-08-04 20:23:30 +02:00
|
|
|
{
|
|
|
|
getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo );
|
|
|
|
}
|
2014-05-29 08:50:19 +02:00
|
|
|
|
2017-03-29 21:12:06 +02:00
|
|
|
ResultBuilder::~ResultBuilder() {
|
|
|
|
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
|
|
|
if ( m_guardException ) {
|
2017-06-26 21:30:23 +02:00
|
|
|
stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
|
2017-04-03 11:36:55 +02:00
|
|
|
captureResult( ResultWas::ThrewException );
|
|
|
|
getCurrentContext().getResultCapture()->exceptionEarlyReported();
|
2017-03-29 21:12:06 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-05-29 08:50:19 +02:00
|
|
|
ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
|
|
|
|
m_data.resultType = result;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
ResultBuilder& ResultBuilder::setResultType( bool result ) {
|
|
|
|
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-01-09 13:23:10 +01:00
|
|
|
void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
|
2017-06-26 21:30:23 +02:00
|
|
|
// Flip bool results if FalseTest flag is set
|
|
|
|
if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
|
|
|
|
m_data.negate( expr.isBinaryExpression() );
|
|
|
|
}
|
|
|
|
|
|
|
|
getResultCapture().assertionRun();
|
|
|
|
|
|
|
|
if(getCurrentContext().getConfig()->includeSuccessfulResults()
|
|
|
|
|| m_data.resultType != ResultWas::Ok) {
|
|
|
|
AssertionResult result = build( expr );
|
|
|
|
handleResult( result );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
getResultCapture().assertionPassed();
|
2014-05-29 08:50:19 +02:00
|
|
|
}
|
2014-05-28 19:53:01 +02:00
|
|
|
|
|
|
|
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
|
|
|
|
m_assertionInfo.resultDisposition = resultDisposition;
|
2017-06-26 21:30:23 +02:00
|
|
|
stream().oss << Catch::translateActiveException();
|
2014-05-28 19:53:01 +02:00
|
|
|
captureResult( ResultWas::ThrewException );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
|
2014-05-29 08:50:19 +02:00
|
|
|
setResultType( resultType );
|
2014-05-28 19:53:01 +02:00
|
|
|
captureExpression();
|
|
|
|
}
|
2017-07-29 08:43:32 +02:00
|
|
|
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
2015-07-13 07:34:41 +02:00
|
|
|
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
|
2015-07-16 00:02:25 +02:00
|
|
|
if( expectedMessage.empty() )
|
2017-02-08 15:17:17 +01:00
|
|
|
captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
|
2015-07-16 00:02:25 +02:00
|
|
|
else
|
|
|
|
captureExpectedException( Matchers::Equals( expectedMessage ) );
|
|
|
|
}
|
|
|
|
|
2017-02-08 15:17:17 +01:00
|
|
|
|
|
|
|
void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
|
2015-11-04 19:01:28 +01:00
|
|
|
|
2017-01-09 13:23:10 +01:00
|
|
|
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
|
2015-07-13 07:34:41 +02:00
|
|
|
AssertionResultData data = m_data;
|
|
|
|
data.resultType = ResultWas::Ok;
|
2017-08-08 02:22:21 +02:00
|
|
|
data.reconstructedExpression = m_assertionInfo.capturedExpression.c_str();
|
2015-11-04 19:01:28 +01:00
|
|
|
|
2015-07-16 00:02:25 +02:00
|
|
|
std::string actualMessage = Catch::translateActiveException();
|
|
|
|
if( !matcher.match( actualMessage ) ) {
|
|
|
|
data.resultType = ResultWas::ExpressionFailed;
|
2017-07-25 15:45:50 +02:00
|
|
|
data.reconstructedExpression = std::move(actualMessage);
|
2015-07-13 07:34:41 +02:00
|
|
|
}
|
|
|
|
AssertionResult result( m_assertionInfo, data );
|
|
|
|
handleResult( result );
|
|
|
|
}
|
2017-07-28 21:34:34 +02:00
|
|
|
#endif // CATCH_CONFIG_DISABLE_MATCHERS
|
2014-05-28 19:53:01 +02:00
|
|
|
void ResultBuilder::captureExpression() {
|
2014-05-29 08:50:19 +02:00
|
|
|
AssertionResult result = build();
|
2015-07-13 07:34:41 +02:00
|
|
|
handleResult( result );
|
|
|
|
}
|
2017-01-09 13:23:10 +01:00
|
|
|
|
2015-07-13 07:34:41 +02:00
|
|
|
void ResultBuilder::handleResult( AssertionResult const& result )
|
|
|
|
{
|
2014-05-28 19:53:01 +02:00
|
|
|
getResultCapture().assertionEnded( result );
|
2015-11-04 19:01:28 +01:00
|
|
|
|
2014-05-28 19:53:01 +02:00
|
|
|
if( !result.isOk() ) {
|
|
|
|
if( getCurrentContext().getConfig()->shouldDebugBreak() )
|
|
|
|
m_shouldDebugBreak = true;
|
2015-04-29 12:54:47 +02:00
|
|
|
if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
|
2014-05-28 19:53:01 +02:00
|
|
|
m_shouldThrow = true;
|
|
|
|
}
|
|
|
|
}
|
2017-01-09 13:23:10 +01:00
|
|
|
|
2014-05-28 19:53:01 +02:00
|
|
|
void ResultBuilder::react() {
|
2017-02-14 15:35:12 +01:00
|
|
|
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
|
|
|
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 throw statement
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
CATCH_BREAK_INTO_DEBUGGER();
|
|
|
|
}
|
|
|
|
#endif
|
2014-05-28 19:53:01 +02:00
|
|
|
if( m_shouldThrow )
|
|
|
|
throw Catch::TestFailureException();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
|
|
|
|
bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
|
|
|
|
|
2014-05-29 08:50:19 +02:00
|
|
|
AssertionResult ResultBuilder::build() const
|
|
|
|
{
|
2017-01-09 13:23:10 +01:00
|
|
|
return build( *this );
|
|
|
|
}
|
2014-05-29 08:50:19 +02:00
|
|
|
|
2017-01-09 13:23:10 +01:00
|
|
|
// CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
|
|
|
|
// a temporary DecomposedExpression, which in turn holds references to
|
|
|
|
// operands, possibly temporary as well.
|
|
|
|
// It should immediately be passed to handleResult; if the expression
|
|
|
|
// needs to be reported, its string expansion must be composed before
|
|
|
|
// the temporaries are destroyed.
|
2017-06-26 21:30:23 +02:00
|
|
|
AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const {
|
2017-01-09 13:23:10 +01:00
|
|
|
assert( m_data.resultType != ResultWas::Unknown );
|
2014-05-29 08:50:19 +02:00
|
|
|
AssertionResultData data = m_data;
|
|
|
|
|
2017-06-26 21:30:23 +02:00
|
|
|
if(m_usedStream)
|
2017-08-02 00:04:26 +02:00
|
|
|
data.message = s_stream().oss.str();
|
2017-01-09 13:23:10 +01:00
|
|
|
data.decomposedExpression = &expr; // for lazy reconstruction
|
2014-05-29 08:50:19 +02:00
|
|
|
return AssertionResult( m_assertionInfo, data );
|
|
|
|
}
|
2017-01-09 13:23:10 +01:00
|
|
|
|
2017-02-06 23:37:23 +01:00
|
|
|
void ResultBuilder::reconstructExpression( std::string& dest ) const {
|
2017-08-08 02:22:21 +02:00
|
|
|
dest = m_assertionInfo.capturedExpression.c_str();
|
2014-05-29 08:50:19 +02:00
|
|
|
}
|
|
|
|
|
2017-03-29 21:12:06 +02:00
|
|
|
void ResultBuilder::setExceptionGuard() {
|
|
|
|
m_guardException = true;
|
|
|
|
}
|
|
|
|
void ResultBuilder::unsetExceptionGuard() {
|
|
|
|
m_guardException = false;
|
|
|
|
}
|
|
|
|
|
2017-06-26 21:30:23 +02:00
|
|
|
CopyableStream& ResultBuilder::stream() {
|
|
|
|
if( !m_usedStream ) {
|
|
|
|
m_usedStream = true;
|
|
|
|
s_stream().oss.str("");
|
|
|
|
}
|
|
|
|
return s_stream();
|
|
|
|
}
|
|
|
|
|
|
|
|
CopyableStream& ResultBuilder::s_stream() {
|
2017-07-25 22:13:14 +02:00
|
|
|
static CopyableStream s;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-28 19:53:01 +02:00
|
|
|
} // end namespace Catch
|