1 /*
2  *  Created by Phil on 18/10/2010.
3  *  Copyright 2010 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_CAPTURE_HPP_INCLUDED
9 #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
10 
11 #include "catch_result_builder.h"
12 #include "catch_message.h"
13 #include "catch_interfaces_capture.h"
14 #include "catch_debugger.h"
15 #include "catch_common.h"
16 #include "catch_tostring.h"
17 #include "catch_interfaces_runner.h"
18 #include "catch_compiler_capabilities.h"
19 
20 
21 #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
22 # define CATCH_INTERNAL_STRINGIFY(expr) #expr
23 #else
24 # define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
25 #endif
26 
27 #if defined(CATCH_CONFIG_FAST_COMPILE)
28 ///////////////////////////////////////////////////////////////////////////////
29 // We can speedup compilation significantly by breaking into debugger lower in
30 // the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER
31 // macro in each assertion
32 #define INTERNAL_CATCH_REACT( resultBuilder ) \
33     resultBuilder.react();
34 
35 ///////////////////////////////////////////////////////////////////////////////
36 // Another way to speed-up compilation is to omit local try-catch for REQUIRE*
37 // macros.
38 // This can potentially cause false negative, if the test code catches
39 // the exception before it propagates back up to the runner.
40 #define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
41     do { \
42         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
43         __catchResult.setExceptionGuard(); \
44         CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
45         ( __catchResult <= expr ).endExpression(); \
46         CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
47         __catchResult.unsetExceptionGuard(); \
48         INTERNAL_CATCH_REACT( __catchResult ) \
49     } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
50 // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
51 
52 #define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
53     do { \
54         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
55         __catchResult.setExceptionGuard(); \
56         __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
57         __catchResult.unsetExceptionGuard(); \
58         INTERNAL_CATCH_REACT( __catchResult ) \
59     } while( Catch::alwaysFalse() )
60 
61 #else
62 ///////////////////////////////////////////////////////////////////////////////
63 // In the event of a failure works out if the debugger needs to be invoked
64 // and/or an exception thrown and takes appropriate action.
65 // This needs to be done as a macro so the debugger will stop in the user
66 // source code rather than in Catch library code
67 #define INTERNAL_CATCH_REACT( resultBuilder ) \
68     if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
69     resultBuilder.react();
70 #endif
71 
72 
73 ///////////////////////////////////////////////////////////////////////////////
74 #define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
75     do { \
76         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
77         try { \
78             CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
79             ( __catchResult <= expr ).endExpression(); \
80             CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
81         } \
82         catch( ... ) { \
83             __catchResult.useActiveException( resultDisposition ); \
84         } \
85         INTERNAL_CATCH_REACT( __catchResult ) \
86     } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
87     // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
88 
89 ///////////////////////////////////////////////////////////////////////////////
90 #define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
91     INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
92     if( Catch::getResultCapture().lastAssertionPassed() )
93 
94 ///////////////////////////////////////////////////////////////////////////////
95 #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
96     INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
97     if( !Catch::getResultCapture().lastAssertionPassed() )
98 
99 ///////////////////////////////////////////////////////////////////////////////
100 #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
101     do { \
102         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
103         try { \
104             static_cast<void>(expr); \
105             __catchResult.captureResult( Catch::ResultWas::Ok ); \
106         } \
107         catch( ... ) { \
108             __catchResult.useActiveException( resultDisposition ); \
109         } \
110         INTERNAL_CATCH_REACT( __catchResult ) \
111     } while( Catch::alwaysFalse() )
112 
113 ///////////////////////////////////////////////////////////////////////////////
114 #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
115     do { \
116         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \
117         if( __catchResult.allowThrows() ) \
118             try { \
119                 static_cast<void>(expr); \
120                 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
121             } \
122             catch( ... ) { \
123                 __catchResult.captureExpectedException( matcher ); \
124             } \
125         else \
126             __catchResult.captureResult( Catch::ResultWas::Ok ); \
127         INTERNAL_CATCH_REACT( __catchResult ) \
128     } while( Catch::alwaysFalse() )
129 
130 ///////////////////////////////////////////////////////////////////////////////
131 #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
132     do { \
133         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
134         if( __catchResult.allowThrows() ) \
135             try { \
136                 static_cast<void>(expr); \
137                 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
138             } \
139             catch( exceptionType ) { \
140                 __catchResult.captureResult( Catch::ResultWas::Ok ); \
141             } \
142             catch( ... ) { \
143                 __catchResult.useActiveException( resultDisposition ); \
144             } \
145         else \
146             __catchResult.captureResult( Catch::ResultWas::Ok ); \
147         INTERNAL_CATCH_REACT( __catchResult ) \
148     } while( Catch::alwaysFalse() )
149 
150 
151 ///////////////////////////////////////////////////////////////////////////////
152 #ifdef CATCH_CONFIG_VARIADIC_MACROS
153     #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
154         do { \
155             Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
156             __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
157             __catchResult.captureResult( messageType ); \
158             INTERNAL_CATCH_REACT( __catchResult ) \
159         } while( Catch::alwaysFalse() )
160 #else
161     #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \
162         do { \
163             Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
164             __catchResult << log + ::Catch::StreamEndStop(); \
165             __catchResult.captureResult( messageType ); \
166             INTERNAL_CATCH_REACT( __catchResult ) \
167         } while( Catch::alwaysFalse() )
168 #endif
169 
170 ///////////////////////////////////////////////////////////////////////////////
171 #define INTERNAL_CATCH_INFO( macroName, log ) \
172     Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
173 
174 ///////////////////////////////////////////////////////////////////////////////
175 #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
176     do { \
177         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
178         try { \
179             __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
180         } catch( ... ) { \
181             __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
182         } \
183         INTERNAL_CATCH_REACT( __catchResult ) \
184     } while( Catch::alwaysFalse() )
185 
186 #endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
187