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 ///////////////////////////////////////////////////////////////////////////////
22 // In the event of a failure works out if the debugger needs to be invoked
23 // and/or an exception thrown and takes appropriate action.
24 // This needs to be done as a macro so the debugger will stop in the user
25 // source code rather than in Catch library code
26 #define INTERNAL_CATCH_REACT( resultBuilder ) \
27     if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
28     resultBuilder.react();
29 
30 
31 ///////////////////////////////////////////////////////////////////////////////
32 #define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
33     do { \
34         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
35         try { \
36             CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
37             ( __catchResult <= expr ).endExpression(); \
38         } \
39         catch( ... ) { \
40             __catchResult.useActiveException( resultDisposition ); \
41         } \
42         INTERNAL_CATCH_REACT( __catchResult ) \
43     } 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
44     // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
45 
46 ///////////////////////////////////////////////////////////////////////////////
47 #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
48     INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
49     if( Catch::getResultCapture().getLastResult()->succeeded() )
50 
51 ///////////////////////////////////////////////////////////////////////////////
52 #define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
53     INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
54     if( !Catch::getResultCapture().getLastResult()->succeeded() )
55 
56 ///////////////////////////////////////////////////////////////////////////////
57 #define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
58     do { \
59         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
60         try { \
61             static_cast<void>(expr); \
62             __catchResult.captureResult( Catch::ResultWas::Ok ); \
63         } \
64         catch( ... ) { \
65             __catchResult.useActiveException( resultDisposition ); \
66         } \
67         INTERNAL_CATCH_REACT( __catchResult ) \
68     } while( Catch::alwaysFalse() )
69 
70 ///////////////////////////////////////////////////////////////////////////////
71 #define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \
72     do { \
73         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
74         if( __catchResult.allowThrows() ) \
75             try { \
76                 static_cast<void>(expr); \
77                 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
78             } \
79             catch( ... ) { \
80                 __catchResult.captureExpectedException( matcher ); \
81             } \
82         else \
83             __catchResult.captureResult( Catch::ResultWas::Ok ); \
84         INTERNAL_CATCH_REACT( __catchResult ) \
85     } while( Catch::alwaysFalse() )
86 
87 ///////////////////////////////////////////////////////////////////////////////
88 #define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
89     do { \
90         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
91         if( __catchResult.allowThrows() ) \
92             try { \
93                 static_cast<void>(expr); \
94                 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
95             } \
96             catch( exceptionType ) { \
97                 __catchResult.captureResult( Catch::ResultWas::Ok ); \
98             } \
99             catch( ... ) { \
100                 __catchResult.useActiveException( resultDisposition ); \
101             } \
102         else \
103             __catchResult.captureResult( Catch::ResultWas::Ok ); \
104         INTERNAL_CATCH_REACT( __catchResult ) \
105     } while( Catch::alwaysFalse() )
106 
107 
108 ///////////////////////////////////////////////////////////////////////////////
109 #ifdef CATCH_CONFIG_VARIADIC_MACROS
110     #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
111         do { \
112             Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
113             __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
114             __catchResult.captureResult( messageType ); \
115             INTERNAL_CATCH_REACT( __catchResult ) \
116         } while( Catch::alwaysFalse() )
117 #else
118     #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
119         do { \
120             Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
121             __catchResult << log + ::Catch::StreamEndStop(); \
122             __catchResult.captureResult( messageType ); \
123             INTERNAL_CATCH_REACT( __catchResult ) \
124         } while( Catch::alwaysFalse() )
125 #endif
126 
127 ///////////////////////////////////////////////////////////////////////////////
128 #define INTERNAL_CATCH_INFO( log, macroName ) \
129     Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
130 
131 ///////////////////////////////////////////////////////////////////////////////
132 #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
133     do { \
134         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
135         try { \
136             __catchResult.captureMatch( arg, matcher, #matcher ); \
137         } catch( ... ) { \
138             __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
139         } \
140         INTERNAL_CATCH_REACT( __catchResult ) \
141     } while( Catch::alwaysFalse() )
142 
143 #endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
144