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