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