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