1 /* 2 * Created by Phil on 28/5/2014. 3 * Copyright 2014 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 #ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED 9 #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED 10 11 #include "catch_result_builder.h" 12 #include "catch_context.h" 13 #include "catch_interfaces_config.h" 14 #include "catch_interfaces_runner.h" 15 #include "catch_interfaces_capture.h" 16 #include "catch_interfaces_registry_hub.h" 17 #include "catch_wildcard_pattern.hpp" 18 19 #include <cassert> 20 21 namespace Catch { 22 ResultBuilder(char const * macroName,SourceLineInfo const & lineInfo,char const * capturedExpression,ResultDisposition::Flags resultDisposition,char const * secondArg)23 ResultBuilder::ResultBuilder( char const* macroName, 24 SourceLineInfo const& lineInfo, 25 char const* capturedExpression, 26 ResultDisposition::Flags resultDisposition, 27 char const* secondArg ) 28 : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ), 29 m_shouldDebugBreak( false ), 30 m_shouldThrow( false ), 31 m_guardException( false ), 32 m_usedStream( false ) 33 {} 34 ~ResultBuilder()35 ResultBuilder::~ResultBuilder() { 36 #if defined(CATCH_CONFIG_FAST_COMPILE) 37 if ( m_guardException ) { 38 stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; 39 captureResult( ResultWas::ThrewException ); 40 getCurrentContext().getResultCapture()->exceptionEarlyReported(); 41 } 42 #endif 43 } 44 setResultType(ResultWas::OfType result)45 ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { 46 m_data.resultType = result; 47 return *this; 48 } setResultType(bool result)49 ResultBuilder& ResultBuilder::setResultType( bool result ) { 50 m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; 51 return *this; 52 } 53 endExpression(DecomposedExpression const & expr)54 void ResultBuilder::endExpression( DecomposedExpression const& expr ) { 55 // Flip bool results if FalseTest flag is set 56 if( isFalseTest( m_assertionInfo.resultDisposition ) ) { 57 m_data.negate( expr.isBinaryExpression() ); 58 } 59 60 getResultCapture().assertionRun(); 61 62 if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok) 63 { 64 AssertionResult result = build( expr ); 65 handleResult( result ); 66 } 67 else 68 getResultCapture().assertionPassed(); 69 } 70 useActiveException(ResultDisposition::Flags resultDisposition)71 void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { 72 m_assertionInfo.resultDisposition = resultDisposition; 73 stream().oss << Catch::translateActiveException(); 74 captureResult( ResultWas::ThrewException ); 75 } 76 captureResult(ResultWas::OfType resultType)77 void ResultBuilder::captureResult( ResultWas::OfType resultType ) { 78 setResultType( resultType ); 79 captureExpression(); 80 } 81 captureExpectedException(std::string const & expectedMessage)82 void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { 83 if( expectedMessage.empty() ) 84 captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() ); 85 else 86 captureExpectedException( Matchers::Equals( expectedMessage ) ); 87 } 88 89 captureExpectedException(Matchers::Impl::MatcherBase<std::string> const & matcher)90 void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) { 91 92 assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); 93 AssertionResultData data = m_data; 94 data.resultType = ResultWas::Ok; 95 data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); 96 97 std::string actualMessage = Catch::translateActiveException(); 98 if( !matcher.match( actualMessage ) ) { 99 data.resultType = ResultWas::ExpressionFailed; 100 data.reconstructedExpression = actualMessage; 101 } 102 AssertionResult result( m_assertionInfo, data ); 103 handleResult( result ); 104 } 105 captureExpression()106 void ResultBuilder::captureExpression() { 107 AssertionResult result = build(); 108 handleResult( result ); 109 } 110 handleResult(AssertionResult const & result)111 void ResultBuilder::handleResult( AssertionResult const& result ) 112 { 113 getResultCapture().assertionEnded( result ); 114 115 if( !result.isOk() ) { 116 if( getCurrentContext().getConfig()->shouldDebugBreak() ) 117 m_shouldDebugBreak = true; 118 if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) 119 m_shouldThrow = true; 120 } 121 } 122 react()123 void ResultBuilder::react() { 124 #if defined(CATCH_CONFIG_FAST_COMPILE) 125 if (m_shouldDebugBreak) { 126 /////////////////////////////////////////////////////////////////// 127 // To inspect the state during test, you need to go one level up the callstack 128 // To go back to the test and change execution, jump over the throw statement 129 /////////////////////////////////////////////////////////////////// 130 CATCH_BREAK_INTO_DEBUGGER(); 131 } 132 #endif 133 if( m_shouldThrow ) 134 throw Catch::TestFailureException(); 135 } 136 shouldDebugBreak() const137 bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } allowThrows() const138 bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } 139 build() const140 AssertionResult ResultBuilder::build() const 141 { 142 return build( *this ); 143 } 144 145 // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, 146 // a temporary DecomposedExpression, which in turn holds references to 147 // operands, possibly temporary as well. 148 // It should immediately be passed to handleResult; if the expression 149 // needs to be reported, its string expansion must be composed before 150 // the temporaries are destroyed. build(DecomposedExpression const & expr) const151 AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const 152 { 153 assert( m_data.resultType != ResultWas::Unknown ); 154 AssertionResultData data = m_data; 155 156 if(m_usedStream) 157 data.message = m_stream().oss.str(); 158 data.decomposedExpression = &expr; // for lazy reconstruction 159 return AssertionResult( m_assertionInfo, data ); 160 } 161 reconstructExpression(std::string & dest) const162 void ResultBuilder::reconstructExpression( std::string& dest ) const { 163 dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); 164 } 165 setExceptionGuard()166 void ResultBuilder::setExceptionGuard() { 167 m_guardException = true; 168 } unsetExceptionGuard()169 void ResultBuilder::unsetExceptionGuard() { 170 m_guardException = false; 171 } 172 173 } // end namespace Catch 174 175 #endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED 176