blob: dd3fd3aa1b1f88a0ca6181b3cb83952f2265d02d [file] [log] [blame]
Phil Nash89d1e6c2011-05-24 08:23:02 +01001/*
Phil Nash67ec8702012-09-26 18:38:26 +01002 * Generated: 2012-09-26 18:38:02.155253
Phil Nash4df051b2012-05-22 22:22:22 +01003 * ----------------------------------------------------------
Phil Nashaec1e5e2012-05-09 19:37:51 +01004 * This file has been merged from multiple headers. Please don't edit it directly
5 * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
Phil Nash89d1e6c2011-05-24 08:23:02 +01006 *
7 * Distributed under the Boost Software License, Version 1.0. (See accompanying
8 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Phil Nash89d1e6c2011-05-24 08:23:02 +01009 */
Phil Nashaec1e5e2012-05-09 19:37:51 +010010#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
11#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +010012
Phil Nash3b80af72012-08-09 07:47:30 +010013#define TWOBLUECUBES_CATCH_HPP_INCLUDED
Phil Nash0f9c5512012-06-02 23:12:42 +010014
Phil Nash5bc030d2012-08-16 18:48:50 +010015#ifdef __clang__
16#pragma clang diagnostic ignored "-Wno-global-constructors"
17
Phil Nasha695eb92012-08-13 07:46:10 +010018#pragma clang diagnostic push
19#pragma clang diagnostic ignored "-Wpadded"
Phil Nash5bc030d2012-08-16 18:48:50 +010020#endif
Phil Nasha695eb92012-08-13 07:46:10 +010021
Phil Nash3b80af72012-08-09 07:47:30 +010022// #included from: internal/catch_notimplemented_exception.h
23#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +010024
Phil Nash89d1e6c2011-05-24 08:23:02 +010025// #included from: catch_common.h
Phil Nash3b80af72012-08-09 07:47:30 +010026#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +010027
Phil Nash89d1e6c2011-05-24 08:23:02 +010028#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
29#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
30#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
31
32#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
33#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
34
35#ifdef __GNUC__
Phil Nasha695eb92012-08-13 07:46:10 +010036#define CATCH_ATTRIBUTE_NORETURN __attribute__ ((noreturn))
Phil Nash89d1e6c2011-05-24 08:23:02 +010037#else
Phil Nasha695eb92012-08-13 07:46:10 +010038#define CATCH_ATTRIBUTE_NORETURN
Phil Nash89d1e6c2011-05-24 08:23:02 +010039#endif
40
41#include <sstream>
42#include <stdexcept>
43#include <algorithm>
44
Phil Nash89d2a3f2012-05-16 15:09:17 +010045namespace Catch {
46
Phil Nashd31737f2012-05-09 19:04:00 +010047 class NonCopyable {
Phil Nash89d1e6c2011-05-24 08:23:02 +010048 NonCopyable( const NonCopyable& );
49 void operator = ( const NonCopyable& );
50 protected:
Phil Nashd31737f2012-05-09 19:04:00 +010051 NonCopyable() {}
Phil Nasha695eb92012-08-13 07:46:10 +010052 virtual ~NonCopyable();
Phil Nash89d1e6c2011-05-24 08:23:02 +010053 };
54
Phil Nash163088a2012-05-31 19:40:26 +010055 class SafeBool {
56 public:
57 typedef void (SafeBool::*type)() const;
58
59 static type makeSafe( bool value ) {
60 return value ? &SafeBool::trueValue : 0;
61 }
62 private:
63 void trueValue() const {}
64 };
65
Phil Nash89d1e6c2011-05-24 08:23:02 +010066 template<typename ContainerT>
Phil Nashd31737f2012-05-09 19:04:00 +010067 inline void deleteAll( ContainerT& container ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +010068 typename ContainerT::const_iterator it = container.begin();
69 typename ContainerT::const_iterator itEnd = container.end();
70 for(; it != itEnd; ++it )
71 {
72 delete *it;
73 }
74 }
75 template<typename AssociativeContainerT>
Phil Nashd31737f2012-05-09 19:04:00 +010076 inline void deleteAllValues( AssociativeContainerT& container ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +010077 typename AssociativeContainerT::const_iterator it = container.begin();
78 typename AssociativeContainerT::const_iterator itEnd = container.end();
79 for(; it != itEnd; ++it )
80 {
81 delete it->second;
82 }
83 }
84
85 template<typename ContainerT, typename Function>
Phil Nashd31737f2012-05-09 19:04:00 +010086 inline void forEach( ContainerT& container, Function function ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +010087 std::for_each( container.begin(), container.end(), function );
88 }
89
90 template<typename ContainerT, typename Function>
Phil Nashd31737f2012-05-09 19:04:00 +010091 inline void forEach( const ContainerT& container, Function function ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +010092 std::for_each( container.begin(), container.end(), function );
93 }
94
Phil Nash56d5c422012-08-23 20:08:50 +010095 inline bool startsWith( const std::string& s, const std::string& prefix ) {
96 return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
97 }
Phil Nash4c97fc52012-08-24 08:23:50 +010098 inline bool endsWith( const std::string& s, const std::string& suffix ) {
99 return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
100 }
101 inline bool contains( const std::string& s, const std::string& infix ) {
102 return s.find( infix ) != std::string::npos;
103 }
104
105 struct pluralise {
106 pluralise( std::size_t count, const std::string& label )
107 : m_count( count ),
108 m_label( label )
109 {}
110
111 friend std::ostream& operator << ( std::ostream& os, const pluralise& pluraliser ) {
112 os << pluraliser.m_count << " " << pluraliser.m_label;
113 if( pluraliser.m_count != 1 )
114 os << "s";
115 return os;
116 }
117
118 std::size_t m_count;
119 std::string m_label;
120 };
Phil Nash56d5c422012-08-23 20:08:50 +0100121
Phil Nash89d2a3f2012-05-16 15:09:17 +0100122 struct SourceLineInfo {
123
Phil Nashd31737f2012-05-09 19:04:00 +0100124 SourceLineInfo() : line( 0 ){}
Phil Nash62179662012-05-11 19:06:43 +0100125 SourceLineInfo( const std::string& _file, std::size_t _line )
126 : file( _file ),
127 line( _line )
Phil Nash6e0f58d2012-02-15 18:37:21 +0000128 {}
Phil Nashabf27162012-07-05 18:37:58 +0100129 SourceLineInfo( const std::string& _function, const std::string& _file, std::size_t _line )
130 : function( _function ),
131 file( _file ),
132 line( _line )
133 {}
Phil Nashd31737f2012-05-09 19:04:00 +0100134 SourceLineInfo( const SourceLineInfo& other )
135 : file( other.file ),
136 line( other.line )
137 {}
138 void swap( SourceLineInfo& other ){
139 file.swap( other.file );
140 std::swap( line, other.line );
141 }
Phil Nash6e0f58d2012-02-15 18:37:21 +0000142
Phil Nashabf27162012-07-05 18:37:58 +0100143 std::string function;
Phil Nash6e0f58d2012-02-15 18:37:21 +0000144 std::string file;
145 std::size_t line;
146 };
147
Phil Nashd31737f2012-05-09 19:04:00 +0100148 inline std::ostream& operator << ( std::ostream& os, const SourceLineInfo& info ) {
Phil Nash6e0f58d2012-02-15 18:37:21 +0000149#ifndef __GNUG__
150 os << info.file << "(" << info.line << "): ";
151#else
152 os << info.file << ":" << info.line << ": ";
153#endif
154 return os;
155 }
156
Phil Nasha695eb92012-08-13 07:46:10 +0100157 CATCH_ATTRIBUTE_NORETURN
158 inline void throwLogicError( const std::string& message, const SourceLineInfo& locationInfo ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100159 std::ostringstream oss;
Phil Nasha695eb92012-08-13 07:46:10 +0100160 oss << "Internal Catch error: '" << message << "' at: " << locationInfo;
Phil Nash89d1e6c2011-05-24 08:23:02 +0100161 throw std::logic_error( oss.str() );
162 }
163}
164
Phil Nasha695eb92012-08-13 07:46:10 +0100165#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
166#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100167
Phil Nash3b80af72012-08-09 07:47:30 +0100168#include <ostream>
169
170namespace Catch {
171
172 class NotImplementedException : public std::exception
173 {
174 public:
175 NotImplementedException( const SourceLineInfo& lineInfo );
176
177 virtual ~NotImplementedException() throw() {}
178
179 virtual const char* what() const throw();
180
181 private:
182 std::string m_what;
183 SourceLineInfo m_lineInfo;
184 };
185
186} // end namespace Catch
187
188///////////////////////////////////////////////////////////////////////////////
189#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
190
191// #included from: internal/catch_context.h
192#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
193
Phil Nasha70fbe32012-08-31 08:10:36 +0100194// #included from: catch_interfaces_generators.h
195#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
Phil Nash3b80af72012-08-09 07:47:30 +0100196
Phil Nasha70fbe32012-08-31 08:10:36 +0100197#include <string>
Phil Nashf7299fc2012-02-25 09:39:45 +0000198
Phil Nash89d2a3f2012-05-16 15:09:17 +0100199namespace Catch {
200
Phil Nasha70fbe32012-08-31 08:10:36 +0100201 struct IGeneratorInfo {
202 virtual ~IGeneratorInfo();
203 virtual bool moveNext() = 0;
204 virtual std::size_t getCurrentIndex() const = 0;
Phil Nashf7299fc2012-02-25 09:39:45 +0000205 };
206
Phil Nasha70fbe32012-08-31 08:10:36 +0100207 struct IGeneratorsForTest {
208 virtual ~IGeneratorsForTest();
Phil Nash89d2a3f2012-05-16 15:09:17 +0100209
Phil Nasha70fbe32012-08-31 08:10:36 +0100210 virtual IGeneratorInfo& getGeneratorInfo( const std::string& fileInfo, std::size_t size ) = 0;
211 virtual bool moveNext() = 0;
Phil Nashf7299fc2012-02-25 09:39:45 +0000212 };
Phil Nasha70fbe32012-08-31 08:10:36 +0100213
214 IGeneratorsForTest* createGeneratorsForTest();
215
216} // end namespace Catch
217
218#include <memory>
219#include <vector>
220#include <stdlib.h>
221
222namespace Catch {
223
224 class TestCaseInfo;
Phil Nash67ec8702012-09-26 18:38:26 +0100225 class Stream;
Phil Nasha70fbe32012-08-31 08:10:36 +0100226 struct IResultCapture;
227 struct IRunner;
228 struct IGeneratorsForTest;
229 struct IConfig;
230
231 class StreamBufBase : public std::streambuf {
232 public:
233 virtual ~StreamBufBase();
234 };
235
236 struct IContext
237 {
238 virtual ~IContext();
239
240 virtual IResultCapture& getResultCapture() = 0;
241 virtual IRunner& getRunner() = 0;
242 virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) = 0;
243 virtual bool advanceGeneratorsForCurrentTest() = 0;
244 virtual const IConfig* getConfig() const = 0;
245 };
246
247 struct IMutableContext : IContext
248 {
249 virtual ~IMutableContext();
250 virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
251 virtual void setRunner( IRunner* runner ) = 0;
252 virtual void setConfig( const IConfig* config ) = 0;
253 };
254
255 IContext& getCurrentContext();
256 IMutableContext& getCurrentMutableContext();
257 void cleanUpContext();
Phil Nash67ec8702012-09-26 18:38:26 +0100258 Stream createStream( const std::string& streamName );
Phil Nasha70fbe32012-08-31 08:10:36 +0100259
Phil Nashf7299fc2012-02-25 09:39:45 +0000260}
261
Phil Nasha70fbe32012-08-31 08:10:36 +0100262// #included from: internal/catch_test_registry.hpp
263#define TWOBLUECUBES_CATCH_REGISTRY_HPP_INCLUDED
264
265// #included from: catch_interfaces_testcase.h
266#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
267
Phil Nash49e6d532012-05-05 19:35:35 +0100268// #included from: catch_ptr.hpp
Phil Nash3b80af72012-08-09 07:47:30 +0100269#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
Phil Nash49e6d532012-05-05 19:35:35 +0100270
Phil Nash89d2a3f2012-05-16 15:09:17 +0100271namespace Catch {
272
Phil Nash49e6d532012-05-05 19:35:35 +0100273 // An intrusive reference counting smart pointer.
274 // T must implement addRef() and release() methods
275 // typically implementing the IShared interface
276 template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100277 class Ptr {
Phil Nash49e6d532012-05-05 19:35:35 +0100278 public:
279 Ptr() : m_p( NULL ){}
280 Ptr( T* p ) : m_p( p ){
Phil Nash61756972012-07-28 20:37:07 +0100281 if( m_p )
282 m_p->addRef();
Phil Nash49e6d532012-05-05 19:35:35 +0100283 }
284 Ptr( const Ptr& other ) : m_p( other.m_p ){
Phil Nash61756972012-07-28 20:37:07 +0100285 if( m_p )
286 m_p->addRef();
Phil Nash49e6d532012-05-05 19:35:35 +0100287 }
288 ~Ptr(){
289 if( m_p )
290 m_p->release();
291 }
292 Ptr& operator = ( T* p ){
293 Ptr temp( p );
294 swap( temp );
295 return *this;
296 }
Phil Nashdeb3ced2012-08-31 18:50:46 +0100297 Ptr& operator = ( const Ptr& other ){
Phil Nash49e6d532012-05-05 19:35:35 +0100298 Ptr temp( other );
299 swap( temp );
300 return *this;
301 }
302 void swap( Ptr& other ){
303 std::swap( m_p, other.m_p );
304 }
305
306 T* get(){
307 return m_p;
308 }
309 const T* get() const{
310 return m_p;
311 }
312
Phil Nash56d5c422012-08-23 20:08:50 +0100313 T& operator*() const {
Phil Nash49e6d532012-05-05 19:35:35 +0100314 return *m_p;
315 }
316
Phil Nash56d5c422012-08-23 20:08:50 +0100317 T* operator->() const {
Phil Nash49e6d532012-05-05 19:35:35 +0100318 return m_p;
319 }
Phil Nash56d5c422012-08-23 20:08:50 +0100320
Phil Nash61756972012-07-28 20:37:07 +0100321 bool operator !() const {
322 return m_p == NULL;
323 }
Phil Nash49e6d532012-05-05 19:35:35 +0100324
325 private:
326 T* m_p;
327 };
328
329 struct IShared : NonCopyable {
Phil Nasha695eb92012-08-13 07:46:10 +0100330 virtual ~IShared();
Phil Nash49e6d532012-05-05 19:35:35 +0100331 virtual void addRef() = 0;
332 virtual void release() = 0;
333 };
334
335 template<typename T>
336 struct SharedImpl : T {
337
338 SharedImpl() : m_rc( 0 ){}
339
340 virtual void addRef(){
341 ++m_rc;
342 }
343 virtual void release(){
344 if( --m_rc == 0 )
345 delete this;
346 }
347
348 int m_rc;
349 };
350
351} // end namespace Catch
352
Phil Nash0f9c5512012-06-02 23:12:42 +0100353#include <vector>
354
355namespace Catch {
Phil Nash56d5c422012-08-23 20:08:50 +0100356
357 class TestCaseFilters;
358
Phil Nash5bc030d2012-08-16 18:48:50 +0100359 struct ITestCase : IShared {
Phil Nash0f9c5512012-06-02 23:12:42 +0100360 virtual void invoke () const = 0;
Phil Nash5bc030d2012-08-16 18:48:50 +0100361 protected:
362 virtual ~ITestCase();
Phil Nash0f9c5512012-06-02 23:12:42 +0100363 };
364
365 class TestCaseInfo;
366
367 struct ITestCaseRegistry {
Phil Nasha695eb92012-08-13 07:46:10 +0100368 virtual ~ITestCaseRegistry();
Phil Nash0f9c5512012-06-02 23:12:42 +0100369 virtual const std::vector<TestCaseInfo>& getAllTests() const = 0;
Phil Nash3b80af72012-08-09 07:47:30 +0100370 virtual std::vector<TestCaseInfo> getMatchingTestCases( const std::string& rawTestSpec ) const = 0;
Phil Nash0f9c5512012-06-02 23:12:42 +0100371 };
372}
373
Phil Nash89d2a3f2012-05-16 15:09:17 +0100374namespace Catch {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100375
376template<typename C>
Phil Nash5bc030d2012-08-16 18:48:50 +0100377class MethodTestCase : public SharedImpl<ITestCase> {
Phil Nash89d2a3f2012-05-16 15:09:17 +0100378
Phil Nash176eb812012-05-11 08:17:16 +0100379public:
380 MethodTestCase( void (C::*method)() ) : m_method( method ) {}
Phil Nash89d1e6c2011-05-24 08:23:02 +0100381
Phil Nash176eb812012-05-11 08:17:16 +0100382 virtual void invoke() const {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100383 C obj;
384 (obj.*m_method)();
385 }
386
Phil Nash89d1e6c2011-05-24 08:23:02 +0100387private:
Phil Nash5bc030d2012-08-16 18:48:50 +0100388 virtual ~MethodTestCase() {}
389
Phil Nash89d1e6c2011-05-24 08:23:02 +0100390 void (C::*m_method)();
391};
392
393typedef void(*TestFunction)();
394
Phil Nash89d2a3f2012-05-16 15:09:17 +0100395struct AutoReg {
396
Phil Nash176eb812012-05-11 08:17:16 +0100397 AutoReg( TestFunction function,
398 const char* name,
399 const char* description,
400 const SourceLineInfo& lineInfo );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100401
Phil Nash89d1e6c2011-05-24 08:23:02 +0100402 template<typename C>
Phil Nash176eb812012-05-11 08:17:16 +0100403 AutoReg( void (C::*method)(),
404 const char* name,
405 const char* description,
406 const SourceLineInfo& lineInfo ) {
Phil Nashd31737f2012-05-09 19:04:00 +0100407 registerTestCase( new MethodTestCase<C>( method ), name, description, lineInfo );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100408 }
409
Phil Nash176eb812012-05-11 08:17:16 +0100410 void registerTestCase( ITestCase* testCase,
411 const char* name,
412 const char* description,
413 const SourceLineInfo& lineInfo );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100414
Phil Nash176eb812012-05-11 08:17:16 +0100415 ~AutoReg();
Phil Nash89d1e6c2011-05-24 08:23:02 +0100416
417private:
Phil Nash176eb812012-05-11 08:17:16 +0100418 AutoReg( const AutoReg& );
419 void operator= ( const AutoReg& );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100420};
421
422} // end namespace Catch
423
424///////////////////////////////////////////////////////////////////////////////
425#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
Phil Nashd31737f2012-05-09 19:04:00 +0100426 static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )(); \
427 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ ), Name, Desc, CATCH_INTERNAL_LINEINFO ); }\
428 static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )()
Phil Nash89d1e6c2011-05-24 08:23:02 +0100429
430///////////////////////////////////////////////////////////////////////////////
431#define INTERNAL_CATCH_TESTCASE_NORETURN( Name, Desc ) \
Phil Nasha695eb92012-08-13 07:46:10 +0100432 static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )() CATCH_ATTRIBUTE_NORETURN; \
Phil Nashd31737f2012-05-09 19:04:00 +0100433 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ ), Name, Desc, CATCH_INTERNAL_LINEINFO ); }\
434 static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )()
Phil Nash89d1e6c2011-05-24 08:23:02 +0100435
436///////////////////////////////////////////////////////////////////////////////
Phil Nash46bcd4b2012-07-20 18:43:48 +0100437#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
Phil Nashd31737f2012-05-09 19:04:00 +0100438 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, Name, Desc, CATCH_INTERNAL_LINEINFO ); }
Phil Nash89d1e6c2011-05-24 08:23:02 +0100439
440///////////////////////////////////////////////////////////////////////////////
441#define TEST_CASE_METHOD( ClassName, TestName, Desc )\
Phil Nashfd78e0f2011-12-28 19:56:39 +0000442 namespace{ \
Phil Nashd31737f2012-05-09 19:04:00 +0100443 struct INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ ) : ClassName{ \
Phil Nashfd78e0f2011-12-28 19:56:39 +0000444 void test(); \
445 }; \
Phil Nashd31737f2012-05-09 19:04:00 +0100446 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ )::test, TestName, Desc, CATCH_INTERNAL_LINEINFO ); \
Phil Nashfd78e0f2011-12-28 19:56:39 +0000447 } \
Phil Nashd31737f2012-05-09 19:04:00 +0100448 void INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ )::test()
Phil Nash89d1e6c2011-05-24 08:23:02 +0100449
450// #included from: internal/catch_capture.hpp
Phil Nash3b80af72012-08-09 07:47:30 +0100451#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +0100452
Phil Nash89d2a3f2012-05-16 15:09:17 +0100453// #included from: catch_expression_builder.hpp
Phil Nash3b80af72012-08-09 07:47:30 +0100454#define TWOBLUECUBES_CATCH_EXPRESSION_BUILDER_HPP_INCLUDED
Phil Nash89d2a3f2012-05-16 15:09:17 +0100455
Phil Nash176eb812012-05-11 08:17:16 +0100456// #included from: catch_expression.hpp
Phil Nash3b80af72012-08-09 07:47:30 +0100457#define TWOBLUECUBES_CATCH_EXPRESSION_HPP_INCLUDED
Phil Nash176eb812012-05-11 08:17:16 +0100458
Phil Nash3b80af72012-08-09 07:47:30 +0100459// #included from: catch_resultinfo_builder.h
460#define TWOBLUECUBES_CATCH_RESULTINFO_BUILDER_H_INCLUDED
Phil Nashd31737f2012-05-09 19:04:00 +0100461
Phil Nashd31737f2012-05-09 19:04:00 +0100462// #included from: catch_tostring.hpp
Phil Nash3b80af72012-08-09 07:47:30 +0100463#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
Phil Nashd31737f2012-05-09 19:04:00 +0100464
Phil Nashd31737f2012-05-09 19:04:00 +0100465#include <sstream>
466
Phil Nash0dc9e432012-08-01 08:17:07 +0100467#ifdef __OBJC__
468// #included from: catch_objc_arc.hpp
Phil Nash3b80af72012-08-09 07:47:30 +0100469#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
Phil Nash0dc9e432012-08-01 08:17:07 +0100470
471#import <Foundation/Foundation.h>
472
473#ifdef __has_feature
474#define CATCH_ARC_ENABLED __has_feature(objc_arc)
475#else
476#define CATCH_ARC_ENABLED 0
477#endif
478
479void arcSafeRelease( NSObject* obj );
480id performOptionalSelector( id obj, SEL sel );
481
482#if !CATCH_ARC_ENABLED
483inline void arcSafeRelease( NSObject* obj ) {
484 [obj release];
485}
486inline id performOptionalSelector( id obj, SEL sel ) {
487 if( [obj respondsToSelector: sel] )
488 return [obj performSelector: sel];
489 return nil;
490}
491#define CATCH_UNSAFE_UNRETAINED
492#define CATCH_ARC_STRONG
493#else
494inline void arcSafeRelease( NSObject* ){}
495inline id performOptionalSelector( id obj, SEL sel ) {
Phil Nash5bc030d2012-08-16 18:48:50 +0100496#ifdef __clang__
Phil Nash0dc9e432012-08-01 08:17:07 +0100497#pragma clang diagnostic push
498#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
Phil Nash5bc030d2012-08-16 18:48:50 +0100499#endif
Phil Nash0dc9e432012-08-01 08:17:07 +0100500 if( [obj respondsToSelector: sel] )
501 return [obj performSelector: sel];
Phil Nash5bc030d2012-08-16 18:48:50 +0100502#ifdef __clang__
Phil Nash0dc9e432012-08-01 08:17:07 +0100503#pragma clang diagnostic pop
Phil Nash5bc030d2012-08-16 18:48:50 +0100504#endif
Phil Nash0dc9e432012-08-01 08:17:07 +0100505 return nil;
506}
507#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
508#define CATCH_ARC_STRONG __strong
509#endif
510
511#endif
512
Phil Nash89d2a3f2012-05-16 15:09:17 +0100513namespace Catch {
514namespace Detail {
515
Phil Nashd31737f2012-05-09 19:04:00 +0100516 struct NonStreamable {
517 template<typename T> NonStreamable( const T& ){}
518 };
519
520 // If the type does not have its own << overload for ostream then
521 // this one will be used instead
522 inline std::ostream& operator << ( std::ostream& ss, NonStreamable ){
523 return ss << "{?}";
524 }
525
526 template<typename T>
527 inline std::string makeString( const T& value ) {
528 std::ostringstream oss;
529 oss << value;
530 return oss.str();
531 }
532
533 template<typename T>
534 inline std::string makeString( T* p ) {
535 if( !p )
536 return INTERNAL_CATCH_STRINGIFY( NULL );
537 std::ostringstream oss;
538 oss << p;
539 return oss.str();
540 }
541
542 template<typename T>
543 inline std::string makeString( const T* p ) {
544 if( !p )
545 return INTERNAL_CATCH_STRINGIFY( NULL );
546 std::ostringstream oss;
547 oss << p;
548 return oss.str();
549 }
550
551} // end namespace Detail
552
553/// \brief converts any type to a string
554///
555/// The default template forwards on to ostringstream - except when an
556/// ostringstream overload does not exist - in which case it attempts to detect
557/// that and writes {?}.
558/// Overload (not specialise) this template for custom typs that you don't want
559/// to provide an ostream overload for.
560template<typename T>
561std::string toString( const T& value ) {
562 return Detail::makeString( value );
563}
564
565// Built in overloads
566
567inline std::string toString( const std::string& value ) {
568 return "\"" + value + "\"";
569}
570
571inline std::string toString( const std::wstring& value ) {
572 std::ostringstream oss;
573 oss << "\"";
574 for(size_t i = 0; i < value.size(); ++i )
575 oss << static_cast<char>( value[i] <= 0xff ? value[i] : '?');
576 oss << "\"";
577 return oss.str();
578}
579
580inline std::string toString( const char* const value ) {
581 return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
582}
583
584inline std::string toString( char* const value ) {
585 return Catch::toString( static_cast<const char*>( value ) );
586}
587
588inline std::string toString( int value ) {
589 std::ostringstream oss;
590 oss << value;
591 return oss.str();
592}
593
594inline std::string toString( unsigned long value ) {
595 std::ostringstream oss;
596 if( value > 8192 )
597 oss << "0x" << std::hex << value;
598 else
599 oss << value;
600 return oss.str();
601}
602
603inline std::string toString( unsigned int value ) {
Phil Nash62179662012-05-11 19:06:43 +0100604 return toString( static_cast<unsigned long>( value ) );
Phil Nashd31737f2012-05-09 19:04:00 +0100605}
606
607inline std::string toString( const double value ) {
608 std::ostringstream oss;
609 oss << value;
610 return oss.str();
611}
612
613inline std::string toString( bool value ) {
614 return value ? "true" : "false";
615}
616
Phil Nash78372d02012-06-06 08:06:40 +0100617inline std::string toString( char value ) {
618 return value < ' '
619 ? toString( (unsigned int)value )
620 : Detail::makeString( value );
621}
622
623inline std::string toString( signed char value ) {
624 return toString( static_cast<char>( value ) );
625}
626
Phil Nash176eb812012-05-11 08:17:16 +0100627#ifdef CATCH_CONFIG_CPP11_NULLPTR
Phil Nash06e959b2012-05-25 08:52:05 +0100628inline std::string toString( std::nullptr_t ) {
Phil Nash176eb812012-05-11 08:17:16 +0100629 return "nullptr";
630}
631#endif
632
Phil Nash0dc9e432012-08-01 08:17:07 +0100633#ifdef __OBJC__
Phil Nash0dc9e432012-08-01 08:17:07 +0100634 inline std::string toString( NSString const * const& nsstring ) {
635 return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
636 }
637 inline std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
638 return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
639 }
640 inline std::string toString( NSObject* const& nsObject ) {
641 return toString( [nsObject description] );
642 }
643#endif
644
Phil Nashd31737f2012-05-09 19:04:00 +0100645} // end namespace Catch
646
Phil Nash3b80af72012-08-09 07:47:30 +0100647// #included from: catch_resultinfo.h
648#define TWOBLUECUBES_CATCH_RESULT_INFO_H_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +0100649
Phil Nash89d1e6c2011-05-24 08:23:02 +0100650#include <string>
651// #included from: catch_result_type.h
Phil Nash3b80af72012-08-09 07:47:30 +0100652#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +0100653
Phil Nash89d2a3f2012-05-16 15:09:17 +0100654namespace Catch {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100655
Phil Nash89d2a3f2012-05-16 15:09:17 +0100656struct ResultWas { enum OfType {
657 Unknown = -1,
658 Ok = 0,
659 Info = 1,
660 Warning = 2,
Phil Nash89d1e6c2011-05-24 08:23:02 +0100661
Phil Nash89d2a3f2012-05-16 15:09:17 +0100662 FailureBit = 0x10,
Phil Nash89d1e6c2011-05-24 08:23:02 +0100663
Phil Nash89d2a3f2012-05-16 15:09:17 +0100664 ExpressionFailed = FailureBit | 1,
665 ExplicitFailure = FailureBit | 2,
Phil Nash89d1e6c2011-05-24 08:23:02 +0100666
Phil Nash89d2a3f2012-05-16 15:09:17 +0100667 Exception = 0x100 | FailureBit,
Phil Nash89d1e6c2011-05-24 08:23:02 +0100668
Phil Nash89d2a3f2012-05-16 15:09:17 +0100669 ThrewException = Exception | 1,
670 DidntThrowException = Exception | 2
Phil Nash89d1e6c2011-05-24 08:23:02 +0100671
Phil Nash89d2a3f2012-05-16 15:09:17 +0100672}; };
Phil Nash89d1e6c2011-05-24 08:23:02 +0100673
Phil Nash89d2a3f2012-05-16 15:09:17 +0100674struct ResultAction { enum Value {
675 None,
Phil Nash19b2aa62012-06-01 19:40:27 +0100676 Failed = 1, // Failure - but no debug break if Debug bit not set
677 Debug = 2, // If this bit is set, invoke the debugger
678 Abort = 4 // Test run should abort
Phil Nash89d2a3f2012-05-16 15:09:17 +0100679}; };
Phil Nash89d1e6c2011-05-24 08:23:02 +0100680
681}
682
683
Phil Nash89d2a3f2012-05-16 15:09:17 +0100684namespace Catch {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100685
Phil Nash89d2a3f2012-05-16 15:09:17 +0100686 class ResultInfo {
687 public:
Phil Nash3b80af72012-08-09 07:47:30 +0100688 ResultInfo();
Phil Nash89d2a3f2012-05-16 15:09:17 +0100689 ResultInfo( const char* expr,
690 ResultWas::OfType result,
691 bool isNot,
692 const SourceLineInfo& lineInfo,
693 const char* macroName,
Phil Nash3b80af72012-08-09 07:47:30 +0100694 const char* message );
Phil Nasha695eb92012-08-13 07:46:10 +0100695 ~ResultInfo();
Phil Nash89d1e6c2011-05-24 08:23:02 +0100696
Phil Nash3b80af72012-08-09 07:47:30 +0100697 bool ok() const;
698 ResultWas::OfType getResultType() const;
699 bool hasExpression() const;
700 bool hasMessage() const;
701 std::string getExpression() const;
702 bool hasExpandedExpression() const;
703 std::string getExpandedExpression() const;
704 std::string getMessage() const;
705 std::string getFilename() const;
706 std::size_t getLine() const;
707 std::string getTestMacroName() const;
Phil Nash89d1e6c2011-05-24 08:23:02 +0100708
709 protected:
710
Phil Nash3b80af72012-08-09 07:47:30 +0100711 std::string getExpandedExpressionInternal() const;
712 bool isNotExpression( const char* expr );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100713
714 protected:
715 std::string m_macroName;
Phil Nashd31737f2012-05-09 19:04:00 +0100716 SourceLineInfo m_lineInfo;
Phil Nash89d1e6c2011-05-24 08:23:02 +0100717 std::string m_expr, m_lhs, m_rhs, m_op;
718 std::string m_message;
719 ResultWas::OfType m_result;
720 bool m_isNot;
721 };
722
723} // end namespace Catch
724
Phil Nash89d1e6c2011-05-24 08:23:02 +0100725// #included from: catch_evaluate.hpp
Phil Nash3b80af72012-08-09 07:47:30 +0100726#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +0100727
Phil Nash89d2a3f2012-05-16 15:09:17 +0100728namespace Catch {
729namespace Internal {
730
731 enum Operator {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100732 IsEqualTo,
733 IsNotEqualTo,
734 IsLessThan,
735 IsGreaterThan,
736 IsLessThanOrEqualTo,
737 IsGreaterThanOrEqualTo
738 };
739
Phil Nash371db8b2012-05-21 18:52:09 +0100740 template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
741 template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
742 template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
743 template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
744 template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
745 template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
746 template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
Phil Nash89d1e6c2011-05-24 08:23:02 +0100747
748 // So the compare overloads can be operator agnostic we convey the operator as a template
749 // enum, which is used to specialise an Evaluator for doing the comparison.
750 template<typename T1, typename T2, Operator Op>
751 class Evaluator{};
752
753 template<typename T1, typename T2>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100754 struct Evaluator<T1, T2, IsEqualTo> {
755 static bool evaluate( const T1& lhs, const T2& rhs) {
Phil Nashd31737f2012-05-09 19:04:00 +0100756 return const_cast<T1&>( lhs ) == const_cast<T2&>( rhs );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100757 }
758 };
759 template<typename T1, typename T2>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100760 struct Evaluator<T1, T2, IsNotEqualTo> {
761 static bool evaluate( const T1& lhs, const T2& rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100762 return const_cast<T1&>( lhs ) != const_cast<T2&>( rhs );
763 }
764 };
765 template<typename T1, typename T2>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100766 struct Evaluator<T1, T2, IsLessThan> {
767 static bool evaluate( const T1& lhs, const T2& rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100768 return const_cast<T1&>( lhs ) < const_cast<T2&>( rhs );
769 }
770 };
771 template<typename T1, typename T2>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100772 struct Evaluator<T1, T2, IsGreaterThan> {
773 static bool evaluate( const T1& lhs, const T2& rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100774 return const_cast<T1&>( lhs ) > const_cast<T2&>( rhs );
775 }
776 };
777 template<typename T1, typename T2>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100778 struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
779 static bool evaluate( const T1& lhs, const T2& rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100780 return const_cast<T1&>( lhs ) >= const_cast<T2&>( rhs );
781 }
782 };
783 template<typename T1, typename T2>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100784 struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
785 static bool evaluate( const T1& lhs, const T2& rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100786 return const_cast<T1&>( lhs ) <= const_cast<T2&>( rhs );
787 }
788 };
789
790 template<Operator Op, typename T1, typename T2>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100791 bool applyEvaluator( const T1& lhs, const T2& rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100792 return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
793 }
794
795 // "base" overload
796 template<Operator Op, typename T1, typename T2>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100797 bool compare( const T1& lhs, const T2& rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100798 return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
799 }
800
801 // unsigned X to int
Phil Nash89d2a3f2012-05-16 15:09:17 +0100802 template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100803 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
804 }
Phil Nash89d2a3f2012-05-16 15:09:17 +0100805 template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100806 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
807 }
Phil Nash89d2a3f2012-05-16 15:09:17 +0100808 template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100809 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
810 }
811
812 // unsigned X to long
Phil Nash89d2a3f2012-05-16 15:09:17 +0100813 template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100814 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
815 }
Phil Nash89d2a3f2012-05-16 15:09:17 +0100816 template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100817 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
818 }
Phil Nash89d2a3f2012-05-16 15:09:17 +0100819 template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100820 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
821 }
822
823 // int to unsigned X
Phil Nash89d2a3f2012-05-16 15:09:17 +0100824 template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100825 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
826 }
Phil Nash89d2a3f2012-05-16 15:09:17 +0100827 template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100828 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
829 }
Phil Nash89d2a3f2012-05-16 15:09:17 +0100830 template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100831 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
832 }
833
834 // long to unsigned X
Phil Nash89d2a3f2012-05-16 15:09:17 +0100835 template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
Jardel Weyrich11dca662012-04-27 14:42:40 -0300836 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100837 }
Phil Nash89d2a3f2012-05-16 15:09:17 +0100838 template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
Jardel Weyrich11dca662012-04-27 14:42:40 -0300839 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100840 }
Phil Nash89d2a3f2012-05-16 15:09:17 +0100841 template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
Jardel Weyrich11dca662012-04-27 14:42:40 -0300842 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100843 }
844
Phil Nash06e959b2012-05-25 08:52:05 +0100845 // pointer to long (when comparing against NULL)
Phil Nash89d1e6c2011-05-24 08:23:02 +0100846 template<Operator Op, typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100847 bool compare( long lhs, const T* rhs ) {
Phil Nash6f1543b2012-05-07 19:46:19 +0100848 return Evaluator<const T*, const T*, Op>::evaluate( reinterpret_cast<const T*>( lhs ), rhs );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100849 }
850
851 template<Operator Op, typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100852 bool compare( long lhs, T* rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100853 return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
Phil Nash6f1543b2012-05-07 19:46:19 +0100854 }
Phil Nash89d1e6c2011-05-24 08:23:02 +0100855
Phil Nash6f1543b2012-05-07 19:46:19 +0100856 template<Operator Op, typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100857 bool compare( const T* lhs, long rhs ) {
Phil Nash6f1543b2012-05-07 19:46:19 +0100858 return Evaluator<const T*, const T*, Op>::evaluate( lhs, reinterpret_cast<const T*>( rhs ) );
859 }
860
861 template<Operator Op, typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100862 bool compare( T* lhs, long rhs ) {
Phil Nash6f1543b2012-05-07 19:46:19 +0100863 return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100864 }
865
Phil Nash06e959b2012-05-25 08:52:05 +0100866 // pointer to int (when comparing against NULL)
867 template<Operator Op, typename T>
868 bool compare( int lhs, const T* rhs ) {
869 return Evaluator<const T*, const T*, Op>::evaluate( reinterpret_cast<const T*>( lhs ), rhs );
870 }
871
872 template<Operator Op, typename T>
873 bool compare( int lhs, T* rhs ) {
874 return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
875 }
876
877 template<Operator Op, typename T>
878 bool compare( const T* lhs, int rhs ) {
879 return Evaluator<const T*, const T*, Op>::evaluate( lhs, reinterpret_cast<const T*>( rhs ) );
880 }
881
882 template<Operator Op, typename T>
883 bool compare( T* lhs, int rhs ) {
884 return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
885 }
886
Phil Nash89d1e6c2011-05-24 08:23:02 +0100887} // end of namespace Internal
888} // end of namespace Catch
889
Phil Nash89d2a3f2012-05-16 15:09:17 +0100890namespace Catch {
Phil Nashf51d3162011-12-28 10:37:31 +0000891
Phil Nash89d1e6c2011-05-24 08:23:02 +0100892struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
893
Phil Nash89d2a3f2012-05-16 15:09:17 +0100894class ResultInfoBuilder : public ResultInfo {
895
Phil Nash89d1e6c2011-05-24 08:23:02 +0100896public:
897
Phil Nash3b80af72012-08-09 07:47:30 +0100898 ResultInfoBuilder();
Phil Nashd31737f2012-05-09 19:04:00 +0100899
900 ResultInfoBuilder( const char* expr,
901 bool isNot,
902 const SourceLineInfo& lineInfo,
903 const char* macroName,
Phil Nash3b80af72012-08-09 07:47:30 +0100904 const char* message = "" );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100905
Phil Nash3b80af72012-08-09 07:47:30 +0100906 void setResultType( ResultWas::OfType result );
907 void setMessage( const std::string& message );
908 void setLineInfo( const SourceLineInfo& lineInfo );
909 void setLhs( const std::string& lhs );
910 void setRhs( const std::string& rhs );
911 void setOp( const std::string& op );
Phil Nash78d95a02012-03-04 21:22:36 +0000912
Phil Nash89d1e6c2011-05-24 08:23:02 +0100913 template<typename RhsT>
914 STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator ||
915 (
916 const RhsT&
917 );
918
Phil Nash89d1e6c2011-05-24 08:23:02 +0100919 template<typename RhsT>
920 STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator &&
921 (
922 const RhsT&
923 );
924
925private:
Phil Nash89d2a3f2012-05-16 15:09:17 +0100926 friend class ExpressionBuilder;
Phil Nash89d1e6c2011-05-24 08:23:02 +0100927 template<typename T> friend class Expression;
928
929 template<typename T> friend class PtrExpression;
930
Phil Nash3b80af72012-08-09 07:47:30 +0100931 ResultInfoBuilder& captureBoolExpression( bool result );
Phil Nash89d1e6c2011-05-24 08:23:02 +0100932
Phil Nash89d1e6c2011-05-24 08:23:02 +0100933 template<Internal::Operator Op, typename T1, typename T2>
Phil Nashd31737f2012-05-09 19:04:00 +0100934 ResultInfoBuilder& captureExpression( const T1& lhs, const T2& rhs ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +0100935 setResultType( Internal::compare<Op>( lhs, rhs ) ? ResultWas::Ok : ResultWas::ExpressionFailed );
936 m_lhs = Catch::toString( lhs );
937 m_rhs = Catch::toString( rhs );
938 m_op = Internal::OperatorTraits<Op>::getName();
939 return *this;
940 }
941
Phil Nash4021d652011-07-15 08:12:10 +0100942 template<Internal::Operator Op, typename T>
Phil Nashd31737f2012-05-09 19:04:00 +0100943 ResultInfoBuilder& captureExpression( const T* lhs, int rhs ) {
Phil Nash4021d652011-07-15 08:12:10 +0100944 return captureExpression<Op>( lhs, reinterpret_cast<const T*>( rhs ) );
945 }
Phil Nash89d1e6c2011-05-24 08:23:02 +0100946};
947
Phil Nashd31737f2012-05-09 19:04:00 +0100948} // end namespace Catch
949
Phil Nash89d2a3f2012-05-16 15:09:17 +0100950namespace Catch {
Phil Nash176eb812012-05-11 08:17:16 +0100951
952template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +0100953class Expression {
Phil Nash176eb812012-05-11 08:17:16 +0100954 void operator = ( const Expression& );
955
956public:
957 Expression( ResultInfoBuilder& result, T lhs )
958 : m_result( result ),
959 m_lhs( lhs )
960 {}
961
962 template<typename RhsT>
963 ResultInfoBuilder& operator == ( const RhsT& rhs ) {
964 return m_result.captureExpression<Internal::IsEqualTo>( m_lhs, rhs );
965 }
966
967 template<typename RhsT>
968 ResultInfoBuilder& operator != ( const RhsT& rhs ) {
969 return m_result.captureExpression<Internal::IsNotEqualTo>( m_lhs, rhs );
970 }
971
972 template<typename RhsT>
973 ResultInfoBuilder& operator < ( const RhsT& rhs ) {
974 return m_result.captureExpression<Internal::IsLessThan>( m_lhs, rhs );
975 }
976
977 template<typename RhsT>
978 ResultInfoBuilder& operator > ( const RhsT& rhs ) {
979 return m_result.captureExpression<Internal::IsGreaterThan>( m_lhs, rhs );
980 }
981
982 template<typename RhsT>
983 ResultInfoBuilder& operator <= ( const RhsT& rhs ) {
984 return m_result.captureExpression<Internal::IsLessThanOrEqualTo>( m_lhs, rhs );
985 }
986
987 template<typename RhsT>
988 ResultInfoBuilder& operator >= ( const RhsT& rhs ) {
989 return m_result.captureExpression<Internal::IsGreaterThanOrEqualTo>( m_lhs, rhs );
990 }
991
992 ResultInfoBuilder& operator == ( bool rhs ) {
993 return m_result.captureExpression<Internal::IsEqualTo>( m_lhs, rhs );
994 }
995
996 ResultInfoBuilder& operator != ( bool rhs ) {
997 return m_result.captureExpression<Internal::IsNotEqualTo>( m_lhs, rhs );
998 }
999
1000 operator ResultInfoBuilder& () {
1001 return m_result.captureBoolExpression( m_lhs );
1002 }
1003
1004 template<typename RhsT>
1005 STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( const RhsT& );
1006
1007 template<typename RhsT>
1008 STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( const RhsT& );
1009
1010private:
1011 ResultInfoBuilder& m_result;
1012 T m_lhs;
1013};
1014
Phil Nash176eb812012-05-11 08:17:16 +01001015} // end namespace Catch
1016
Phil Nash89d2a3f2012-05-16 15:09:17 +01001017#include <sstream>
1018
1019namespace Catch {
1020
1021class ExpressionBuilder {
1022public:
1023
1024 ExpressionBuilder( const SourceLineInfo& lineInfo,
1025 const char* macroName,
1026 const char* expr = "",
1027 bool isNot = false )
1028 : m_result( expr, isNot, lineInfo, macroName ),
1029 m_messageStream()
1030 {}
1031
1032 template<typename T>
1033 Expression<const T&> operator->* ( const T & operand ) {
1034 Expression<const T&> expr( m_result, operand );
1035 return expr;
1036 }
1037
Phil Nash89d2a3f2012-05-16 15:09:17 +01001038 Expression<bool> operator->* ( bool value ) {
1039 Expression<bool> expr( m_result, value );
1040 return expr;
1041 }
1042
1043 template<typename T>
1044 ExpressionBuilder& operator << ( const T & value ) {
1045 m_messageStream << Catch::toString( value );
1046 return *this;
1047 }
1048
1049 template<typename MatcherT, typename ArgT>
1050 ExpressionBuilder& acceptMatcher( const MatcherT& matcher,
1051 const ArgT& arg,
1052 const std::string& matcherCallAsString ) {
1053 std::string matcherAsString = Catch::toString( matcher );
1054 if( matcherAsString == "{?}" )
1055 matcherAsString = matcherCallAsString;
1056 m_result.setLhs( Catch::toString( arg ) );
1057 m_result.setRhs( matcherAsString );
1058 m_result.setOp( "matches" );
1059 m_result.setResultType( matcher( arg ) ? ResultWas::Ok : ResultWas::ExpressionFailed );
1060 return *this;
1061 }
1062
1063 template<typename MatcherT, typename ArgT>
1064 ExpressionBuilder& acceptMatcher( const MatcherT& matcher,
1065 ArgT* arg,
1066 const std::string& matcherCallAsString ) {
1067 std::string matcherAsString = Catch::toString( matcher );
1068 if( matcherAsString == "{?}" )
1069 matcherAsString = matcherCallAsString;
1070 m_result.setLhs( Catch::toString( arg ) );
1071 m_result.setRhs( matcherAsString );
1072 m_result.setOp( "matches" );
1073 m_result.setResultType( matcher( arg ) ? ResultWas::Ok : ResultWas::ExpressionFailed );
1074 return *this;
1075 }
1076
1077 ExpressionBuilder& setResultType( ResultWas::OfType resultType ) {
1078 m_result.setResultType( resultType );
1079 return *this;
1080 }
1081
1082 operator ResultInfoBuilder&() {
1083 m_result.setMessage( m_messageStream.str() );
1084 return m_result;
1085 }
1086
1087private:
1088 ResultInfoBuilder m_result;
1089 std::ostringstream m_messageStream;
1090};
1091
1092} // end namespace Catch
1093
Phil Nashd31737f2012-05-09 19:04:00 +01001094// #included from: catch_interfaces_capture.h
Phil Nash3b80af72012-08-09 07:47:30 +01001095#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
Phil Nashd31737f2012-05-09 19:04:00 +01001096
Phil Nashd31737f2012-05-09 19:04:00 +01001097#include <string>
Phil Nasha70fbe32012-08-31 08:10:36 +01001098// #included from: catch_totals.hpp
1099#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
1100
1101namespace Catch {
1102
1103 struct Counts {
1104 Counts() : passed( 0 ), failed( 0 ) {}
1105
1106 Counts operator - ( const Counts& other ) const {
1107 Counts diff;
1108 diff.passed = passed - other.passed;
1109 diff.failed = failed - other.failed;
1110 return diff;
1111 }
1112 Counts& operator += ( const Counts& other ) {
1113 passed += other.passed;
1114 failed += other.failed;
1115 return *this;
1116 }
1117
1118 std::size_t total() const {
1119 return passed + failed;
1120 }
1121
1122 std::size_t passed;
1123 std::size_t failed;
1124 };
1125
1126 struct Totals {
1127
1128 Totals operator - ( const Totals& other ) const {
1129 Totals diff;
1130 diff.assertions = assertions - other.assertions;
1131 diff.testCases = testCases - other.testCases;
1132 return diff;
1133 }
1134
1135 Totals delta( const Totals& prevTotals ) const {
1136 Totals diff = *this - prevTotals;
1137 if( diff.assertions.failed > 0 )
1138 ++diff.testCases.failed;
1139 else
1140 ++diff.testCases.passed;
1141 return diff;
1142 }
1143
1144 Totals& operator += ( const Totals& other ) {
1145 assertions += other.assertions;
1146 testCases += other.testCases;
1147 return *this;
1148 }
1149
1150 Counts assertions;
1151 Counts testCases;
1152 };
1153}
1154
Phil Nashd31737f2012-05-09 19:04:00 +01001155
Phil Nash89d2a3f2012-05-16 15:09:17 +01001156namespace Catch {
1157
Phil Nashd31737f2012-05-09 19:04:00 +01001158 class TestCaseInfo;
1159 class ScopedInfo;
1160 class ResultInfoBuilder;
1161 class ResultInfo;
1162
Phil Nash89d2a3f2012-05-16 15:09:17 +01001163 struct IResultCapture {
Phil Nashd31737f2012-05-09 19:04:00 +01001164
Phil Nasha695eb92012-08-13 07:46:10 +01001165 virtual ~IResultCapture();
Phil Nashd31737f2012-05-09 19:04:00 +01001166
Phil Nash89d2a3f2012-05-16 15:09:17 +01001167 virtual void testEnded( const ResultInfo& result ) = 0;
1168 virtual bool sectionStarted( const std::string& name,
1169 const std::string& description,
1170 const SourceLineInfo& lineInfo,
1171 Counts& assertions ) = 0;
1172 virtual void sectionEnded( const std::string& name, const Counts& assertions ) = 0;
1173 virtual void pushScopedInfo( ScopedInfo* scopedInfo ) = 0;
1174 virtual void popScopedInfo( ScopedInfo* scopedInfo ) = 0;
1175 virtual bool shouldDebugBreak() const = 0;
Phil Nashd31737f2012-05-09 19:04:00 +01001176
Phil Nash89d2a3f2012-05-16 15:09:17 +01001177 virtual ResultAction::Value acceptResult( bool result ) = 0;
1178 virtual ResultAction::Value acceptResult( ResultWas::OfType result ) = 0;
1179 virtual ResultAction::Value acceptExpression( const ResultInfoBuilder& resultInfo ) = 0;
1180 virtual void acceptMessage( const std::string& msg ) = 0;
Phil Nashd31737f2012-05-09 19:04:00 +01001181
Phil Nash89d2a3f2012-05-16 15:09:17 +01001182 virtual std::string getCurrentTestName() const = 0;
1183 virtual const ResultInfo* getLastResult() const = 0;
Phil Nashd31737f2012-05-09 19:04:00 +01001184 };
1185}
1186
1187// #included from: catch_debugger.hpp
Phil Nash3b80af72012-08-09 07:47:30 +01001188#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
Phil Nashd31737f2012-05-09 19:04:00 +01001189
Phil Nashd31737f2012-05-09 19:04:00 +01001190#include <iostream>
1191
1192#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
1193#define CATCH_PLATFORM_MAC
1194#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
1195#define CATCH_PLATFORM_IPHONE
1196#elif defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
1197#define CATCH_PLATFORM_WINDOWS
1198#endif
1199
1200#ifdef CATCH_PLATFORM_MAC
1201
1202 #include <assert.h>
1203 #include <stdbool.h>
1204 #include <sys/types.h>
1205 #include <unistd.h>
1206 #include <sys/sysctl.h>
1207
Phil Nash89d2a3f2012-05-16 15:09:17 +01001208 namespace Catch{
1209
Phil Nashd31737f2012-05-09 19:04:00 +01001210 // The following function is taken directly from the following technical note:
1211 // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
1212
Phil Nashd31737f2012-05-09 19:04:00 +01001213 // Returns true if the current process is being debugged (either
1214 // running under the debugger or has a debugger attached post facto).
Phil Nash89d2a3f2012-05-16 15:09:17 +01001215 inline bool isDebuggerActive(){
1216
Phil Nashd31737f2012-05-09 19:04:00 +01001217 int junk;
1218 int mib[4];
1219 struct kinfo_proc info;
1220 size_t size;
1221
1222 // Initialize the flags so that, if sysctl fails for some bizarre
1223 // reason, we get a predictable result.
1224
1225 info.kp_proc.p_flag = 0;
1226
1227 // Initialize mib, which tells sysctl the info we want, in this case
1228 // we're looking for information about a specific process ID.
1229
1230 mib[0] = CTL_KERN;
1231 mib[1] = KERN_PROC;
1232 mib[2] = KERN_PROC_PID;
1233 mib[3] = getpid();
1234
1235 // Call sysctl.
1236
1237 size = sizeof(info);
1238 junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
1239 assert(junk == 0);
1240
1241 // We're being debugged if the P_TRACED flag is set.
1242
1243 return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
1244 }
1245 }
1246
1247 // The following code snippet taken from:
1248 // http://cocoawithlove.com/2008/03/break-into-debugger.html
1249 #ifdef DEBUG
1250 #if defined(__ppc64__) || defined(__ppc__)
1251 #define BreakIntoDebugger() \
Phil Nash89d2a3f2012-05-16 15:09:17 +01001252 if( Catch::isDebuggerActive() ) { \
Phil Nashd31737f2012-05-09 19:04:00 +01001253 __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
1254 : : : "memory","r0","r3","r4" ); \
1255 }
1256 #else
1257 #define BreakIntoDebugger() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
1258 #endif
1259 #else
1260 inline void BreakIntoDebugger(){}
1261 #endif
1262
1263#elif defined(_MSC_VER)
1264 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
1265 #define BreakIntoDebugger() if (IsDebuggerPresent() ) { __debugbreak(); }
Phil Nash89d2a3f2012-05-16 15:09:17 +01001266 inline bool isDebuggerActive() {
Phil Nashd31737f2012-05-09 19:04:00 +01001267 return IsDebuggerPresent() != 0;
1268 }
Phil Nash176eb812012-05-11 08:17:16 +01001269#elif defined(__MINGW32__)
1270 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
1271 extern "C" __declspec(dllimport) void __stdcall DebugBreak();
1272 #define BreakIntoDebugger() if (IsDebuggerPresent() ) { DebugBreak(); }
Phil Nash89d2a3f2012-05-16 15:09:17 +01001273 inline bool isDebuggerActive() {
Phil Nash176eb812012-05-11 08:17:16 +01001274 return IsDebuggerPresent() != 0;
1275 }
Phil Nashd31737f2012-05-09 19:04:00 +01001276#else
1277 inline void BreakIntoDebugger(){}
1278 inline bool isDebuggerActive() { return false; }
1279#endif
1280
1281#ifdef CATCH_PLATFORM_WINDOWS
1282extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
Phil Nash89d2a3f2012-05-16 15:09:17 +01001283inline void writeToDebugConsole( const std::string& text ) {
Phil Nashd31737f2012-05-09 19:04:00 +01001284 ::OutputDebugStringA( text.c_str() );
1285}
1286#else
Phil Nash89d2a3f2012-05-16 15:09:17 +01001287inline void writeToDebugConsole( const std::string& text ) {
Phil Nashd31737f2012-05-09 19:04:00 +01001288 // !TBD: Need a version for Mac/ XCode and other IDEs
1289 std::cout << text;
1290}
1291#endif // CATCH_PLATFORM_WINDOWS
1292
Phil Nash89d2a3f2012-05-16 15:09:17 +01001293#include <ostream>
Phil Nashd31737f2012-05-09 19:04:00 +01001294
Phil Nash89d2a3f2012-05-16 15:09:17 +01001295namespace Catch {
Phil Nashd31737f2012-05-09 19:04:00 +01001296
1297struct TestFailureException{};
Phil Nashd31737f2012-05-09 19:04:00 +01001298
Phil Nash89d2a3f2012-05-16 15:09:17 +01001299class ScopedInfo {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001300public:
Phil Nashd31737f2012-05-09 19:04:00 +01001301 ScopedInfo() : m_oss() {
Phil Nash371db8b2012-05-21 18:52:09 +01001302 getCurrentContext().getResultCapture().pushScopedInfo( this );
Phil Nash89d1e6c2011-05-24 08:23:02 +01001303 }
1304
Phil Nashd31737f2012-05-09 19:04:00 +01001305 ~ScopedInfo() {
Phil Nash371db8b2012-05-21 18:52:09 +01001306 getCurrentContext().getResultCapture().popScopedInfo( this );
Phil Nash89d1e6c2011-05-24 08:23:02 +01001307 }
1308
Phil Nashd31737f2012-05-09 19:04:00 +01001309 template<typename T>
1310 ScopedInfo& operator << ( const T& value ) {
1311 m_oss << value;
Phil Nash89d1e6c2011-05-24 08:23:02 +01001312 return *this;
1313 }
1314
Phil Nash799ecf92012-09-24 08:30:13 +01001315 ResultInfo getInfo () const {
1316 return ResultInfo( "", ResultWas::Info, false, SourceLineInfo(), "SCOPED_INFO", m_oss.str().c_str() );
Phil Nash89d1e6c2011-05-24 08:23:02 +01001317 }
1318
1319private:
1320 std::ostringstream m_oss;
1321};
1322
Phil Nash89d1e6c2011-05-24 08:23:02 +01001323// This is just here to avoid compiler warnings with macro constants
Phil Nashd31737f2012-05-09 19:04:00 +01001324inline bool isTrue( bool value ){ return value; }
Phil Nash89d1e6c2011-05-24 08:23:02 +01001325
1326} // end namespace Catch
1327
1328///////////////////////////////////////////////////////////////////////////////
Phil Nashd31737f2012-05-09 19:04:00 +01001329#define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \
Phil Nashe4636872012-06-05 20:51:05 +01001330 if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) { \
Phil Nash19b2aa62012-06-01 19:40:27 +01001331 if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \
1332 if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001333 if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \
Phil Nashd31737f2012-05-09 19:04:00 +01001334 if( Catch::isTrue( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001335 }
1336
1337///////////////////////////////////////////////////////////////////////////////
1338#define INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ) \
Phil Nashe4636872012-06-05 20:51:05 +01001339 do { try { \
Phil Nash89d2a3f2012-05-16 15:09:17 +01001340 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr, isNot )->*expr ), stopOnFailure, expr ); \
Phil Nashe4636872012-06-05 20:51:05 +01001341 } catch( Catch::TestFailureException& ) { \
Phil Nash333e6e62012-02-17 19:50:59 +00001342 throw; \
Phil Nashe4636872012-06-05 20:51:05 +01001343 } catch( ... ) { \
Phil Nash3b80af72012-08-09 07:47:30 +01001344 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getRegistryHub().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, expr ); \
Phil Nash333e6e62012-02-17 19:50:59 +00001345 throw; \
Phil Nashe4636872012-06-05 20:51:05 +01001346 } } while( Catch::isTrue( false ) )
Phil Nash89d1e6c2011-05-24 08:23:02 +01001347
1348///////////////////////////////////////////////////////////////////////////////
Phil Nasha162e222012-02-10 08:30:13 +00001349#define INTERNAL_CATCH_IF( expr, isNot, stopOnFailure, macroName ) \
1350 INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \
Phil Nash371db8b2012-05-21 18:52:09 +01001351 if( Catch::getCurrentContext().getResultCapture().getLastResult()->ok() )
Phil Nasha162e222012-02-10 08:30:13 +00001352
1353///////////////////////////////////////////////////////////////////////////////
1354#define INTERNAL_CATCH_ELSE( expr, isNot, stopOnFailure, macroName ) \
1355 INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \
Phil Nash371db8b2012-05-21 18:52:09 +01001356 if( !Catch::getCurrentContext().getResultCapture().getLastResult()->ok() )
Phil Nasha162e222012-02-10 08:30:13 +00001357
1358///////////////////////////////////////////////////////////////////////////////
Phil Nash89d1e6c2011-05-24 08:23:02 +01001359#define INTERNAL_CATCH_NO_THROW( expr, stopOnFailure, macroName ) \
Phil Nashe4636872012-06-05 20:51:05 +01001360 try { \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001361 expr; \
Phil Nash89d2a3f2012-05-16 15:09:17 +01001362 INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::Ok ), stopOnFailure, false ); \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001363 } \
Phil Nashe4636872012-06-05 20:51:05 +01001364 catch( ... ) { \
Phil Nash3b80af72012-08-09 07:47:30 +01001365 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getRegistryHub().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001366 }
1367
1368///////////////////////////////////////////////////////////////////////////////
1369#define INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \
Phil Nashe4636872012-06-05 20:51:05 +01001370 try { \
1371 if( Catch::getCurrentContext().getConfig()->allowThrows() ) { \
1372 expr; \
1373 INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::DidntThrowException ), stopOnFailure, false ); \
1374 } \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001375 } \
Phil Nashe4636872012-06-05 20:51:05 +01001376 catch( Catch::TestFailureException& ) { \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001377 throw; \
1378 } \
Phil Nashe4636872012-06-05 20:51:05 +01001379 catch( exceptionType ) { \
Phil Nash89d2a3f2012-05-16 15:09:17 +01001380 INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::Ok ), stopOnFailure, false ); \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001381 }
1382
1383///////////////////////////////////////////////////////////////////////////////
1384#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, stopOnFailure, macroName ) \
1385 INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \
Phil Nashe4636872012-06-05 20:51:05 +01001386 catch( ... ) { \
Phil Nash3b80af72012-08-09 07:47:30 +01001387 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getRegistryHub().getExceptionTranslatorRegistry() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \
Phil Nash89d1e6c2011-05-24 08:23:02 +01001388 }
1389
1390///////////////////////////////////////////////////////////////////////////////
1391#define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \
Phil Nash371db8b2012-05-21 18:52:09 +01001392 Catch::getCurrentContext().getResultCapture().acceptExpression( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName ) << reason ).setResultType( resultType ) );
Phil Nash89d1e6c2011-05-24 08:23:02 +01001393
1394///////////////////////////////////////////////////////////////////////////////
1395#define INTERNAL_CATCH_SCOPED_INFO( log ) \
1396 Catch::ScopedInfo INTERNAL_CATCH_UNIQUE_NAME( info ); \
1397 INTERNAL_CATCH_UNIQUE_NAME( info ) << log
1398
Phil Nash78d95a02012-03-04 21:22:36 +00001399///////////////////////////////////////////////////////////////////////////////
1400#define INTERNAL_CHECK_THAT( arg, matcher, stopOnFailure, macroName ) \
Phil Nashe4636872012-06-05 20:51:05 +01001401 do { try { \
Phil Nasha8570df2012-05-24 08:29:41 +01001402 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher, false ).acceptMatcher( ::Catch::Matchers::matcher, arg, #matcher ) ), stopOnFailure, false ); \
Phil Nashe4636872012-06-05 20:51:05 +01001403 } catch( Catch::TestFailureException& ) { \
Phil Nash78d95a02012-03-04 21:22:36 +00001404 throw; \
Phil Nashe4636872012-06-05 20:51:05 +01001405 } catch( ... ) { \
Phil Nash3b80af72012-08-09 07:47:30 +01001406 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher ) << Catch::getRegistryHub().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, false ); \
Phil Nash78d95a02012-03-04 21:22:36 +00001407 throw; \
1408 }}while( Catch::isTrue( false ) )
1409
Phil Nash89d1e6c2011-05-24 08:23:02 +01001410// #included from: internal/catch_section.hpp
Phil Nash3b80af72012-08-09 07:47:30 +01001411#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +01001412
Phil Nash89d1e6c2011-05-24 08:23:02 +01001413#include <string>
1414
Phil Nash89d2a3f2012-05-16 15:09:17 +01001415namespace Catch {
1416
1417 class Section {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001418 public:
Phil Nash89d2a3f2012-05-16 15:09:17 +01001419 Section( const std::string& name,
1420 const std::string& description,
1421 const SourceLineInfo& lineInfo )
Phil Nash89d1e6c2011-05-24 08:23:02 +01001422 : m_name( name ),
Phil Nash371db8b2012-05-21 18:52:09 +01001423 m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( name, description, lineInfo, m_assertions ) )
Phil Nash89d2a3f2012-05-16 15:09:17 +01001424 {}
Phil Nash89d1e6c2011-05-24 08:23:02 +01001425
Phil Nash89d2a3f2012-05-16 15:09:17 +01001426 ~Section() {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001427 if( m_sectionIncluded )
Phil Nash371db8b2012-05-21 18:52:09 +01001428 getCurrentContext().getResultCapture().sectionEnded( m_name, m_assertions );
Phil Nash89d1e6c2011-05-24 08:23:02 +01001429 }
1430
Phil Nash89d1e6c2011-05-24 08:23:02 +01001431 // This indicates whether the section should be executed or not
Phil Nash89d2a3f2012-05-16 15:09:17 +01001432 operator bool() {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001433 return m_sectionIncluded;
1434 }
1435
1436 private:
1437
1438 std::string m_name;
Phil Nashf7299fc2012-02-25 09:39:45 +00001439 Counts m_assertions;
Phil Nash89d1e6c2011-05-24 08:23:02 +01001440 bool m_sectionIncluded;
1441 };
1442
1443} // end namespace Catch
1444
1445#define INTERNAL_CATCH_SECTION( name, desc ) \
Phil Nashd31737f2012-05-09 19:04:00 +01001446 if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( name, desc, CATCH_INTERNAL_LINEINFO ) )
Phil Nash89d1e6c2011-05-24 08:23:02 +01001447
1448// #included from: internal/catch_generators.hpp
Phil Nash3b80af72012-08-09 07:47:30 +01001449#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +01001450
Phil Nash89d1e6c2011-05-24 08:23:02 +01001451#include <iterator>
1452#include <vector>
1453#include <string>
1454#include <stdlib.h>
1455
Phil Nash89d2a3f2012-05-16 15:09:17 +01001456namespace Catch {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001457
1458template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01001459struct IGenerator {
1460 virtual ~IGenerator() {}
1461 virtual T getValue( std::size_t index ) const = 0;
1462 virtual std::size_t size () const = 0;
Phil Nash89d1e6c2011-05-24 08:23:02 +01001463};
1464
1465template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01001466class BetweenGenerator : public IGenerator<T> {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001467public:
Phil Nash89d2a3f2012-05-16 15:09:17 +01001468 BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
Phil Nash89d1e6c2011-05-24 08:23:02 +01001469
Phil Nash89d2a3f2012-05-16 15:09:17 +01001470 virtual T getValue( std::size_t index ) const {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001471 return m_from+static_cast<T>( index );
1472 }
1473
Phil Nash89d2a3f2012-05-16 15:09:17 +01001474 virtual std::size_t size() const {
Phil Nashd31737f2012-05-09 19:04:00 +01001475 return static_cast<std::size_t>( 1+m_to-m_from );
Phil Nash89d1e6c2011-05-24 08:23:02 +01001476 }
1477
1478private:
1479
1480 T m_from;
1481 T m_to;
1482};
1483
1484template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01001485class ValuesGenerator : public IGenerator<T> {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001486public:
Phil Nash89d2a3f2012-05-16 15:09:17 +01001487 ValuesGenerator(){}
Phil Nash89d1e6c2011-05-24 08:23:02 +01001488
Phil Nash89d2a3f2012-05-16 15:09:17 +01001489 void add( T value ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001490 m_values.push_back( value );
1491 }
1492
Phil Nash89d2a3f2012-05-16 15:09:17 +01001493 virtual T getValue( std::size_t index ) const {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001494 return m_values[index];
1495 }
1496
Phil Nash89d2a3f2012-05-16 15:09:17 +01001497 virtual std::size_t size() const {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001498 return m_values.size();
1499 }
1500
1501private:
Phil Nash89d1e6c2011-05-24 08:23:02 +01001502 std::vector<T> m_values;
1503};
1504
1505template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01001506class CompositeGenerator {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001507public:
Phil Nash89d2a3f2012-05-16 15:09:17 +01001508 CompositeGenerator() : m_totalSize( 0 ) {}
Phil Nash89d1e6c2011-05-24 08:23:02 +01001509
Phil Nash89d1e6c2011-05-24 08:23:02 +01001510 // *** Move semantics, similar to auto_ptr ***
1511 CompositeGenerator( CompositeGenerator& other )
Phil Nash89d2a3f2012-05-16 15:09:17 +01001512 : m_fileInfo( other.m_fileInfo ),
1513 m_totalSize( 0 )
Phil Nash89d1e6c2011-05-24 08:23:02 +01001514 {
1515 move( other );
1516 }
1517
Phil Nash89d2a3f2012-05-16 15:09:17 +01001518 CompositeGenerator& setFileInfo( const char* fileInfo ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001519 m_fileInfo = fileInfo;
1520 return *this;
1521 }
1522
Phil Nash89d2a3f2012-05-16 15:09:17 +01001523 ~CompositeGenerator() {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001524 deleteAll( m_composed );
1525 }
1526
Phil Nash89d2a3f2012-05-16 15:09:17 +01001527 operator T () const {
Phil Nash371db8b2012-05-21 18:52:09 +01001528 size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
Phil Nash89d1e6c2011-05-24 08:23:02 +01001529
1530 typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
1531 typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
1532 for( size_t index = 0; it != itEnd; ++it )
1533 {
1534 const IGenerator<T>* generator = *it;
1535 if( overallIndex >= index && overallIndex < index + generator->size() )
1536 {
1537 return generator->getValue( overallIndex-index );
1538 }
1539 index += generator->size();
1540 }
1541 CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
1542 return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
1543 }
1544
Phil Nash89d2a3f2012-05-16 15:09:17 +01001545 void add( const IGenerator<T>* generator ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001546 m_totalSize += generator->size();
1547 m_composed.push_back( generator );
1548 }
1549
Phil Nash89d2a3f2012-05-16 15:09:17 +01001550 CompositeGenerator& then( CompositeGenerator& other ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001551 move( other );
1552 return *this;
1553 }
1554
Phil Nash89d2a3f2012-05-16 15:09:17 +01001555 CompositeGenerator& then( T value ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001556 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
1557 valuesGen->add( value );
1558 add( valuesGen );
1559 return *this;
1560 }
1561
1562private:
1563
Phil Nash89d2a3f2012-05-16 15:09:17 +01001564 void move( CompositeGenerator& other ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001565 std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
1566 m_totalSize += other.m_totalSize;
1567 other.m_composed.clear();
1568 }
1569
1570 std::vector<const IGenerator<T>*> m_composed;
1571 std::string m_fileInfo;
1572 size_t m_totalSize;
1573};
1574
1575namespace Generators
1576{
Phil Nash89d1e6c2011-05-24 08:23:02 +01001577 template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01001578 CompositeGenerator<T> between( T from, T to ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001579 CompositeGenerator<T> generators;
1580 generators.add( new BetweenGenerator<T>( from, to ) );
1581 return generators;
1582 }
1583
Phil Nash89d1e6c2011-05-24 08:23:02 +01001584 template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01001585 CompositeGenerator<T> values( T val1, T val2 ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001586 CompositeGenerator<T> generators;
1587 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
1588 valuesGen->add( val1 );
1589 valuesGen->add( val2 );
1590 generators.add( valuesGen );
1591 return generators;
1592 }
1593
Phil Nash89d1e6c2011-05-24 08:23:02 +01001594 template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01001595 CompositeGenerator<T> values( T val1, T val2, T val3 ){
Phil Nash89d1e6c2011-05-24 08:23:02 +01001596 CompositeGenerator<T> generators;
1597 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
1598 valuesGen->add( val1 );
1599 valuesGen->add( val2 );
1600 valuesGen->add( val3 );
1601 generators.add( valuesGen );
1602 return generators;
1603 }
1604
Phil Nash89d1e6c2011-05-24 08:23:02 +01001605 template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01001606 CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01001607 CompositeGenerator<T> generators;
1608 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
1609 valuesGen->add( val1 );
1610 valuesGen->add( val2 );
1611 valuesGen->add( val3 );
1612 valuesGen->add( val4 );
1613 generators.add( valuesGen );
1614 return generators;
1615 }
1616
1617} // end namespace Generators
1618
1619using namespace Generators;
1620
1621} // end namespace Catch
1622
1623#define INTERNAL_CATCH_LINESTR2( line ) #line
1624#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
1625
1626#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
1627
1628// #included from: internal/catch_interfaces_exception.h
Phil Nash3b80af72012-08-09 07:47:30 +01001629#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTIONS_H_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +01001630
Phil Nash89d1e6c2011-05-24 08:23:02 +01001631#include <string>
Phil Nash3b80af72012-08-09 07:47:30 +01001632// #included from: catch_interfaces_registry_hub.h
1633#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
1634
Phil Nasha70fbe32012-08-31 08:10:36 +01001635// #included from: catch_interfaces_reporter.h
1636#define TWOBLUECUBES_CATCH_IREPORTERREGISTRY_INCLUDED
1637
1638// #included from: catch_config.hpp
1639#define TWOBLUECUBES_CATCH_RUNNERCONFIG_HPP_INCLUDED
1640
1641// #included from: catch_test_spec.h
1642#define TWOBLUECUBES_CATCH_TESTSPEC_H_INCLUDED
1643
1644// #included from: catch_test_case_info.h
1645#define TWOBLUECUBES_CATCH_TESTCASEINFO_H_INCLUDED
1646
1647#include <string>
Phil Nashfc1baac2012-09-15 17:53:27 +01001648#include <set>
Phil Nasha70fbe32012-08-31 08:10:36 +01001649
1650namespace Catch {
1651
1652 struct ITestCase;
1653
1654 class TestCaseInfo {
1655 public:
1656 TestCaseInfo();
1657
1658 TestCaseInfo( ITestCase* testCase,
1659 const char* name,
1660 const char* description,
1661 const SourceLineInfo& lineInfo );
1662
1663 TestCaseInfo( const TestCaseInfo& other, const std::string& name );
1664 TestCaseInfo( const TestCaseInfo& other );
1665
1666 void invoke() const;
1667 const std::string& getName() const;
1668 const std::string& getDescription() const;
1669 const SourceLineInfo& getLineInfo() const;
1670 bool isHidden() const;
Phil Nashfc1baac2012-09-15 17:53:27 +01001671 bool hasTag( const std::string& tag ) const;
Phil Nash799ecf92012-09-24 08:30:13 +01001672 bool matchesTags( const std::string& tagPattern ) const;
Phil Nash67ec8702012-09-26 18:38:26 +01001673 const std::set<std::string>& getTags() const;
Phil Nasha70fbe32012-08-31 08:10:36 +01001674
1675 void swap( TestCaseInfo& other );
1676 bool operator == ( const TestCaseInfo& other ) const;
1677 bool operator < ( const TestCaseInfo& other ) const;
1678 TestCaseInfo& operator = ( const TestCaseInfo& other );
1679
1680 private:
1681 Ptr<ITestCase> m_test;
1682 std::string m_name;
1683 std::string m_description;
Phil Nashfc1baac2012-09-15 17:53:27 +01001684 std::set<std::string> m_tags;
Phil Nasha70fbe32012-08-31 08:10:36 +01001685 SourceLineInfo m_lineInfo;
Phil Nashfc1baac2012-09-15 17:53:27 +01001686 bool m_isHidden;
Phil Nasha70fbe32012-08-31 08:10:36 +01001687 };
1688}
1689
Phil Nash67ec8702012-09-26 18:38:26 +01001690// #included from: catch_tags.hpp
1691#define TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED
1692
1693#include <string>
1694#include <set>
1695#include <map>
1696#include <vector>
1697
1698#ifdef __clang__
1699#pragma clang diagnostic ignored "-Wpadded"
1700#endif
1701
1702namespace Catch {
1703 class TagParser {
1704 public:
1705 virtual ~TagParser();
1706
1707 void parse( const std::string& str ) {
1708 std::size_t pos = 0;
1709 while( pos < str.size() ) {
1710 char c = str[pos];
1711 if( c == '[' ) {
1712 std::size_t end = str.find_first_of( ']', pos );
1713 if( end != std::string::npos ) {
1714 acceptTag( str.substr( pos+1, end-pos-1 ) );
1715 pos = end+1;
1716 }
1717 else {
1718 acceptChar( c );
1719 pos++;
1720 }
1721 }
1722 else {
1723 acceptChar( c );
1724 pos++;
1725 }
1726 }
1727 endParse();
1728 }
1729
1730 protected:
1731 virtual void acceptTag( const std::string& tag ) = 0;
1732 virtual void acceptChar( char c ) = 0;
1733 virtual void endParse() {}
1734
1735 private:
1736 };
1737
1738 class TagExtracter : public TagParser {
1739 public:
1740
1741 TagExtracter( std::set<std::string>& tags )
1742 : m_tags( tags )
1743 {}
1744 virtual ~TagExtracter();
1745
1746 void parse( std::string& description ) {
1747 TagParser::parse( description );
1748 description = m_remainder;
1749 }
1750
1751 private:
1752 virtual void acceptTag( const std::string& tag ) {
1753 m_tags.insert( tag );
1754 }
1755 virtual void acceptChar( char c ) {
1756 m_remainder += c;
1757 }
1758
1759 std::set<std::string>& m_tags;
1760 std::string m_remainder;
1761 };
1762
1763 class Tag {
1764 public:
1765 Tag()
1766 : m_isNegated( false )
1767 {}
1768
1769 Tag( const std::string& name, bool isNegated )
1770 : m_name( name ),
1771 m_isNegated( isNegated )
1772 {}
1773
1774 std::string getName() const {
1775 return m_name;
1776 }
1777 bool isNegated() const {
1778 return m_isNegated;
1779 }
1780
1781 bool operator ! () const {
1782 return m_name.empty();
1783 }
1784
1785 private:
1786 std::string m_name;
1787 bool m_isNegated;
1788 };
1789
1790 class TagSet {
1791 typedef std::map<std::string, Tag> TagMap;
1792 public:
1793 void add( const Tag& tag ) {
1794 m_tags.insert( std::make_pair( tag.getName(), tag ) );
1795 }
1796
1797 // needed?
1798 Tag find( const std::string& name ) const {
1799 TagMap::const_iterator it = m_tags.find( name );
1800 if( it == m_tags.end() )
1801 return Tag();
1802 else
1803 return it->second;
1804 }
1805 bool empty() const {
1806 return m_tags.empty();
1807 }
1808
1809 bool matches( const std::set<std::string>& tags ) const {
1810 TagMap::const_iterator it = m_tags.begin();
1811 TagMap::const_iterator itEnd = m_tags.end();
1812 for(; it != itEnd; ++it ) {
1813 bool found = tags.find( it->first ) != tags.end();
1814 if( found == it->second.isNegated() )
1815 return false;
1816 }
1817 return true;
1818 }
1819
1820 private:
1821 TagMap m_tags;
1822 };
1823
1824 class TagExpression {
1825 public:
1826 bool matches( const std::set<std::string>& tags ) const {
1827 std::vector<TagSet>::const_iterator it = m_tagSets.begin();
1828 std::vector<TagSet>::const_iterator itEnd = m_tagSets.end();
1829 for(; it != itEnd; ++it )
1830 if( it->matches( tags ) )
1831 return true;
1832 return false;
1833 }
1834
1835 private:
1836 friend class TagExpressionParser;
1837
1838 std::vector<TagSet> m_tagSets;
1839 };
1840
1841 class TagExpressionParser : public TagParser {
1842 public:
1843 TagExpressionParser( TagExpression& exp )
1844 : m_isNegated( false ),
1845 m_exp( exp )
1846 {}
1847
1848 ~TagExpressionParser();
1849
1850 private:
1851 virtual void acceptTag( const std::string& tag ) {
1852 m_currentTagSet.add( Tag( tag, m_isNegated ) );
1853 m_isNegated = false;
1854 }
1855 virtual void acceptChar( char c ) {
1856 switch( c ) {
1857 case '~':
1858 m_isNegated = true;
1859 break;
1860 case ',':
1861 m_exp.m_tagSets.push_back( m_currentTagSet );
1862 break;
1863 }
1864 }
1865 virtual void endParse() {
1866 if( !m_currentTagSet.empty() )
1867 m_exp.m_tagSets.push_back( m_currentTagSet );
1868 }
1869
1870 bool m_isNegated;
1871 TagSet m_currentTagSet;
1872 TagExpression& m_exp;
1873 };
1874
1875} // end namespace Catch
1876
Phil Nasha70fbe32012-08-31 08:10:36 +01001877#include <string>
1878#include <vector>
1879
1880namespace Catch {
1881
1882 struct IfFilterMatches{ enum DoWhat {
Phil Nashe2d215e2012-09-07 17:52:35 +01001883 AutoDetectBehaviour,
Phil Nasha70fbe32012-08-31 08:10:36 +01001884 IncludeTests,
1885 ExcludeTests
1886 }; };
1887
1888 class TestCaseFilter {
1889 enum WildcardPosition {
1890 NoWildcard = 0,
1891 WildcardAtStart = 1,
1892 WildcardAtEnd = 2,
1893 WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
1894 };
1895
1896 public:
Phil Nashe2d215e2012-09-07 17:52:35 +01001897 TestCaseFilter( const std::string& testSpec, IfFilterMatches::DoWhat matchBehaviour = IfFilterMatches::AutoDetectBehaviour )
Phil Nasha70fbe32012-08-31 08:10:36 +01001898 : m_stringToMatch( testSpec ),
1899 m_filterType( matchBehaviour ),
1900 m_wildcardPosition( NoWildcard )
1901 {
Phil Nashe2d215e2012-09-07 17:52:35 +01001902 if( m_filterType == IfFilterMatches::AutoDetectBehaviour ) {
1903 if( startsWith( m_stringToMatch, "exclude:" ) ) {
1904 m_stringToMatch = m_stringToMatch.substr( 8 );
1905 m_filterType = IfFilterMatches::ExcludeTests;
1906 }
1907 else if( startsWith( m_stringToMatch, "~" ) ) {
1908 m_stringToMatch = m_stringToMatch.substr( 1 );
1909 m_filterType = IfFilterMatches::ExcludeTests;
1910 }
1911 else {
1912 m_filterType = IfFilterMatches::IncludeTests;
1913 }
1914 }
1915
Phil Nasha70fbe32012-08-31 08:10:36 +01001916 if( m_stringToMatch[0] == '*' ) {
1917 m_stringToMatch = m_stringToMatch.substr( 1 );
1918 m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtStart );
1919 }
1920 if( m_stringToMatch[m_stringToMatch.size()-1] == '*' ) {
1921 m_stringToMatch = m_stringToMatch.substr( 0, m_stringToMatch.size()-1 );
1922 m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtEnd );
1923 }
1924 }
1925
1926 IfFilterMatches::DoWhat getFilterType() const {
1927 return m_filterType;
1928 }
1929
1930 bool shouldInclude( const TestCaseInfo& testCase ) const {
1931 return isMatch( testCase ) == (m_filterType == IfFilterMatches::IncludeTests);
1932 }
1933 private:
1934
1935#ifdef __clang__
1936#pragma clang diagnostic push
1937#pragma clang diagnostic ignored "-Wunreachable-code"
1938#endif
1939
1940 bool isMatch( const TestCaseInfo& testCase ) const {
1941 const std::string& name = testCase.getName();
1942
1943 switch( m_wildcardPosition ) {
1944 case NoWildcard:
1945 return m_stringToMatch == name;
1946 case WildcardAtStart:
1947 return endsWith( name, m_stringToMatch );
1948 case WildcardAtEnd:
1949 return startsWith( name, m_stringToMatch );
1950 case WildcardAtBothEnds:
1951 return contains( name, m_stringToMatch );
1952 }
1953 throw std::logic_error( "Unhandled wildcard type" );
1954 }
1955
1956#ifdef __clang__
1957#pragma clang diagnostic pop
1958#endif
1959
1960 std::string m_stringToMatch;
1961 IfFilterMatches::DoWhat m_filterType;
1962 WildcardPosition m_wildcardPosition;
1963 };
1964
1965 class TestCaseFilters {
1966 public:
1967 TestCaseFilters( const std::string& name ) : m_name( name ) {}
1968
1969 std::string getName() const {
1970 return m_name;
1971 }
1972
1973 void addFilter( const TestCaseFilter& filter ) {
1974 if( filter.getFilterType() == IfFilterMatches::ExcludeTests )
1975 m_exclusionFilters.push_back( filter );
1976 else
1977 m_inclusionFilters.push_back( filter );
1978 }
1979
Phil Nash67ec8702012-09-26 18:38:26 +01001980 void addTags( const std::string& tagPattern ) {
1981 TagExpression exp;
1982 TagExpressionParser( exp ).parse( tagPattern );
1983
1984 m_tagExpressions.push_back( exp );
1985 }
1986
Phil Nasha70fbe32012-08-31 08:10:36 +01001987 bool shouldInclude( const TestCaseInfo& testCase ) const {
Phil Nash67ec8702012-09-26 18:38:26 +01001988 if( !m_tagExpressions.empty() ) {
1989 std::vector<TagExpression>::const_iterator it = m_tagExpressions.begin();
1990 std::vector<TagExpression>::const_iterator itEnd = m_tagExpressions.end();
1991 for(; it != itEnd; ++it )
1992 if( it->matches( testCase.getTags() ) )
1993 break;
1994 if( it == itEnd )
1995 return false;
1996 }
1997
Phil Nasha70fbe32012-08-31 08:10:36 +01001998 if( !m_inclusionFilters.empty() ) {
1999 std::vector<TestCaseFilter>::const_iterator it = m_inclusionFilters.begin();
2000 std::vector<TestCaseFilter>::const_iterator itEnd = m_inclusionFilters.end();
2001 for(; it != itEnd; ++it )
2002 if( it->shouldInclude( testCase ) )
2003 break;
2004 if( it == itEnd )
2005 return false;
2006 }
Phil Nash67ec8702012-09-26 18:38:26 +01002007 else if( m_exclusionFilters.empty() && m_tagExpressions.empty() ) {
Phil Nashfc1baac2012-09-15 17:53:27 +01002008 return !testCase.isHidden();
2009 }
2010
Phil Nasha70fbe32012-08-31 08:10:36 +01002011 std::vector<TestCaseFilter>::const_iterator it = m_exclusionFilters.begin();
2012 std::vector<TestCaseFilter>::const_iterator itEnd = m_exclusionFilters.end();
2013 for(; it != itEnd; ++it )
2014 if( !it->shouldInclude( testCase ) )
2015 return false;
2016 return true;
2017 }
2018 private:
Phil Nash67ec8702012-09-26 18:38:26 +01002019 std::vector<TagExpression> m_tagExpressions;
Phil Nasha70fbe32012-08-31 08:10:36 +01002020 std::vector<TestCaseFilter> m_inclusionFilters;
2021 std::vector<TestCaseFilter> m_exclusionFilters;
2022 std::string m_name;
2023 };
2024
2025}
2026
2027// #included from: catch_interfaces_config.h
2028#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
2029
2030namespace Catch {
2031
2032 struct IConfig {
2033
2034 virtual ~IConfig();
2035
2036 virtual bool allowThrows() const = 0;
2037 };
2038}
2039
Phil Nash67ec8702012-09-26 18:38:26 +01002040// #included from: catch_stream.hpp
2041#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
2042
2043#include <stdexcept>
2044#include <cstdio>
2045
2046namespace Catch {
2047
2048 template<typename WriterF, size_t bufferSize=256>
2049 class StreamBufImpl : public StreamBufBase {
2050 char data[bufferSize];
2051 WriterF m_writer;
2052
2053 public:
2054 StreamBufImpl() {
2055 setp( data, data + sizeof(data) );
2056 }
2057
2058 ~StreamBufImpl() {
2059 sync();
2060 }
2061
2062 private:
2063 int overflow( int c ) {
2064 sync();
2065
2066 if( c != EOF ) {
2067 if( pbase() == epptr() )
2068 m_writer( std::string( 1, static_cast<char>( c ) ) );
2069 else
2070 sputc( static_cast<char>( c ) );
2071 }
2072 return 0;
2073 }
2074
2075 int sync() {
2076 if( pbase() != pptr() ) {
2077 m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
2078 setp( pbase(), epptr() );
2079 }
2080 return 0;
2081 }
2082 };
2083
2084 ///////////////////////////////////////////////////////////////////////////
2085
2086 struct OutputDebugWriter {
2087
2088 void operator()( const std::string &str ) {
2089 writeToDebugConsole( str );
2090 }
2091 };
2092
2093 class Stream {
2094 public:
2095 Stream()
2096 : streamBuf( NULL ), isOwned( false )
2097 {}
2098
2099 Stream( std::streambuf* _streamBuf, bool _isOwned )
2100 : streamBuf( _streamBuf ), isOwned( _isOwned )
2101 {}
2102
2103 void release() {
2104 if( isOwned ) {
2105 delete streamBuf;
2106 streamBuf = NULL;
2107 isOwned = false;
2108 }
2109 }
2110
2111 std::streambuf* streamBuf;
2112
2113 private:
2114 bool isOwned;
2115 };
2116}
2117
Phil Nasha70fbe32012-08-31 08:10:36 +01002118#include <memory>
2119#include <vector>
2120#include <string>
2121#include <iostream>
2122
2123namespace Catch {
2124
2125 struct Include { enum WhichResults {
2126 FailedOnly,
2127 SuccessfulResults
2128 }; };
2129
2130 struct List{ enum What {
2131 None = 0,
2132
2133 Reports = 1,
2134 Tests = 2,
2135 All = 3,
2136
2137 TestNames = 6,
2138
2139 WhatMask = 0xf,
2140
2141 AsText = 0x10,
2142 AsXml = 0x20,
2143
2144 AsMask = 0xf0
2145 }; };
2146
2147 struct ConfigData {
2148
2149 struct WarnAbout { enum What {
2150 Nothing = 0x00,
2151 NoAssertions = 0x01
2152 }; };
2153
2154 ConfigData()
2155 : listSpec( List::None ),
2156 shouldDebugBreak( false ),
2157 includeWhichResults( Include::FailedOnly ),
2158 cutoff( -1 ),
2159 allowThrows( true ),
2160 warnings( WarnAbout::Nothing )
2161 {}
2162
2163 std::string reporter;
2164 std::string outputFilename;
2165 List::What listSpec;
2166 std::vector<TestCaseFilters> filters;
2167 bool shouldDebugBreak;
2168 std::string stream;
2169 Include::WhichResults includeWhichResults;
2170 std::string name;
2171 int cutoff;
2172 bool allowThrows;
2173 WarnAbout::What warnings;
2174 };
2175
2176 class Config : public IConfig {
2177 private:
2178 Config( const Config& other );
2179 Config& operator = ( const Config& other );
2180 virtual void dummy();
2181 public:
2182
2183 Config()
Phil Nash67ec8702012-09-26 18:38:26 +01002184 : m_os( std::cout.rdbuf() )
Phil Nasha70fbe32012-08-31 08:10:36 +01002185 {}
2186
2187 Config( const ConfigData& data )
2188 : m_data( data ),
Phil Nasha70fbe32012-08-31 08:10:36 +01002189 m_os( std::cout.rdbuf() )
2190 {}
2191
2192 virtual ~Config() {
2193 m_os.rdbuf( std::cout.rdbuf() );
Phil Nash67ec8702012-09-26 18:38:26 +01002194 m_stream.release();
Phil Nasha70fbe32012-08-31 08:10:36 +01002195 }
2196
2197 void setFilename( const std::string& filename ) {
2198 m_data.outputFilename = filename;
2199 }
2200
2201 List::What getListSpec( void ) const {
2202 return m_data.listSpec;
2203 }
2204
2205 const std::string& getFilename() const {
2206 return m_data.outputFilename ;
2207 }
2208
2209 List::What listWhat() const {
2210 return static_cast<List::What>( m_data.listSpec & List::WhatMask );
2211 }
2212
2213 List::What listAs() const {
2214 return static_cast<List::What>( m_data.listSpec & List::AsMask );
2215 }
2216
2217 std::string getName() const {
2218 return m_data.name;
2219 }
2220
2221 bool shouldDebugBreak() const {
2222 return m_data.shouldDebugBreak;
2223 }
2224
2225 virtual std::ostream& stream() const {
2226 return m_os;
2227 }
2228
2229 void setStreamBuf( std::streambuf* buf ) {
2230 m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
2231 }
2232
2233 void useStream( const std::string& streamName ) {
Phil Nash67ec8702012-09-26 18:38:26 +01002234 Stream stream = createStream( streamName );
2235 setStreamBuf( stream.streamBuf );
2236 m_stream.release();
2237 m_stream = stream;
Phil Nasha70fbe32012-08-31 08:10:36 +01002238 }
2239
Phil Nashe2d215e2012-09-07 17:52:35 +01002240 void addTestSpec( const std::string& testSpec ) {
2241 TestCaseFilters filters( testSpec );
2242 filters.addFilter( TestCaseFilter( testSpec ) );
2243 m_data.filters.push_back( filters );
2244 }
2245
Phil Nasha70fbe32012-08-31 08:10:36 +01002246 virtual bool includeSuccessfulResults() const {
2247 return m_data.includeWhichResults == Include::SuccessfulResults;
2248 }
2249
2250 int getCutoff() const {
2251 return m_data.cutoff;
2252 }
2253
2254 virtual bool allowThrows() const {
2255 return m_data.allowThrows;
2256 }
2257
2258 const ConfigData& data() const {
2259 return m_data;
2260 }
2261 ConfigData& data() {
2262 return m_data;
2263 }
2264
2265 private:
2266 ConfigData m_data;
2267
2268 // !TBD Move these out of here
Phil Nash67ec8702012-09-26 18:38:26 +01002269 Stream m_stream;
Phil Nasha70fbe32012-08-31 08:10:36 +01002270 mutable std::ostream m_os;
2271 };
2272
2273} // end namespace Catch
2274
2275#include <string>
2276#include <ostream>
2277#include <map>
2278
2279namespace Catch
2280{
2281 struct ReporterConfig
2282 {
2283 ReporterConfig( const std::string& _name,
2284 std::ostream& _stream,
2285 bool _includeSuccessfulResults,
2286 const ConfigData& _fullConfig )
2287 : name( _name ),
2288 stream( _stream ),
2289 includeSuccessfulResults( _includeSuccessfulResults ),
2290 fullConfig( _fullConfig )
2291 {}
2292
Phil Nash799ecf92012-09-24 08:30:13 +01002293 ReporterConfig( const ReporterConfig& other )
2294 : name( other.name ),
2295 stream( other.stream ),
2296 includeSuccessfulResults( other.includeSuccessfulResults ),
2297 fullConfig( other.fullConfig )
2298 {}
2299
Phil Nasha70fbe32012-08-31 08:10:36 +01002300 std::string name;
2301 std::ostream& stream;
2302 bool includeSuccessfulResults;
2303 ConfigData fullConfig;
Phil Nash799ecf92012-09-24 08:30:13 +01002304
2305 private:
2306 void operator=(const ReporterConfig&);
Phil Nasha70fbe32012-08-31 08:10:36 +01002307 };
2308
2309 class TestCaseInfo;
2310 class ResultInfo;
2311
2312 struct IReporter : IShared {
2313 virtual ~IReporter();
2314 virtual bool shouldRedirectStdout() const = 0;
2315 virtual void StartTesting() = 0;
2316 virtual void EndTesting( const Totals& totals ) = 0;
2317 virtual void StartGroup( const std::string& groupName ) = 0;
2318 virtual void EndGroup( const std::string& groupName, const Totals& totals ) = 0;
2319 virtual void StartSection( const std::string& sectionName, const std::string& description ) = 0;
2320 virtual void NoAssertionsInSection( const std::string& sectionName ) = 0;
2321 virtual void NoAssertionsInTestCase( const std::string& testName ) = 0;
2322 virtual void EndSection( const std::string& sectionName, const Counts& assertions ) = 0;
2323 virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0;
2324 virtual void Aborted() = 0;
2325 virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr ) = 0;
2326 virtual void Result( const ResultInfo& result ) = 0;
2327 };
2328
2329 struct IReporterFactory {
2330 virtual ~IReporterFactory();
2331 virtual IReporter* create( const ReporterConfig& config ) const = 0;
2332 virtual std::string getDescription() const = 0;
2333 };
2334
2335 struct IReporterRegistry {
2336 typedef std::map<std::string, IReporterFactory*> FactoryMap;
2337
2338 virtual ~IReporterRegistry();
2339 virtual IReporter* create( const std::string& name, const ReporterConfig& config ) const = 0;
2340 virtual const FactoryMap& getFactories() const = 0;
2341 };
2342
2343 inline std::string trim( const std::string& str ) {
2344 std::string::size_type start = str.find_first_not_of( "\n\r\t " );
2345 std::string::size_type end = str.find_last_not_of( "\n\r\t " );
2346
2347 return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
2348 }
2349}
2350
Phil Nash3b80af72012-08-09 07:47:30 +01002351#include <vector>
Phil Nash3b80af72012-08-09 07:47:30 +01002352
2353namespace Catch {
2354
2355 class TestCaseInfo;
Phil Nash3b80af72012-08-09 07:47:30 +01002356 struct ITestCaseRegistry;
2357 struct IExceptionTranslatorRegistry;
2358 struct IExceptionTranslator;
2359
2360 struct IRegistryHub {
Phil Nasha695eb92012-08-13 07:46:10 +01002361 virtual ~IRegistryHub();
Phil Nash3b80af72012-08-09 07:47:30 +01002362
2363 virtual const IReporterRegistry& getReporterRegistry() const = 0;
2364 virtual const ITestCaseRegistry& getTestCaseRegistry() const = 0;
2365 virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
2366 };
2367
2368 struct IMutableRegistryHub {
Phil Nasha695eb92012-08-13 07:46:10 +01002369 virtual ~IMutableRegistryHub();
Phil Nash3b80af72012-08-09 07:47:30 +01002370 virtual void registerReporter( const std::string& name, IReporterFactory* factory ) = 0;
2371 virtual void registerTest( const TestCaseInfo& testInfo ) = 0;
2372 virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
2373 };
2374
2375 IRegistryHub& getRegistryHub();
2376 IMutableRegistryHub& getMutableRegistryHub();
2377 void cleanUp();
2378}
2379
Phil Nash89d1e6c2011-05-24 08:23:02 +01002380
Phil Nash89d2a3f2012-05-16 15:09:17 +01002381namespace Catch {
2382
Phil Nash89d1e6c2011-05-24 08:23:02 +01002383 typedef std::string(*exceptionTranslateFunction)();
2384
Phil Nash89d2a3f2012-05-16 15:09:17 +01002385 struct IExceptionTranslator {
Phil Nasha695eb92012-08-13 07:46:10 +01002386 virtual ~IExceptionTranslator();
Phil Nash89d1e6c2011-05-24 08:23:02 +01002387 virtual std::string translate() const = 0;
2388 };
2389
Phil Nash89d2a3f2012-05-16 15:09:17 +01002390 struct IExceptionTranslatorRegistry {
Phil Nasha695eb92012-08-13 07:46:10 +01002391 virtual ~IExceptionTranslatorRegistry();
Phil Nash89d1e6c2011-05-24 08:23:02 +01002392
Phil Nash89d2a3f2012-05-16 15:09:17 +01002393 virtual std::string translateActiveException() const = 0;
Phil Nash89d1e6c2011-05-24 08:23:02 +01002394 };
2395
Phil Nash89d2a3f2012-05-16 15:09:17 +01002396 class ExceptionTranslatorRegistrar {
Phil Nash89d1e6c2011-05-24 08:23:02 +01002397 template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01002398 class ExceptionTranslator : public IExceptionTranslator {
Phil Nash89d1e6c2011-05-24 08:23:02 +01002399 public:
2400
Phil Nash89d2a3f2012-05-16 15:09:17 +01002401 ExceptionTranslator( std::string(*translateFunction)( T& ) )
Phil Nash89d1e6c2011-05-24 08:23:02 +01002402 : m_translateFunction( translateFunction )
2403 {}
2404
Phil Nash89d2a3f2012-05-16 15:09:17 +01002405 virtual std::string translate() const {
2406 try {
Phil Nash89d1e6c2011-05-24 08:23:02 +01002407 throw;
2408 }
Phil Nash89d2a3f2012-05-16 15:09:17 +01002409 catch( T& ex ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01002410 return m_translateFunction( ex );
2411 }
2412 }
2413
2414 protected:
2415 std::string(*m_translateFunction)( T& );
2416 };
2417
2418 public:
2419 template<typename T>
Phil Nash89d2a3f2012-05-16 15:09:17 +01002420 ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
Phil Nash3b80af72012-08-09 07:47:30 +01002421 getMutableRegistryHub().registerTranslator
Phil Nash89d1e6c2011-05-24 08:23:02 +01002422 ( new ExceptionTranslator<T>( translateFunction ) );
2423 }
2424 };
2425}
2426
2427///////////////////////////////////////////////////////////////////////////////
2428#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
2429 static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
2430 namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
2431 static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
2432
2433// #included from: internal/catch_approx.hpp
Phil Nash3b80af72012-08-09 07:47:30 +01002434#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +01002435
Phil Nash89d1e6c2011-05-24 08:23:02 +01002436#include <cmath>
2437#include <limits>
2438
Phil Nash89d2a3f2012-05-16 15:09:17 +01002439namespace Catch {
2440namespace Detail {
Phil Nash89d1e6c2011-05-24 08:23:02 +01002441
Phil Nash89d2a3f2012-05-16 15:09:17 +01002442 class Approx {
2443 public:
2444 explicit Approx ( double value )
2445 : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
2446 m_scale( 1.0 ),
2447 m_value( value )
2448 {}
Phil Nashf721a962011-06-07 14:13:57 +01002449
Phil Nash89d2a3f2012-05-16 15:09:17 +01002450 Approx( const Approx& other )
2451 : m_epsilon( other.m_epsilon ),
2452 m_scale( other.m_scale ),
2453 m_value( other.m_value )
2454 {}
Phil Nashf721a962011-06-07 14:13:57 +01002455
Phil Nash89d2a3f2012-05-16 15:09:17 +01002456 static Approx custom() {
2457 return Approx( 0 );
2458 }
Phil Nashf721a962011-06-07 14:13:57 +01002459
Phil Nash89d2a3f2012-05-16 15:09:17 +01002460 Approx operator()( double value ) {
2461 Approx approx( value );
2462 approx.epsilon( m_epsilon );
2463 approx.scale( m_scale );
2464 return approx;
2465 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01002466
Phil Nash89d2a3f2012-05-16 15:09:17 +01002467 friend bool operator == ( double lhs, const Approx& rhs ) {
2468 // Thanks to Richard Harris for his help refining this formula
2469 return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
2470 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01002471
Phil Nash89d2a3f2012-05-16 15:09:17 +01002472 friend bool operator == ( const Approx& lhs, double rhs ) {
2473 return operator==( rhs, lhs );
2474 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01002475
Phil Nash89d2a3f2012-05-16 15:09:17 +01002476 friend bool operator != ( double lhs, const Approx& rhs ) {
2477 return !operator==( lhs, rhs );
2478 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01002479
Phil Nash89d2a3f2012-05-16 15:09:17 +01002480 friend bool operator != ( const Approx& lhs, double rhs ) {
2481 return !operator==( rhs, lhs );
2482 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01002483
Phil Nash89d2a3f2012-05-16 15:09:17 +01002484 Approx& epsilon( double newEpsilon ) {
2485 m_epsilon = newEpsilon;
2486 return *this;
2487 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01002488
Phil Nash89d2a3f2012-05-16 15:09:17 +01002489 Approx& scale( double newScale ) {
2490 m_scale = newScale;
2491 return *this;
2492 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01002493
Phil Nash89d2a3f2012-05-16 15:09:17 +01002494 std::string toString() const {
2495 std::ostringstream oss;
2496 oss << "Approx( " << m_value << ")";
2497 return oss.str();
2498 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01002499
Phil Nash89d2a3f2012-05-16 15:09:17 +01002500 private:
2501 double m_epsilon;
2502 double m_scale;
2503 double m_value;
2504 };
2505}
2506
2507template<>
2508inline std::string toString<Detail::Approx>( const Detail::Approx& value ) {
2509 return value.toString();
2510}
Phil Nash89d1e6c2011-05-24 08:23:02 +01002511
2512} // end namespace Catch
2513
Phil Nash371db8b2012-05-21 18:52:09 +01002514// #included from: internal/catch_matchers.hpp
Phil Nash3b80af72012-08-09 07:47:30 +01002515#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
Phil Nash371db8b2012-05-21 18:52:09 +01002516
2517namespace Catch {
2518namespace Matchers {
2519 namespace Impl {
2520 namespace StdString {
2521
Phil Nasha8570df2012-05-24 08:29:41 +01002522 struct Equals {
2523 Equals( const std::string& str ) : m_str( str ){}
2524
2525 bool operator()( const std::string& str ) const
2526 {
2527 return str == m_str;
2528 }
2529
2530 friend std::ostream& operator<<( std::ostream& os, const Equals& matcher )
2531 {
2532 os << "equals: \"" << matcher.m_str << "\"";
2533 return os;
2534 }
2535 std::string m_str;
2536 };
2537
Phil Nash371db8b2012-05-21 18:52:09 +01002538 struct Contains {
2539 Contains( const std::string& substr ) : m_substr( substr ){}
2540
2541 bool operator()( const std::string& str ) const
2542 {
2543 return str.find( m_substr ) != std::string::npos;
2544 }
2545
2546 friend std::ostream& operator<<( std::ostream& os, const Contains& matcher )
2547 {
2548 os << "contains: \"" << matcher.m_substr << "\"";
2549 return os;
2550 }
2551 std::string m_substr;
2552 };
2553
2554 struct StartsWith {
2555 StartsWith( const std::string& substr ) : m_substr( substr ){}
2556
2557 bool operator()( const std::string& str ) const
2558 {
2559 return str.find( m_substr ) == 0;
2560 }
2561
2562 friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher )
2563 {
2564 os << "starts with: \"" << matcher.m_substr << "\"";
2565 return os;
2566 }
2567 std::string m_substr;
2568 };
2569
2570 struct EndsWith {
2571 EndsWith( const std::string& substr ) : m_substr( substr ){}
2572
2573 bool operator()( const std::string& str ) const
2574 {
2575 return str.find( m_substr ) == str.size() - m_substr.size();
2576 }
2577
2578 friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher )
2579 {
2580 os << "ends with: \"" << matcher.m_substr << "\"";
2581 return os;
2582 }
2583 std::string m_substr;
2584 };
2585 } // namespace StdString
2586 } // namespace Impl
2587
Phil Nasha8570df2012-05-24 08:29:41 +01002588 inline Impl::StdString::Equals Equals( const std::string& str ){ return Impl::StdString::Equals( str ); }
Phil Nash371db8b2012-05-21 18:52:09 +01002589 inline Impl::StdString::Contains Contains( const std::string& substr ){ return Impl::StdString::Contains( substr ); }
2590 inline Impl::StdString::StartsWith StartsWith( const std::string& substr ){ return Impl::StdString::StartsWith( substr ); }
2591 inline Impl::StdString::EndsWith EndsWith( const std::string& substr ){ return Impl::StdString::EndsWith( substr ); }
2592
2593} // namespace Matchers
2594
2595using namespace Matchers;
2596
2597} // namespace Catch
2598
Phil Nash0f9c5512012-06-02 23:12:42 +01002599// These files are included here so the single_include script doesn't put them
2600// in the conditionally compiled sections
Phil Nash0f9c5512012-06-02 23:12:42 +01002601// #included from: internal/catch_interfaces_runner.h
Phil Nash3b80af72012-08-09 07:47:30 +01002602#define TWOBLUECUBES_INTERNAL_CATCH_INTERFACES_RUNNER_H_INCLUDED
Phil Nash0f9c5512012-06-02 23:12:42 +01002603
2604#include <string>
2605
2606namespace Catch {
2607 class TestCaseInfo;
2608
2609 struct IRunner {
Phil Nasha695eb92012-08-13 07:46:10 +01002610 virtual ~IRunner();
Phil Nash0f9c5512012-06-02 23:12:42 +01002611 };
2612}
2613
2614
Phil Nash371db8b2012-05-21 18:52:09 +01002615#ifdef __OBJC__
2616// #included from: internal/catch_objc.hpp
Phil Nash3b80af72012-08-09 07:47:30 +01002617#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
Phil Nash371db8b2012-05-21 18:52:09 +01002618
Phil Nash371db8b2012-05-21 18:52:09 +01002619#import <objc/runtime.h>
2620
2621#include <string>
2622
2623// NB. Any general catch headers included here must be included
2624// in catch.hpp first to make sure they are included by the single
2625// header for non obj-usage
Phil Nash81528252011-08-15 09:06:31 +01002626
Phil Nash83224e62011-08-12 18:53:28 +01002627///////////////////////////////////////////////////////////////////////////////
2628// This protocol is really only here for (self) documenting purposes, since
2629// all its methods are optional.
2630@protocol OcFixture
2631
2632@optional
2633
2634-(void) setUp;
2635-(void) tearDown;
2636
2637@end
2638
Phil Nash89d2a3f2012-05-16 15:09:17 +01002639namespace Catch {
Phil Nash83224e62011-08-12 18:53:28 +01002640
Phil Nash5bc030d2012-08-16 18:48:50 +01002641 class OcMethod : public SharedImpl<ITestCase> {
Phil Nash89d2a3f2012-05-16 15:09:17 +01002642
2643 public:
2644 OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
2645
2646 virtual void invoke() const {
Phil Nash53c990a2012-03-17 18:20:06 +00002647 id obj = [[m_cls alloc] init];
Phil Nash83224e62011-08-12 18:53:28 +01002648
Phil Nash53c990a2012-03-17 18:20:06 +00002649 performOptionalSelector( obj, @selector(setUp) );
2650 performOptionalSelector( obj, m_sel );
2651 performOptionalSelector( obj, @selector(tearDown) );
Phil Nash83224e62011-08-12 18:53:28 +01002652
Phil Nash53c990a2012-03-17 18:20:06 +00002653 arcSafeRelease( obj );
Phil Nash83224e62011-08-12 18:53:28 +01002654 }
Phil Nash83224e62011-08-12 18:53:28 +01002655 private:
Phil Nash5bc030d2012-08-16 18:48:50 +01002656 virtual ~OcMethod() {}
2657
Phil Nash83224e62011-08-12 18:53:28 +01002658 Class m_cls;
2659 SEL m_sel;
2660 };
2661
Phil Nash89d2a3f2012-05-16 15:09:17 +01002662 namespace Detail{
Phil Nash83224e62011-08-12 18:53:28 +01002663
Phil Nash89d2a3f2012-05-16 15:09:17 +01002664 inline bool startsWith( const std::string& str, const std::string& sub ) {
Phil Nash83224e62011-08-12 18:53:28 +01002665 return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
2666 }
2667
Phil Nash89d2a3f2012-05-16 15:09:17 +01002668 inline std::string getAnnotation( Class cls,
2669 const std::string& annotationName,
2670 const std::string& testCaseName ) {
Phil Nash83224e62011-08-12 18:53:28 +01002671 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
2672 SEL sel = NSSelectorFromString( selStr );
Phil Nash53c990a2012-03-17 18:20:06 +00002673 arcSafeRelease( selStr );
2674 id value = performOptionalSelector( cls, sel );
2675 if( value )
2676 return [(NSString*)value UTF8String];
Phil Nash83224e62011-08-12 18:53:28 +01002677 return "";
2678 }
2679 }
2680
Phil Nash89d2a3f2012-05-16 15:09:17 +01002681 inline size_t registerTestMethods() {
Phil Nash83224e62011-08-12 18:53:28 +01002682 size_t noTestMethods = 0;
2683 int noClasses = objc_getClassList( NULL, 0 );
2684
Phil Nash861a1e72012-04-28 12:29:52 +01002685 Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
Phil Nash53c990a2012-03-17 18:20:06 +00002686 objc_getClassList( classes, noClasses );
Phil Nash83224e62011-08-12 18:53:28 +01002687
Phil Nash89d2a3f2012-05-16 15:09:17 +01002688 for( int c = 0; c < noClasses; c++ ) {
Phil Nash83224e62011-08-12 18:53:28 +01002689 Class cls = classes[c];
2690 {
2691 u_int count;
2692 Method* methods = class_copyMethodList( cls, &count );
Phil Nash7004f4a2012-05-22 08:56:59 +01002693 for( u_int m = 0; m < count ; m++ ) {
Phil Nash83224e62011-08-12 18:53:28 +01002694 SEL selector = method_getName(methods[m]);
2695 std::string methodName = sel_getName(selector);
Phil Nash89d2a3f2012-05-16 15:09:17 +01002696 if( Detail::startsWith( methodName, "Catch_TestCase_" ) ) {
Phil Nash83224e62011-08-12 18:53:28 +01002697 std::string testCaseName = methodName.substr( 15 );
Phil Nash53c990a2012-03-17 18:20:06 +00002698 std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
2699 std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
Phil Nash83224e62011-08-12 18:53:28 +01002700
Phil Nash3b80af72012-08-09 07:47:30 +01002701 getMutableRegistryHub().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) );
Phil Nash83224e62011-08-12 18:53:28 +01002702 noTestMethods++;
Phil Nash83224e62011-08-12 18:53:28 +01002703 }
2704 }
2705 free(methods);
2706 }
2707 }
2708 return noTestMethods;
2709 }
Phil Nash78d95a02012-03-04 21:22:36 +00002710
Phil Nash89d2a3f2012-05-16 15:09:17 +01002711 namespace Matchers {
2712 namespace Impl {
2713 namespace NSStringMatchers {
2714
2715 struct StringHolder {
Phil Nash78d95a02012-03-04 21:22:36 +00002716 StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
Phil Nash89d2a3f2012-05-16 15:09:17 +01002717 StringHolder() {
Phil Nash53c990a2012-03-17 18:20:06 +00002718 arcSafeRelease( m_substr );
Phil Nash78d95a02012-03-04 21:22:36 +00002719 }
2720
2721 NSString* m_substr;
2722 };
2723
Phil Nash89d2a3f2012-05-16 15:09:17 +01002724 struct Equals : StringHolder {
Phil Nash8d18d162012-03-14 20:06:14 +00002725 Equals( NSString* substr ) : StringHolder( substr ){}
2726
Phil Nash89d2a3f2012-05-16 15:09:17 +01002727 bool operator()( NSString* str ) const {
Phil Nash8d18d162012-03-14 20:06:14 +00002728 return [str isEqualToString:m_substr];
2729 }
2730
Phil Nash89d2a3f2012-05-16 15:09:17 +01002731 friend std::ostream& operator<<( std::ostream& os, const Equals& matcher ) {
Phil Nash8d18d162012-03-14 20:06:14 +00002732 os << "equals string: " << Catch::toString( matcher.m_substr );
2733 return os;
2734 }
2735 };
2736
Phil Nash89d2a3f2012-05-16 15:09:17 +01002737 struct Contains : StringHolder {
Phil Nash78d95a02012-03-04 21:22:36 +00002738 Contains( NSString* substr ) : StringHolder( substr ){}
2739
Phil Nash89d2a3f2012-05-16 15:09:17 +01002740 bool operator()( NSString* str ) const {
Phil Nash78d95a02012-03-04 21:22:36 +00002741 return [str rangeOfString:m_substr].location != NSNotFound;
2742 }
2743
Phil Nash89d2a3f2012-05-16 15:09:17 +01002744 friend std::ostream& operator<<( std::ostream& os, const Contains& matcher ) {
Phil Nash78d95a02012-03-04 21:22:36 +00002745 os << "contains: " << Catch::toString( matcher.m_substr );
2746 return os;
2747 }
2748 };
2749
Phil Nash89d2a3f2012-05-16 15:09:17 +01002750 struct StartsWith : StringHolder {
Phil Nash78d95a02012-03-04 21:22:36 +00002751 StartsWith( NSString* substr ) : StringHolder( substr ){}
2752
Phil Nash89d2a3f2012-05-16 15:09:17 +01002753 bool operator()( NSString* str ) const {
Phil Nash78d95a02012-03-04 21:22:36 +00002754 return [str rangeOfString:m_substr].location == 0;
2755 }
2756
Phil Nash89d2a3f2012-05-16 15:09:17 +01002757 friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher ) {
Phil Nash78d95a02012-03-04 21:22:36 +00002758 os << "starts with: " << Catch::toString( matcher.m_substr );
2759 return os;
2760 }
2761 };
Phil Nash89d2a3f2012-05-16 15:09:17 +01002762 struct EndsWith : StringHolder {
Phil Nash78d95a02012-03-04 21:22:36 +00002763 EndsWith( NSString* substr ) : StringHolder( substr ){}
2764
Phil Nash89d2a3f2012-05-16 15:09:17 +01002765 bool operator()( NSString* str ) const {
Phil Nash78d95a02012-03-04 21:22:36 +00002766 return [str rangeOfString:m_substr].location == [str length] - [m_substr length];
2767 }
2768
Phil Nash89d2a3f2012-05-16 15:09:17 +01002769 friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher ) {
Phil Nash78d95a02012-03-04 21:22:36 +00002770 os << "ends with: " << Catch::toString( matcher.m_substr );
2771 return os;
2772 }
2773 };
2774
2775 } // namespace NSStringMatchers
2776 } // namespace Impl
2777
Phil Nash8d18d162012-03-14 20:06:14 +00002778 inline Impl::NSStringMatchers::Equals
2779 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
2780
Phil Nash78d95a02012-03-04 21:22:36 +00002781 inline Impl::NSStringMatchers::Contains
2782 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
Phil Nash8d18d162012-03-14 20:06:14 +00002783
Phil Nash78d95a02012-03-04 21:22:36 +00002784 inline Impl::NSStringMatchers::StartsWith
2785 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
Phil Nash8d18d162012-03-14 20:06:14 +00002786
Phil Nash78d95a02012-03-04 21:22:36 +00002787 inline Impl::NSStringMatchers::EndsWith
2788 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
2789
2790 } // namespace Matchers
2791
2792 using namespace Matchers;
2793
2794} // namespace Catch
Phil Nash83224e62011-08-12 18:53:28 +01002795
2796///////////////////////////////////////////////////////////////////////////////
2797#define OC_TEST_CASE( name, desc )\
Phil Nash53c990a2012-03-17 18:20:06 +00002798+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
Phil Nash83224e62011-08-12 18:53:28 +01002799{\
Phil Nash53c990a2012-03-17 18:20:06 +00002800return @ name; \
Phil Nash83224e62011-08-12 18:53:28 +01002801}\
Phil Nash53c990a2012-03-17 18:20:06 +00002802+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
Phil Nash83224e62011-08-12 18:53:28 +01002803{ \
Phil Nash53c990a2012-03-17 18:20:06 +00002804return @ desc; \
Phil Nash83224e62011-08-12 18:53:28 +01002805} \
2806-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
2807
2808#endif
2809
2810#if defined( CATCH_CONFIG_MAIN ) || defined( CATCH_CONFIG_RUNNER )
Phil Nasha695eb92012-08-13 07:46:10 +01002811// #included from: internal/catch_impl.hpp
2812
2813// Collect all the implementation files together here
2814// These are the equivalent of what would usually be cpp files
2815
Phil Nash5bc030d2012-08-16 18:48:50 +01002816#ifdef __clang__
Phil Nasha695eb92012-08-13 07:46:10 +01002817#pragma clang diagnostic push
2818#pragma clang diagnostic ignored "-Wweak-vtables"
Phil Nash5bc030d2012-08-16 18:48:50 +01002819#endif
Phil Nasha695eb92012-08-13 07:46:10 +01002820
Phil Nash83224e62011-08-12 18:53:28 +01002821// #included from: catch_runner.hpp
Phil Nash3b80af72012-08-09 07:47:30 +01002822#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
Phil Nash83224e62011-08-12 18:53:28 +01002823
Phil Nasha695eb92012-08-13 07:46:10 +01002824// #included from: internal/catch_commandline.hpp
2825#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
2826
Phil Nasha695eb92012-08-13 07:46:10 +01002827namespace Catch {
2828
2829 class Command {
2830 public:
2831 Command(){}
2832
Phil Nashecf934b2012-08-27 21:42:55 +01002833 explicit Command( const std::string& name ) : m_name( name ) {
2834 }
Phil Nasha695eb92012-08-13 07:46:10 +01002835
2836 Command& operator += ( const std::string& arg ) {
2837 m_args.push_back( arg );
2838 return *this;
2839 }
2840 Command& operator += ( const Command& other ) {
2841 std::copy( other.m_args.begin(), other.m_args.end(), std::back_inserter( m_args ) );
2842 if( m_name.empty() )
2843 m_name = other.m_name;
2844 return *this;
2845 }
2846 Command operator + ( const Command& other ) {
2847 Command newCommand( *this );
2848 newCommand += other;
2849 return newCommand;
2850 }
2851
2852 operator SafeBool::type() const {
Phil Nashe571e6f2012-08-24 18:54:56 +01002853 return SafeBool::makeSafe( !m_name.empty() || !m_args.empty() );
Phil Nasha695eb92012-08-13 07:46:10 +01002854 }
2855
2856 std::string name() const { return m_name; }
2857 std::string operator[]( std::size_t i ) const { return m_args[i]; }
2858 std::size_t argsCount() const { return m_args.size(); }
2859
2860 CATCH_ATTRIBUTE_NORETURN
2861 void raiseError( const std::string& message ) const {
2862 std::ostringstream oss;
Phil Nashecf934b2012-08-27 21:42:55 +01002863 if( m_name.empty() )
2864 oss << "Error while parsing " << m_name << ". " << message << ".";
2865 else
2866 oss << "Error while parsing arguments. " << message << ".";
2867
Phil Nasha695eb92012-08-13 07:46:10 +01002868 if( m_args.size() > 0 )
Phil Nashecf934b2012-08-27 21:42:55 +01002869 oss << " Arguments were:";
Phil Nasha695eb92012-08-13 07:46:10 +01002870 for( std::size_t i = 0; i < m_args.size(); ++i )
2871 oss << " " << m_args[i];
2872 throw std::domain_error( oss.str() );
2873 }
2874
2875 private:
2876
2877 std::string m_name;
2878 std::vector<std::string> m_args;
2879 };
2880
2881 class CommandParser {
2882 public:
2883 CommandParser( int argc, char const * const * argv ) : m_argc( static_cast<std::size_t>( argc ) ), m_argv( argv ) {}
2884
Phil Nashe2d215e2012-09-07 17:52:35 +01002885 std::string exeName() const {
2886 return m_argv[0];
2887 }
Phil Nasha695eb92012-08-13 07:46:10 +01002888 Command find( const std::string& arg1, const std::string& arg2, const std::string& arg3 ) const {
2889 return find( arg1 ) + find( arg2 ) + find( arg3 );
2890 }
2891
2892 Command find( const std::string& shortArg, const std::string& longArg ) const {
2893 return find( shortArg ) + find( longArg );
2894 }
2895 Command find( const std::string& arg ) const {
Phil Nashecf934b2012-08-27 21:42:55 +01002896 if( arg.empty() )
2897 return getArgs( "", 1 );
2898 else
2899 for( std::size_t i = 1; i < m_argc; ++i )
2900 if( m_argv[i] == arg )
2901 return getArgs( m_argv[i], i+1 );
Phil Nasha695eb92012-08-13 07:46:10 +01002902 return Command();
2903 }
Phil Nashe571e6f2012-08-24 18:54:56 +01002904 Command getDefaultArgs() const {
2905 return getArgs( "", 1 );
2906 }
Phil Nasha695eb92012-08-13 07:46:10 +01002907
2908 private:
Phil Nashe571e6f2012-08-24 18:54:56 +01002909 Command getArgs( const std::string& cmdName, std::size_t from ) const {
2910 Command command( cmdName );
2911 for( std::size_t i = from; i < m_argc && m_argv[i][0] != '-'; ++i )
Phil Nasha695eb92012-08-13 07:46:10 +01002912 command += m_argv[i];
2913 return command;
2914 }
2915
2916 std::size_t m_argc;
2917 char const * const * m_argv;
2918 };
2919
Phil Nashecf934b2012-08-27 21:42:55 +01002920 class OptionParser : public SharedImpl<IShared> {
2921 public:
2922 OptionParser( int minArgs = 0, int maxArgs = 0 )
2923 : m_minArgs( minArgs ), m_maxArgs( maxArgs )
2924 {}
Phil Nasha695eb92012-08-13 07:46:10 +01002925
Phil Nashecf934b2012-08-27 21:42:55 +01002926 virtual ~OptionParser() {}
Phil Nasha695eb92012-08-13 07:46:10 +01002927
Phil Nashecf934b2012-08-27 21:42:55 +01002928 Command find( const CommandParser& parser ) const {
2929 Command cmd;
2930 for( std::vector<std::string>::const_iterator it = m_optionNames.begin();
2931 it != m_optionNames.end();
2932 ++it )
2933 cmd += parser.find( *it );
2934 return cmd;
2935 }
2936
2937 void validateArgs( const Command& args ) const {
2938 if( tooFewArgs( args ) || tooManyArgs( args ) ) {
2939 std::ostringstream oss;
2940 if( m_maxArgs == -1 )
2941 oss <<"Expected at least " << pluralise( static_cast<std::size_t>( m_minArgs ), "argument" );
2942 else if( m_minArgs == m_maxArgs )
2943 oss <<"Expected " << pluralise( static_cast<std::size_t>( m_minArgs ), "argument" );
Phil Nasha695eb92012-08-13 07:46:10 +01002944 else
Phil Nashecf934b2012-08-27 21:42:55 +01002945 oss <<"Expected between " << m_minArgs << " and " << m_maxArgs << " argument";
2946 args.raiseError( oss.str() );
Phil Nasha695eb92012-08-13 07:46:10 +01002947 }
Phil Nashecf934b2012-08-27 21:42:55 +01002948 }
2949
2950 void parseIntoConfig( const CommandParser& parser, ConfigData& config ) {
2951 if( Command cmd = find( parser ) ) {
2952 validateArgs( cmd );
2953 parseIntoConfig( cmd, config );
2954 }
2955 }
2956
2957 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) = 0;
2958 virtual std::string argsSynopsis() const = 0;
2959 virtual std::string optionSummary() const = 0;
Phil Nashe2d215e2012-09-07 17:52:35 +01002960 virtual std::string optionDescription() const { return ""; };
Phil Nashecf934b2012-08-27 21:42:55 +01002961
2962 std::string optionNames() const {
2963 std::string names;
2964 for( std::vector<std::string>::const_iterator it = m_optionNames.begin();
2965 it != m_optionNames.end();
2966 ++it ) {
2967 if( !it->empty() ) {
2968 if( !names.empty() )
2969 names += ", ";
2970 names += *it;
2971 }
2972 else {
2973 names = "[" + names;
2974 }
2975 }
2976 if( names[0] == '[' )
2977 names += "]";
2978 return names;
2979 }
2980
2981 protected:
2982
2983 bool tooFewArgs( const Command& args ) const {
2984 return args.argsCount() < static_cast<std::size_t>( m_minArgs );
2985 }
2986 bool tooManyArgs( const Command& args ) const {
2987 return m_maxArgs >= 0 && args.argsCount() > static_cast<std::size_t>( m_maxArgs );
2988 }
2989 std::vector<std::string> m_optionNames;
2990 int m_minArgs;
2991 int m_maxArgs;
2992 };
2993
2994 namespace Options {
2995
2996 class HelpOptionParser : public OptionParser {
2997 public:
2998 HelpOptionParser() {
2999 m_optionNames.push_back( "-?" );
3000 m_optionNames.push_back( "-h" );
3001 m_optionNames.push_back( "--help" );
3002 }
3003 virtual std::string argsSynopsis() const {
Phil Nash67ec8702012-09-26 18:38:26 +01003004 return "[<option for help on> ...]";
Phil Nashecf934b2012-08-27 21:42:55 +01003005 }
3006 virtual std::string optionSummary() const {
Phil Nash67ec8702012-09-26 18:38:26 +01003007 return "Shows this usage summary, or help on a specific option, or options, if supplied";
Phil Nashe2d215e2012-09-07 17:52:35 +01003008 }
3009 virtual std::string optionDescription() const {
3010 return "";
Phil Nashecf934b2012-08-27 21:42:55 +01003011 }
3012
3013 virtual void parseIntoConfig( const Command&, ConfigData& ) {
3014 // Does not affect config
3015 }
3016 };
3017
3018 class TestCaseOptionParser : public OptionParser {
3019 public:
3020 TestCaseOptionParser() : OptionParser( 1, -1 ) {
3021 m_optionNames.push_back( "-t" );
3022 m_optionNames.push_back( "--test" );
3023 m_optionNames.push_back( "" ); // default option
3024 }
3025 virtual std::string argsSynopsis() const {
3026 return "<testspec> [<testspec>...]";
3027 }
3028 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003029 return "Specifies which test case or cases to run";
3030 }
3031
3032 // Lines are split at the nearest prior space char to the 80 char column.
3033 // Tab chars are removed from the output but their positions are used to align
3034 // subsequently wrapped lines
3035 virtual std::string optionDescription() const {
Phil Nashf7418eb2012-09-09 11:44:30 +01003036 return
3037 "This option allows one ore more test specs to be supplied. Each spec either fully "
3038 "specifies a test case or is a pattern containing wildcards to match a set of test "
3039 "cases. If this option is not provided then all test cases, except those prefixed "
3040 "by './' are run\n"
3041 "\n"
3042 "Specs must be enclosed in \"quotes\" if they contain spaces. If they do not "
3043 "contain spaces the quotes are optional.\n"
3044 "\n"
3045 "Wildcards consist of the * character at the beginning, end, or both and can substitute for "
3046 "any number of any characters (including none)\n"
3047 "\n"
3048 "If spec is prefixed with exclude: or the ~ character then the pattern matches an exclusion. "
3049 "This means that tests matching the pattern are excluded from the set - even if a prior "
Phil Nash799ecf92012-09-24 08:30:13 +01003050 "inclusion spec included them. Subsequent inclusion specs will take precedence, however. "
Phil Nashf7418eb2012-09-09 11:44:30 +01003051 "Inclusions and exclusions are evaluated in left-to-right order.\n"
3052 "\n"
3053 "Examples:\n"
3054 "\n"
3055 " -t thisTestOnly \tMatches the test case called, 'thisTestOnly'\n"
3056 " -t \"this test only\" \tMatches the test case called, 'this test only'\n"
3057 " -t these/* \tMatches all cases starting with 'these/'\n"
3058 " -t exclude:notThis \tMatches all tests except, 'notThis'\n"
3059 " -t ~notThis \tMatches all tests except, 'notThis'\n"
3060 " -t ~*private* \tMatches all tests except those that contain 'private'\n"
3061 " -t a/* ~a/b/* a/b/c \tMatches all tests that start with 'a/', except those "
3062 "that start with 'a/b/', except 'a/b/c', which is included";
Phil Nashecf934b2012-08-27 21:42:55 +01003063 }
3064
3065 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
3066 std::string groupName;
3067 for( std::size_t i = 0; i < cmd.argsCount(); ++i ) {
3068 if( i != 0 )
3069 groupName += " ";
3070 groupName += cmd[i];
3071 }
3072 TestCaseFilters filters( groupName );
Phil Nashe2d215e2012-09-07 17:52:35 +01003073 for( std::size_t i = 0; i < cmd.argsCount(); ++i )
3074 filters.addFilter( TestCaseFilter( cmd[i] ) );
Phil Nashecf934b2012-08-27 21:42:55 +01003075 config.filters.push_back( filters );
3076 }
3077 };
3078
Phil Nash799ecf92012-09-24 08:30:13 +01003079 class TagOptionParser : public OptionParser {
3080 public:
3081 TagOptionParser() : OptionParser( 1, -1 ) {
3082 m_optionNames.push_back( "-g" );
3083 m_optionNames.push_back( "--tag" );
3084 }
3085 virtual std::string argsSynopsis() const {
3086 return "<tagspec> [,<tagspec>...]";
3087 }
3088 virtual std::string optionSummary() const {
3089 return "Matches test cases against tags or tag patterns";
3090 }
3091
3092 // Lines are split at the nearest prior space char to the 80 char column.
3093 // Tab chars are removed from the output but their positions are used to align
3094 // subsequently wrapped lines
3095 virtual std::string optionDescription() const {
3096 return
3097 "!TBD";
3098 }
3099
3100 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
Phil Nash67ec8702012-09-26 18:38:26 +01003101 std::string groupName;
3102 for( std::size_t i = 0; i < cmd.argsCount(); ++i ) {
3103 if( i != 0 )
3104 groupName += " ";
3105 groupName += cmd[i];
3106 }
3107 TestCaseFilters filters( groupName );
3108 for( std::size_t i = 0; i < cmd.argsCount(); ++i )
3109 filters.addTags( cmd[i] );
3110 config.filters.push_back( filters );
Phil Nash799ecf92012-09-24 08:30:13 +01003111 }
3112 };
3113
Phil Nashecf934b2012-08-27 21:42:55 +01003114 class ListOptionParser : public OptionParser {
3115 public:
3116 ListOptionParser() : OptionParser( 0, 2 ) {
3117 m_optionNames.push_back( "-l" );
3118 m_optionNames.push_back( "--list" );
3119 }
3120 virtual std::string argsSynopsis() const {
3121 return "[all | tests | reporters [xml]]";
3122 }
3123 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003124 return "Lists available tests or reporters";
3125 }
3126
3127 virtual std::string optionDescription() const {
Phil Nashf7418eb2012-09-09 11:44:30 +01003128 return
3129 "With no arguments this option will list all registered tests - one per line.\n"
3130 "Supplying the xml argument formats the list as an xml document (which may be useful for "
3131 "consumption by other tools).\n"
3132 "Supplying the tests or reporters lists tests or reporters respectively - with descriptions.\n"
3133 "\n"
3134 "Examples:\n"
3135 "\n"
3136 " -l\n"
3137 " -l tests\n"
3138 " -l reporters xml\n"
3139 " -l xml";
Phil Nashecf934b2012-08-27 21:42:55 +01003140 }
3141
3142 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
3143 config.listSpec = List::TestNames;
3144 if( cmd.argsCount() >= 1 ) {
3145 if( cmd[0] == "all" )
3146 config.listSpec = List::All;
3147 else if( cmd[0] == "tests" )
3148 config.listSpec = List::Tests;
3149 else if( cmd[0] == "reporters" )
3150 config.listSpec = List::Reports;
3151 else
3152 cmd.raiseError( "Expected [tests] or [reporters]" );
3153 }
3154 if( cmd.argsCount() >= 2 ) {
3155 if( cmd[1] == "xml" )
3156 config.listSpec = static_cast<List::What>( config.listSpec | List::AsXml );
3157 else if( cmd[1] == "text" )
3158 config.listSpec = static_cast<List::What>( config.listSpec | List::AsText );
3159 else
3160 cmd.raiseError( "Expected [xml] or [text]" );
3161 }
3162 }
3163 };
3164
3165 class ReporterOptionParser : public OptionParser {
3166 public:
3167 ReporterOptionParser() : OptionParser( 1, 1 ) {
3168 m_optionNames.push_back( "-r" );
3169 m_optionNames.push_back( "--reporter" );
3170 }
3171 virtual std::string argsSynopsis() const {
3172 return "<reporter name>";
3173 }
3174 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003175 return "Specifies type of reporter";
3176 }
3177
3178 virtual std::string optionDescription() const {
Phil Nashf7418eb2012-09-09 11:44:30 +01003179 return
3180 "A reporter is an object that formats and structures the output of running "
3181 "tests, and potentially summarises the results. By default a basic reporter "
3182 "is used that writes IDE friendly results. CATCH comes bundled with some "
3183 "alternative reporters, but more can be added in client code.\n"
3184 "\n"
3185 "The bundled reporters are:\n"
3186 " -r basic\n"
3187 " -r xml\n"
3188 " -r junit\n"
3189 "\n"
3190 "The JUnit reporter is an xml format that follows the structure of the JUnit "
3191 "XML Report ANT task, as consumed by a number of third-party tools, "
3192 "including Continuous Integration servers such as Jenkins.\n"
3193 "If not otherwise needed, the standard XML reporter is preferred as this is "
3194 "a streaming reporter, whereas the Junit reporter needs to hold all its "
3195 "results until the end so it can write the overall results into attributes "
3196 "of the root node.";
Phil Nashecf934b2012-08-27 21:42:55 +01003197 }
3198
3199 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
3200 config.reporter = cmd[0];
3201 }
3202 };
3203
3204 class OutputOptionParser : public OptionParser {
3205 public:
3206 OutputOptionParser() : OptionParser( 1, 1 ) {
3207 m_optionNames.push_back( "-o" );
3208 m_optionNames.push_back( "--out" );
3209 }
3210 virtual std::string argsSynopsis() const {
3211 return "<file name>|<%stream name>";
3212 }
3213 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003214 return "Sends output to a file or stream";
Phil Nashecf934b2012-08-27 21:42:55 +01003215 }
Phil Nashf7418eb2012-09-09 11:44:30 +01003216 virtual std::string optionDescription() const {
3217 return
3218 "Use this option to send all output to a file or a stream. By default output is "
Phil Nash799ecf92012-09-24 08:30:13 +01003219 "sent to stdout (note that uses of stdout and stderr from within test cases are "
Phil Nashf7418eb2012-09-09 11:44:30 +01003220 "redirected and included in the report - so even stderr will effectively end up "
Phil Nash799ecf92012-09-24 08:30:13 +01003221 "on stdout). If the name begins with % it is interpreted as a stream. "
Phil Nashf7418eb2012-09-09 11:44:30 +01003222 "Otherwise it is treated as a filename.\n"
3223 "\n"
3224 "Examples are:\n"
3225 "\n"
3226 " -o filename.txt\n"
3227 " -o \"long filename.txt\"\n"
3228 " -o %stdout\n"
3229 " -o %stderr\n"
3230 " -o %debug \t(The IDE's debug output window - currently only Windows' "
3231 "OutputDebugString is supported).";
3232 }
Phil Nashecf934b2012-08-27 21:42:55 +01003233 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
3234 if( cmd[0][0] == '%' )
3235 config.stream = cmd[0].substr( 1 );
Phil Nasha695eb92012-08-13 07:46:10 +01003236 else
Phil Nashecf934b2012-08-27 21:42:55 +01003237 config.outputFilename = cmd[0];
Phil Nasha695eb92012-08-13 07:46:10 +01003238 }
Phil Nashecf934b2012-08-27 21:42:55 +01003239 };
Phil Nasha695eb92012-08-13 07:46:10 +01003240
Phil Nashf7418eb2012-09-09 11:44:30 +01003241 class SuccessOptionParser : public OptionParser {
Phil Nashecf934b2012-08-27 21:42:55 +01003242 public:
Phil Nashf7418eb2012-09-09 11:44:30 +01003243 SuccessOptionParser() {
Phil Nashecf934b2012-08-27 21:42:55 +01003244 m_optionNames.push_back( "-s" );
3245 m_optionNames.push_back( "--success" );
Phil Nash56d5c422012-08-23 20:08:50 +01003246 }
Phil Nashecf934b2012-08-27 21:42:55 +01003247 virtual std::string argsSynopsis() const {
3248 return "";
Phil Nash56d5c422012-08-23 20:08:50 +01003249 }
Phil Nashecf934b2012-08-27 21:42:55 +01003250 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003251 return "Shows results for successful tests";
Phil Nasha695eb92012-08-13 07:46:10 +01003252 }
Phil Nashf7418eb2012-09-09 11:44:30 +01003253 virtual std::string optionDescription() const {
3254 return
3255 "Usually you only want to see reporting for failed tests. Sometimes it's useful "
3256 "to see all the output (especially when you don't trust that that test you just "
Phil Nash799ecf92012-09-24 08:30:13 +01003257 "added worked first time!). To see successful, as well as failing, test results "
Phil Nashf7418eb2012-09-09 11:44:30 +01003258 "just pass this option.";
3259 }
Phil Nash78c92e62012-08-27 21:48:15 +01003260 virtual void parseIntoConfig( const Command&, ConfigData& config ) {
Phil Nashecf934b2012-08-27 21:42:55 +01003261 config.includeWhichResults = Include::SuccessfulResults;
3262 }
3263 };
Phil Nasha695eb92012-08-13 07:46:10 +01003264
Phil Nashecf934b2012-08-27 21:42:55 +01003265 class DebugBreakOptionParser : public OptionParser {
3266 public:
3267 DebugBreakOptionParser() {
3268 m_optionNames.push_back( "-b" );
3269 m_optionNames.push_back( "--break" );
3270 }
3271 virtual std::string argsSynopsis() const {
3272 return "";
3273 }
3274 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003275 return "Breaks into the debugger on failure";
Phil Nashecf934b2012-08-27 21:42:55 +01003276 }
Phil Nashf7418eb2012-09-09 11:44:30 +01003277 virtual std::string optionDescription() const {
3278 return
3279 "In some IDEs (currently XCode and Visual Studio) it is possible for CATCH to "
3280 "break into the debugger on a test failure. This can be very helpful during "
3281 "debug sessions - especially when there is more than one path through a "
3282 "particular test. In addition to the command line option, ensure you have "
3283 "built your code with the DEBUG preprocessor symbol";
3284 }
Phil Nashecf934b2012-08-27 21:42:55 +01003285
Phil Nash78c92e62012-08-27 21:48:15 +01003286 virtual void parseIntoConfig( const Command&, ConfigData& config ) {
Phil Nashecf934b2012-08-27 21:42:55 +01003287 config.shouldDebugBreak = true;
3288 }
3289 };
3290
3291 class NameOptionParser : public OptionParser {
3292 public:
3293 NameOptionParser() : OptionParser( 1, 1 ) {
3294 m_optionNames.push_back( "-n" );
3295 m_optionNames.push_back( "--name" );
3296 }
3297 virtual std::string argsSynopsis() const {
3298 return "<name>";
3299 }
3300 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003301 return "Names a test run";
Phil Nashecf934b2012-08-27 21:42:55 +01003302 }
Phil Nashf7418eb2012-09-09 11:44:30 +01003303 virtual std::string optionDescription() const {
3304 return
3305 "If a name is supplied it will be used by the reporter to provide an overall "
3306 "name for the test run. This can be useful if you are sending to a file, for "
3307 "example, and need to distinguish different test runs - either from different "
3308 "Catch executables or runs of the same executable with different options.\n"
3309 "\n"
3310 "Examples:\n"
3311 "\n"
3312 " -n testRun\n"
3313 " -n \"tests of the widget component\"";
3314 }
Phil Nashecf934b2012-08-27 21:42:55 +01003315
3316 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
3317 config.name = cmd[0];
3318 }
3319 };
3320
3321 class AbortOptionParser : public OptionParser {
3322 public:
3323 AbortOptionParser() : OptionParser( 0, 1 ) {
3324 m_optionNames.push_back( "-a" );
3325 m_optionNames.push_back( "--abort" );
3326 }
3327 virtual std::string argsSynopsis() const {
3328 return "[#]";
3329 }
3330 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003331 return "Aborts after a certain number of failures";
Phil Nashecf934b2012-08-27 21:42:55 +01003332 }
Phil Nashf7418eb2012-09-09 11:44:30 +01003333 virtual std::string optionDescription() const {
3334 return
3335 "If a REQUIRE assertion fails the test case aborts, but subsequent test cases "
3336 "are still run. If a CHECK assertion fails even the current test case is not "
3337 "aborted.\n"
3338 "\n"
3339 "Sometimes this results in a flood of failure messages and you'd rather just "
3340 "see the first few. Specifying -a or --abort on its own will abort the whole "
3341 "test run on the first failed assertion of any kind. Following it with a "
3342 "number causes it to abort after that number of assertion failures.";
3343 }
Phil Nashecf934b2012-08-27 21:42:55 +01003344
3345 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
3346 int threshold = 1;
3347 if( cmd.argsCount() == 1 ) {
3348 std::stringstream ss;
3349 ss << cmd[0];
3350 ss >> threshold;
3351 if( ss.fail() || threshold <= 0 )
3352 cmd.raiseError( "threshold must be a number greater than zero" );
3353 }
3354 config.cutoff = threshold;
3355 }
3356 };
3357
3358 class NoThrowOptionParser : public OptionParser {
3359 public:
3360 NoThrowOptionParser() {
3361 m_optionNames.push_back( "-nt" );
3362 m_optionNames.push_back( "--nothrow" );
3363 }
3364 virtual std::string argsSynopsis() const {
3365 return "";
3366 }
3367 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003368 return "Elides assertions expected to throw";
Phil Nashecf934b2012-08-27 21:42:55 +01003369 }
Phil Nashf7418eb2012-09-09 11:44:30 +01003370 virtual std::string optionDescription() const {
3371 return
3372 "Skips all assertions that test that an exception is thrown, "
3373 "e.g. REQUIRE_THROWS.\n"
3374 "\n"
3375 "These can be a nuisance in certain debugging environments that may break when "
3376 "exceptions are thrown (while this is usually optional for handled exceptions, "
3377 "it can be useful to have enabled if you are trying to track down something "
3378 "unexpected).\n"
3379 "\n"
3380 "When running with this option the throw checking assertions are skipped so "
3381 "as not to contribute additional noise.";
3382 }
Phil Nashecf934b2012-08-27 21:42:55 +01003383
Phil Nash78c92e62012-08-27 21:48:15 +01003384 virtual void parseIntoConfig( const Command&, ConfigData& config ) {
Phil Nashecf934b2012-08-27 21:42:55 +01003385 config.allowThrows = false;
3386 }
3387 };
Phil Nasha70fbe32012-08-31 08:10:36 +01003388
3389 class WarningsOptionParser : public OptionParser {
3390 public:
3391 WarningsOptionParser() : OptionParser( 1, -1 ) {
3392 m_optionNames.push_back( "-w" );
3393 m_optionNames.push_back( "--warnings" );
3394 }
3395 virtual std::string argsSynopsis() const {
3396 return "<warning>";
3397 }
3398 virtual std::string optionSummary() const {
Phil Nashe2d215e2012-09-07 17:52:35 +01003399 return "Enable warnings";
Phil Nasha70fbe32012-08-31 08:10:36 +01003400 }
Phil Nashf7418eb2012-09-09 11:44:30 +01003401 virtual std::string optionDescription() const {
3402 return
3403 "Enables the named warnings. If the warnings are violated the test case is "
3404 "failed.\n"
3405 "\n"
3406 "At present only one warning has been provided: NoAssertions. If this warning "
3407 "is enabled then any test case that completes without an assertions (CHECK, "
3408 "REQUIRE etc) being encountered violates the warning.\n"
3409 "\n"
3410 "e.g.:\n"
3411 "\n"
3412 " -w NoAssertions";
3413 }
Phil Nasha70fbe32012-08-31 08:10:36 +01003414
3415 virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
3416 for( std::size_t i = 0; i < cmd.argsCount(); ++i ) {
3417 if( cmd[i] == "NoAssertions" )
3418 config.warnings = (ConfigData::WarnAbout::What)( config.warnings | ConfigData::WarnAbout::NoAssertions );
3419 else
3420 cmd.raiseError( "Unrecognised warning: " + cmd[i] );
3421 }
3422 }
3423 };
Phil Nasha695eb92012-08-13 07:46:10 +01003424 }
3425
Phil Nashecf934b2012-08-27 21:42:55 +01003426 class AllOptions
3427 {
3428 public:
3429 typedef std::vector<Ptr<OptionParser> > Parsers;
3430 typedef Parsers::const_iterator const_iterator;
3431 typedef Parsers::const_iterator iterator;
3432
3433 AllOptions() {
Phil Nasha70fbe32012-08-31 08:10:36 +01003434 add<Options::TestCaseOptionParser>(); // Keep this one first
3435
Phil Nash67ec8702012-09-26 18:38:26 +01003436 add<Options::TagOptionParser>();
Phil Nashecf934b2012-08-27 21:42:55 +01003437 add<Options::ListOptionParser>();
3438 add<Options::ReporterOptionParser>();
3439 add<Options::OutputOptionParser>();
Phil Nashf7418eb2012-09-09 11:44:30 +01003440 add<Options::SuccessOptionParser>();
Phil Nashecf934b2012-08-27 21:42:55 +01003441 add<Options::DebugBreakOptionParser>();
3442 add<Options::NameOptionParser>();
3443 add<Options::AbortOptionParser>();
3444 add<Options::NoThrowOptionParser>();
Phil Nasha70fbe32012-08-31 08:10:36 +01003445 add<Options::WarningsOptionParser>();
3446
3447 add<Options::HelpOptionParser>(); // Keep this one last
Phil Nashecf934b2012-08-27 21:42:55 +01003448 }
3449
3450 void parseIntoConfig( const CommandParser& parser, ConfigData& config ) {
3451 for( const_iterator it = m_parsers.begin(); it != m_parsers.end(); ++it )
3452 (*it)->parseIntoConfig( parser, config );
3453 }
3454
3455 const_iterator begin() const {
3456 return m_parsers.begin();
3457 }
3458 const_iterator end() const {
3459 return m_parsers.end();
3460 }
3461 private:
3462
3463 template<typename T>
3464 void add() {
3465 m_parsers.push_back( new T() );
3466 }
3467 Parsers m_parsers;
3468
3469 };
3470
Phil Nasha695eb92012-08-13 07:46:10 +01003471} // end namespace Catch
3472
3473// #included from: internal/catch_list.hpp
3474#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
3475
3476#include <limits>
3477
3478namespace Catch {
Phil Nash56d5c422012-08-23 20:08:50 +01003479 inline bool matchesFilters( const std::vector<TestCaseFilters>& filters, const TestCaseInfo& testCase ) {
3480 std::vector<TestCaseFilters>::const_iterator it = filters.begin();
3481 std::vector<TestCaseFilters>::const_iterator itEnd = filters.end();
3482 for(; it != itEnd; ++it )
3483 if( !it->shouldInclude( testCase ) )
3484 return false;
3485 return true;
3486 }
3487 inline void List( const ConfigData& config ) {
Phil Nasha695eb92012-08-13 07:46:10 +01003488
Phil Nash5bc030d2012-08-16 18:48:50 +01003489 if( config.listSpec & List::Reports ) {
Phil Nasha695eb92012-08-13 07:46:10 +01003490 std::cout << "Available reports:\n";
3491 IReporterRegistry::FactoryMap::const_iterator it = getRegistryHub().getReporterRegistry().getFactories().begin();
3492 IReporterRegistry::FactoryMap::const_iterator itEnd = getRegistryHub().getReporterRegistry().getFactories().end();
3493 for(; it != itEnd; ++it ) {
3494 // !TBD: consider listAs()
3495 std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n";
3496 }
3497 std::cout << std::endl;
3498 }
3499
Phil Nash5bc030d2012-08-16 18:48:50 +01003500 if( config.listSpec & List::Tests ) {
Phil Nash56d5c422012-08-23 20:08:50 +01003501 if( config.filters.empty() )
Phil Nash4c97fc52012-08-24 08:23:50 +01003502 std::cout << "All available test cases:\n";
Phil Nash56d5c422012-08-23 20:08:50 +01003503 else
Phil Nash4c97fc52012-08-24 08:23:50 +01003504 std::cout << "Matching test cases:\n";
Phil Nasha695eb92012-08-13 07:46:10 +01003505 std::vector<TestCaseInfo>::const_iterator it = getRegistryHub().getTestCaseRegistry().getAllTests().begin();
3506 std::vector<TestCaseInfo>::const_iterator itEnd = getRegistryHub().getTestCaseRegistry().getAllTests().end();
Phil Nash4c97fc52012-08-24 08:23:50 +01003507 std::size_t matchedTests = 0;
Phil Nasha695eb92012-08-13 07:46:10 +01003508 for(; it != itEnd; ++it ) {
Phil Nash56d5c422012-08-23 20:08:50 +01003509 if( matchesFilters( config.filters, *it ) ) {
Phil Nash4c97fc52012-08-24 08:23:50 +01003510 matchedTests++;
Phil Nash56d5c422012-08-23 20:08:50 +01003511 // !TBD: consider listAs()
3512 std::cout << "\t" << it->getName() << "\n";
3513 if( ( config.listSpec & List::TestNames ) != List::TestNames )
3514 std::cout << "\t\t '" << it->getDescription() << "'\n";
3515 }
Phil Nasha695eb92012-08-13 07:46:10 +01003516 }
Phil Nash4c97fc52012-08-24 08:23:50 +01003517 if( config.filters.empty() )
3518 std::cout << pluralise( matchedTests, "test case" ) << std::endl;
3519 else
3520 std::cout << pluralise( matchedTests, "matching test case" ) << std::endl;
Phil Nasha695eb92012-08-13 07:46:10 +01003521 }
3522
Phil Nash5bc030d2012-08-16 18:48:50 +01003523 if( ( config.listSpec & List::All ) == 0 ) {
Phil Nash56d5c422012-08-23 20:08:50 +01003524 std::ostringstream oss;
3525 oss << "Unknown list type";
3526 throw std::domain_error( oss.str() );
Phil Nasha695eb92012-08-13 07:46:10 +01003527 }
Phil Nasha695eb92012-08-13 07:46:10 +01003528 }
3529
3530} // end namespace Catch
3531
3532// #included from: internal/catch_runner_impl.hpp
3533#define TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED
3534
3535// #included from: catch_running_test.hpp
3536#define TWOBLUECUBES_INTERNAL_CATCH_RUNNING_TEST_HPP_INCLUDED
3537
3538// #included from: catch_section_info.hpp
3539#define TWOBLUECUBES_INTERNAL_CATCH_SECTION_INFO_HPP_INCLUDED
3540
3541#include <map>
3542#include <string>
3543
3544namespace Catch {
3545
3546 class SectionInfo {
3547 public:
3548
3549 enum Status {
3550 Root,
3551 Unknown,
3552 Branch,
3553 TestedBranch,
3554 TestedLeaf
3555 };
3556
3557 SectionInfo( SectionInfo* parent )
3558 : m_status( Unknown ),
3559 m_parent( parent )
3560 {}
3561
3562 SectionInfo()
3563 : m_status( Root ),
3564 m_parent( NULL )
3565 {}
3566
3567 ~SectionInfo() {
3568 deleteAllValues( m_subSections );
3569 }
3570
3571 bool shouldRun() const {
3572 return m_status < TestedBranch;
3573 }
3574
3575 bool ran() {
3576 if( m_status < Branch ) {
3577 m_status = TestedLeaf;
3578 return true;
3579 }
3580 return false;
3581 }
3582
Phil Nasha70fbe32012-08-31 08:10:36 +01003583 bool isBranch() const {
3584 return m_status == Branch;
3585 }
3586
Phil Nasha695eb92012-08-13 07:46:10 +01003587 void ranToCompletion() {
3588 if( m_status == Branch && !hasUntestedSections() )
3589 m_status = TestedBranch;
3590 }
3591
3592 SectionInfo* findSubSection( const std::string& name ) {
3593 std::map<std::string, SectionInfo*>::const_iterator it = m_subSections.find( name );
3594 return it != m_subSections.end()
3595 ? it->second
3596 : NULL;
3597 }
3598
3599 SectionInfo* addSubSection( const std::string& name ) {
3600 SectionInfo* subSection = new SectionInfo( this );
3601 m_subSections.insert( std::make_pair( name, subSection ) );
3602 m_status = Branch;
3603 return subSection;
3604 }
3605
3606 SectionInfo* getParent() {
3607 return m_parent;
3608 }
3609
3610 bool hasUntestedSections() const {
3611 if( m_status == Unknown )
3612 return true;
3613
3614 std::map<std::string, SectionInfo*>::const_iterator it = m_subSections.begin();
3615 std::map<std::string, SectionInfo*>::const_iterator itEnd = m_subSections.end();
3616 for(; it != itEnd; ++it ) {
3617 if( it->second->hasUntestedSections() )
3618 return true;
3619 }
3620 return false;
3621 }
3622
3623 private:
3624 Status m_status;
3625 std::map<std::string, SectionInfo*> m_subSections;
3626 SectionInfo* m_parent;
3627 };
3628}
3629
3630namespace Catch {
3631
3632 class RunningTest {
3633
3634 enum RunStatus {
3635 NothingRun,
3636 EncounteredASection,
3637 RanAtLeastOneSection,
3638 RanToCompletionWithSections,
3639 RanToCompletionWithNoSections
3640 };
3641
3642 public:
3643 explicit RunningTest( const TestCaseInfo* info = NULL )
3644 : m_info( info ),
3645 m_runStatus( RanAtLeastOneSection ),
3646 m_currentSection( &m_rootSection ),
3647 m_changed( false )
3648 {}
3649
3650 bool wasSectionSeen() const {
3651 return m_runStatus == RanAtLeastOneSection ||
3652 m_runStatus == RanToCompletionWithSections;
3653 }
3654
Phil Nasha70fbe32012-08-31 08:10:36 +01003655 bool isBranchSection() const {
3656 return m_currentSection &&
3657 m_currentSection->isBranch();
3658 }
3659
3660 bool hasSections() const {
3661 return m_runStatus == RanAtLeastOneSection ||
3662 m_runStatus == RanToCompletionWithSections ||
3663 m_runStatus == EncounteredASection;
3664 }
3665
Phil Nasha695eb92012-08-13 07:46:10 +01003666 void reset() {
3667 m_runStatus = NothingRun;
3668 m_changed = false;
3669 m_lastSectionToRun = NULL;
3670 }
3671
3672 void ranToCompletion() {
3673 if( m_runStatus == RanAtLeastOneSection ||
3674 m_runStatus == EncounteredASection ) {
3675 m_runStatus = RanToCompletionWithSections;
3676 if( m_lastSectionToRun ) {
3677 m_lastSectionToRun->ranToCompletion();
3678 m_changed = true;
3679 }
3680 }
3681 else {
3682 m_runStatus = RanToCompletionWithNoSections;
3683 }
3684 }
3685
3686 bool addSection( const std::string& name ) {
3687 if( m_runStatus == NothingRun )
3688 m_runStatus = EncounteredASection;
3689
3690 SectionInfo* thisSection = m_currentSection->findSubSection( name );
3691 if( !thisSection ) {
3692 thisSection = m_currentSection->addSubSection( name );
3693 m_changed = true;
3694 }
3695
3696 if( !wasSectionSeen() && thisSection->shouldRun() ) {
3697 m_currentSection = thisSection;
3698 m_lastSectionToRun = NULL;
3699 return true;
3700 }
3701 return false;
3702 }
3703
3704 void endSection( const std::string& ) {
3705 if( m_currentSection->ran() ) {
3706 m_runStatus = RanAtLeastOneSection;
3707 m_changed = true;
3708 }
3709 else if( m_runStatus == EncounteredASection ) {
3710 m_runStatus = RanAtLeastOneSection;
3711 m_lastSectionToRun = m_currentSection;
3712 }
3713 m_currentSection = m_currentSection->getParent();
3714 }
3715
3716 const TestCaseInfo& getTestCaseInfo() const {
3717 return *m_info;
3718 }
3719
3720 bool hasUntestedSections() const {
3721 return m_runStatus == RanAtLeastOneSection ||
3722 ( m_rootSection.hasUntestedSections() && m_changed );
3723 }
3724
3725 private:
3726 const TestCaseInfo* m_info;
3727 RunStatus m_runStatus;
3728 SectionInfo m_rootSection;
3729 SectionInfo* m_currentSection;
3730 SectionInfo* m_lastSectionToRun;
3731 bool m_changed;
3732 };
3733}
3734
3735#include <set>
3736#include <string>
3737
3738namespace Catch {
3739
3740 class StreamRedirect {
3741
3742 public:
3743 StreamRedirect( std::ostream& stream, std::string& targetString )
3744 : m_stream( stream ),
3745 m_prevBuf( stream.rdbuf() ),
3746 m_targetString( targetString )
3747 {
3748 stream.rdbuf( m_oss.rdbuf() );
3749 }
3750
3751 ~StreamRedirect() {
3752 m_targetString += m_oss.str();
3753 m_stream.rdbuf( m_prevBuf );
3754 }
3755
3756 private:
3757 std::ostream& m_stream;
3758 std::streambuf* m_prevBuf;
3759 std::ostringstream m_oss;
3760 std::string& m_targetString;
3761 };
3762
3763 ///////////////////////////////////////////////////////////////////////////
3764
3765 class Runner : public IResultCapture, public IRunner {
3766
3767 Runner( const Runner& );
3768 void operator =( const Runner& );
3769
3770 public:
3771
Phil Nash56d5c422012-08-23 20:08:50 +01003772 explicit Runner( const Config& config, const Ptr<IReporter>& reporter )
Phil Nasha695eb92012-08-13 07:46:10 +01003773 : m_context( getCurrentMutableContext() ),
3774 m_runningTest( NULL ),
3775 m_config( config ),
3776 m_reporter( reporter ),
3777 m_prevRunner( &m_context.getRunner() ),
3778 m_prevResultCapture( &m_context.getResultCapture() ),
3779 m_prevConfig( m_context.getConfig() )
3780 {
3781 m_context.setRunner( this );
3782 m_context.setConfig( &m_config );
3783 m_context.setResultCapture( this );
3784 m_reporter->StartTesting();
3785 }
3786
3787 virtual ~Runner() {
3788 m_reporter->EndTesting( m_totals );
3789 m_context.setRunner( m_prevRunner );
3790 m_context.setConfig( NULL );
3791 m_context.setResultCapture( m_prevResultCapture );
3792 m_context.setConfig( m_prevConfig );
3793 }
3794
Phil Nash56d5c422012-08-23 20:08:50 +01003795 Totals runMatching( const std::string& testSpec ) {
Phil Nasha695eb92012-08-13 07:46:10 +01003796
Phil Nash56d5c422012-08-23 20:08:50 +01003797 std::vector<TestCaseInfo> matchingTests = getRegistryHub().getTestCaseRegistry().getMatchingTestCases( testSpec );
Phil Nash5bc030d2012-08-16 18:48:50 +01003798
3799 Totals totals;
Phil Nash5bc030d2012-08-16 18:48:50 +01003800
Phil Nash56d5c422012-08-23 20:08:50 +01003801 m_reporter->StartGroup( testSpec );
3802
3803 std::vector<TestCaseInfo>::const_iterator it = matchingTests.begin();
3804 std::vector<TestCaseInfo>::const_iterator itEnd = matchingTests.end();
3805 for(; it != itEnd; ++it )
3806 totals += runTest( *it );
3807 // !TBD use std::accumulate?
3808
3809 m_reporter->EndGroup( testSpec, totals );
Phil Nash5bc030d2012-08-16 18:48:50 +01003810 return totals;
3811 }
3812
3813 Totals runTest( const TestCaseInfo& testInfo ) {
Phil Nasha695eb92012-08-13 07:46:10 +01003814 Totals prevTotals = m_totals;
3815
3816 std::string redirectedCout;
3817 std::string redirectedCerr;
3818
3819 m_reporter->StartTestCase( testInfo );
3820
3821 m_runningTest = new RunningTest( &testInfo );
3822
3823 do {
3824 do {
Phil Nasha695eb92012-08-13 07:46:10 +01003825 m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() );
3826 runCurrentTest( redirectedCout, redirectedCerr );
Phil Nasha695eb92012-08-13 07:46:10 +01003827 }
3828 while( m_runningTest->hasUntestedSections() && !aborting() );
3829 }
3830 while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
3831
3832 delete m_runningTest;
3833 m_runningTest = NULL;
3834
3835 Totals deltaTotals = m_totals.delta( prevTotals );
3836 m_totals.testCases += deltaTotals.testCases;
3837 m_reporter->EndTestCase( testInfo, deltaTotals, redirectedCout, redirectedCerr );
Phil Nash5bc030d2012-08-16 18:48:50 +01003838 return deltaTotals;
Phil Nasha695eb92012-08-13 07:46:10 +01003839 }
3840
3841 const Config& config() const {
3842 return m_config;
3843 }
3844
3845 private: // IResultCapture
3846
3847 virtual ResultAction::Value acceptResult( bool result ) {
3848 return acceptResult( result ? ResultWas::Ok : ResultWas::ExpressionFailed );
3849 }
3850
3851 virtual ResultAction::Value acceptResult( ResultWas::OfType result ) {
3852 m_currentResult.setResultType( result );
3853 return actOnCurrentResult();
3854 }
3855
3856 virtual ResultAction::Value acceptExpression( const ResultInfoBuilder& resultInfo ) {
3857 m_currentResult = resultInfo;
3858 return actOnCurrentResult();
3859 }
3860
3861 virtual void acceptMessage( const std::string& msg ) {
3862 m_currentResult.setMessage( msg );
3863 }
3864
3865 virtual void testEnded( const ResultInfo& result ) {
3866 if( result.getResultType() == ResultWas::Ok ) {
3867 m_totals.assertions.passed++;
3868 }
3869 else if( !result.ok() ) {
3870 m_totals.assertions.failed++;
3871
Phil Nash799ecf92012-09-24 08:30:13 +01003872 {
3873 std::vector<ScopedInfo*>::const_iterator it = m_scopedInfos.begin();
3874 std::vector<ScopedInfo*>::const_iterator itEnd = m_scopedInfos.end();
3875 for(; it != itEnd; ++it )
3876 m_reporter->Result( (*it)->getInfo() );
3877 }
3878 {
3879 std::vector<ResultInfo>::const_iterator it = m_info.begin();
3880 std::vector<ResultInfo>::const_iterator itEnd = m_info.end();
3881 for(; it != itEnd; ++it )
3882 m_reporter->Result( *it );
3883 }
Phil Nasha695eb92012-08-13 07:46:10 +01003884 m_info.clear();
3885 }
3886
3887 if( result.getResultType() == ResultWas::Info )
3888 m_info.push_back( result );
3889 else
3890 m_reporter->Result( result );
3891 }
3892
3893 virtual bool sectionStarted (
3894 const std::string& name,
3895 const std::string& description,
3896 const SourceLineInfo& lineInfo,
3897 Counts& assertions
3898 )
3899 {
3900 std::ostringstream oss;
3901 oss << name << "@" << lineInfo;
3902
3903 if( !m_runningTest->addSection( oss.str() ) )
3904 return false;
3905
3906 m_currentResult.setLineInfo( lineInfo );
3907 m_reporter->StartSection( name, description );
3908 assertions = m_totals.assertions;
3909
3910 return true;
3911 }
3912
3913 virtual void sectionEnded( const std::string& name, const Counts& prevAssertions ) {
Phil Nasha70fbe32012-08-31 08:10:36 +01003914 Counts assertions = m_totals.assertions - prevAssertions;
3915 if( assertions.total() == 0 &&
3916 ( m_config.data().warnings & ConfigData::WarnAbout::NoAssertions ) &&
3917 !m_runningTest->isBranchSection() ) {
3918 m_reporter->NoAssertionsInSection( name );
3919 m_totals.assertions.failed++;
3920 assertions.failed++;
3921 }
Phil Nasha695eb92012-08-13 07:46:10 +01003922 m_runningTest->endSection( name );
Phil Nasha70fbe32012-08-31 08:10:36 +01003923 m_reporter->EndSection( name, assertions );
Phil Nasha695eb92012-08-13 07:46:10 +01003924 }
3925
3926 virtual void pushScopedInfo( ScopedInfo* scopedInfo ) {
3927 m_scopedInfos.push_back( scopedInfo );
3928 }
3929
3930 virtual void popScopedInfo( ScopedInfo* scopedInfo ) {
3931 if( m_scopedInfos.back() == scopedInfo )
3932 m_scopedInfos.pop_back();
3933 }
3934
3935 virtual bool shouldDebugBreak() const {
3936 return m_config.shouldDebugBreak();
3937 }
3938
3939 virtual std::string getCurrentTestName() const {
3940 return m_runningTest
3941 ? m_runningTest->getTestCaseInfo().getName()
3942 : "";
3943 }
3944
3945 virtual const ResultInfo* getLastResult() const {
3946 return &m_lastResult;
3947 }
3948
Phil Nash56d5c422012-08-23 20:08:50 +01003949 public:
3950 // !TBD We need to do this another way!
Phil Nasha695eb92012-08-13 07:46:10 +01003951 bool aborting() const {
3952 return m_totals.assertions.failed == static_cast<std::size_t>( m_config.getCutoff() );
3953 }
3954
Phil Nash56d5c422012-08-23 20:08:50 +01003955 private:
3956
Phil Nasha695eb92012-08-13 07:46:10 +01003957 ResultAction::Value actOnCurrentResult() {
3958 testEnded( m_currentResult );
3959 m_lastResult = m_currentResult;
3960
3961 m_currentResult = ResultInfoBuilder();
3962
3963 ResultAction::Value action = ResultAction::None;
3964
3965 if( !m_lastResult.ok() ) {
3966 action = ResultAction::Failed;
3967 if( shouldDebugBreak() )
3968 action = (ResultAction::Value)( action | ResultAction::Debug );
3969 if( aborting() )
3970 action = (ResultAction::Value)( action | ResultAction::Abort );
3971 }
3972 return action;
3973 }
3974
3975 void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
3976 try {
3977 m_runningTest->reset();
Phil Nasha70fbe32012-08-31 08:10:36 +01003978 Counts prevAssertions = m_totals.assertions;
Phil Nasha695eb92012-08-13 07:46:10 +01003979 if( m_reporter->shouldRedirectStdout() ) {
3980 StreamRedirect coutRedir( std::cout, redirectedCout );
3981 StreamRedirect cerrRedir( std::cerr, redirectedCerr );
3982 m_runningTest->getTestCaseInfo().invoke();
3983 }
3984 else {
3985 m_runningTest->getTestCaseInfo().invoke();
3986 }
Phil Nasha70fbe32012-08-31 08:10:36 +01003987 Counts assertions = m_totals.assertions - prevAssertions;
3988 if( assertions.total() == 0 &&
3989 ( m_config.data().warnings & ConfigData::WarnAbout::NoAssertions ) &&
3990 !m_runningTest->hasSections() ) {
3991 m_totals.assertions.failed++;
3992 m_reporter->NoAssertionsInTestCase( m_runningTest->getTestCaseInfo().getName() );
3993 }
Phil Nasha695eb92012-08-13 07:46:10 +01003994 m_runningTest->ranToCompletion();
3995 }
3996 catch( TestFailureException& ) {
3997 // This just means the test was aborted due to failure
3998 }
3999 catch(...) {
4000 acceptMessage( getRegistryHub().getExceptionTranslatorRegistry().translateActiveException() );
4001 acceptResult( ResultWas::ThrewException );
4002 }
4003 m_info.clear();
4004 }
4005
4006 private:
4007 IMutableContext& m_context;
4008 RunningTest* m_runningTest;
4009 ResultInfoBuilder m_currentResult;
4010 ResultInfo m_lastResult;
4011
4012 const Config& m_config;
4013 Totals m_totals;
4014 Ptr<IReporter> m_reporter;
4015 std::vector<ScopedInfo*> m_scopedInfos;
4016 std::vector<ResultInfo> m_info;
4017 IRunner* m_prevRunner;
4018 IResultCapture* m_prevResultCapture;
4019 const IConfig* m_prevConfig;
4020 };
4021
4022} // end namespace Catch
4023
Phil Nash89d1e6c2011-05-24 08:23:02 +01004024#include <fstream>
4025#include <stdlib.h>
4026#include <limits>
4027
Phil Nash89d2a3f2012-05-16 15:09:17 +01004028namespace Catch {
4029
Phil Nash56d5c422012-08-23 20:08:50 +01004030 class Runner2 { // This will become Runner when Runner becomes Context
Phil Nash163088a2012-05-31 19:40:26 +01004031
Phil Nash56d5c422012-08-23 20:08:50 +01004032 public:
4033 Runner2( Config& configWrapper )
4034 : m_configWrapper( configWrapper ),
4035 m_config( configWrapper.data() )
Phil Nash06e959b2012-05-25 08:52:05 +01004036 {
Phil Nash67ec8702012-09-26 18:38:26 +01004037 openStream();
Phil Nash56d5c422012-08-23 20:08:50 +01004038 makeReporter();
4039 }
Phil Nash06e959b2012-05-25 08:52:05 +01004040
Phil Nash56d5c422012-08-23 20:08:50 +01004041 Totals runTests() {
4042
4043 std::vector<TestCaseFilters> filterGroups = m_config.filters;
4044 if( filterGroups.empty() ) {
4045 TestCaseFilters filterGroup( "" );
Phil Nash56d5c422012-08-23 20:08:50 +01004046 filterGroups.push_back( filterGroup );
Phil Nash89d1e6c2011-05-24 08:23:02 +01004047 }
Phil Nash56d5c422012-08-23 20:08:50 +01004048
4049 Runner context( m_configWrapper, m_reporter ); // This Runner will be renamed Context
4050 Totals totals;
4051
4052 std::vector<TestCaseFilters>::const_iterator it = filterGroups.begin();
4053 std::vector<TestCaseFilters>::const_iterator itEnd = filterGroups.end();
Phil Nashe2d215e2012-09-07 17:52:35 +01004054 for(; it != itEnd && !context.aborting(); ++it ) {
Phil Nash56d5c422012-08-23 20:08:50 +01004055 m_reporter->StartGroup( it->getName() );
Phil Nash62b70392012-08-31 18:46:13 +01004056 totals += runTestsForGroup( context, *it );
Phil Nash56d5c422012-08-23 20:08:50 +01004057 if( context.aborting() )
4058 m_reporter->Aborted();
4059 m_reporter->EndGroup( it->getName(), totals );
4060 }
4061 return totals;
4062 }
4063
4064 Totals runTestsForGroup( Runner& context, const TestCaseFilters& filterGroup ) {
4065 Totals totals;
4066 std::vector<TestCaseInfo>::const_iterator it = getRegistryHub().getTestCaseRegistry().getAllTests().begin();
4067 std::vector<TestCaseInfo>::const_iterator itEnd = getRegistryHub().getTestCaseRegistry().getAllTests().end();
4068 int testsRunForGroup = 0;
4069 for(; it != itEnd; ++it ) {
4070 if( filterGroup.shouldInclude( *it ) ) {
4071 testsRunForGroup++;
4072 if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
4073
4074 if( context.aborting() )
4075 break;
4076
4077 totals += context.runTest( *it );
4078 m_testsAlreadyRun.insert( *it );
4079 }
Phil Nash06e959b2012-05-25 08:52:05 +01004080 }
4081 }
Phil Nash56d5c422012-08-23 20:08:50 +01004082 if( testsRunForGroup == 0 )
4083 std::cerr << "\n[No test cases matched with: " << filterGroup.getName() << "]" << std::endl;
4084 return totals;
4085
Phil Nash89d1e6c2011-05-24 08:23:02 +01004086 }
Phil Nash56d5c422012-08-23 20:08:50 +01004087
4088 private:
Phil Nash67ec8702012-09-26 18:38:26 +01004089 void openStream() {
4090 if( !m_config.stream.empty() )
4091 m_configWrapper.useStream( m_config.stream );
4092
Phil Nash56d5c422012-08-23 20:08:50 +01004093 // Open output file, if specified
4094 if( !m_config.outputFilename.empty() ) {
4095 m_ofs.open( m_config.outputFilename.c_str() );
4096 if( m_ofs.fail() ) {
4097 std::ostringstream oss;
4098 oss << "Unable to open file: '" << m_config.outputFilename << "'";
4099 throw std::domain_error( oss.str() );
4100 }
4101 m_configWrapper.setStreamBuf( m_ofs.rdbuf() );
4102 }
4103 }
4104 void makeReporter() {
4105 std::string reporterName = m_config.reporter.empty()
4106 ? "basic"
4107 : m_config.reporter;
4108
Phil Nasha70fbe32012-08-31 08:10:36 +01004109 ReporterConfig reporterConfig( m_config.name, m_configWrapper.stream(), m_config.includeWhichResults == Include::SuccessfulResults, m_config );
Phil Nash56d5c422012-08-23 20:08:50 +01004110
4111 m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, reporterConfig );
4112 if( !m_reporter ) {
4113 std::ostringstream oss;
4114 oss << "No reporter registered with name: '" << reporterName << "'";
4115 throw std::domain_error( oss.str() );
4116 }
4117 }
4118
4119 private:
4120 Config& m_configWrapper;
4121 const ConfigData& m_config;
4122 std::ofstream m_ofs;
4123 Ptr<IReporter> m_reporter;
4124 std::set<TestCaseInfo> m_testsAlreadyRun;
4125 };
4126
4127 inline int Main( Config& configWrapper ) {
4128 int result = 0;
4129 try
4130 {
4131 Runner2 runner( configWrapper );
4132
4133 const ConfigData& config = configWrapper.data();
4134
4135 // Handle list request
4136 if( config.listSpec != List::None ) {
4137 List( config );
Phil Nash799ecf92012-09-24 08:30:13 +01004138 Catch::cleanUp();
Phil Nash56d5c422012-08-23 20:08:50 +01004139 return 0;
4140 }
4141
4142 result = static_cast<int>( runner.runTests().assertions.failed );
4143
4144 }
4145 catch( std::exception& ex ) {
4146 std::cerr << ex.what() << std::endl;
4147 result = (std::numeric_limits<int>::max)();
4148 }
4149
Phil Nash3b80af72012-08-09 07:47:30 +01004150 Catch::cleanUp();
Phil Nash371db8b2012-05-21 18:52:09 +01004151 return result;
Phil Nash89d1e6c2011-05-24 08:23:02 +01004152 }
4153
Phil Nash163088a2012-05-31 19:40:26 +01004154 inline void showUsage( std::ostream& os ) {
Phil Nashecf934b2012-08-27 21:42:55 +01004155 AllOptions options;
Phil Nashe2d215e2012-09-07 17:52:35 +01004156
Phil Nashecf934b2012-08-27 21:42:55 +01004157 for( AllOptions::const_iterator it = options.begin(); it != options.end(); ++it ) {
4158 OptionParser& opt = **it;
4159 os << " " << opt.optionNames() << " " << opt.argsSynopsis() << "\n";
4160 }
4161 os << "\nFor more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line\n" << std::endl;
Phil Nash163088a2012-05-31 19:40:26 +01004162 }
Phil Nashe2d215e2012-09-07 17:52:35 +01004163
4164 inline void addIndent( std::ostream& os, std::size_t indent ) {
4165 while( indent-- > 0 )
4166 os << ' ';
4167 }
4168
4169 inline void recursivelyWrapLine( std::ostream& os, std::string paragraph, std::size_t columns, std::size_t indent ) {
4170 std::size_t width = columns-indent;
4171 std::size_t tab = 0;
4172 std::size_t wrapPoint = width;
4173 for( std::size_t pos = 0; pos < paragraph.size(); ++pos ) {
4174 if( pos == width ) {
4175 addIndent( os, indent );
4176 os << paragraph.substr( 0, wrapPoint ) << "\n";
4177 return recursivelyWrapLine( os, paragraph.substr( wrapPoint+1 ), columns, indent+tab );
4178 }
4179 if( paragraph[pos] == '\t' ) {
4180 tab = pos;
4181 paragraph = paragraph.substr( 0, tab ) + paragraph.substr( tab+1 );
4182 pos--;
4183 }
4184 else if( paragraph[pos] == ' ' ) {
4185 wrapPoint = pos;
4186 }
4187 }
4188 addIndent( os, indent );
4189 os << paragraph << "\n";
4190 }
Phil Nashf7418eb2012-09-09 11:44:30 +01004191
Phil Nashe2d215e2012-09-07 17:52:35 +01004192 inline std::string addLineBreaks( const std::string& str, std::size_t columns, std::size_t indent = 0 ) {
4193 std::ostringstream oss;
4194 std::string::size_type pos = 0;
4195 std::string::size_type newline = str.find_first_of( '\n' );
4196 while( newline != std::string::npos ) {
4197 std::string paragraph = str.substr( pos, newline-pos );
4198 recursivelyWrapLine( oss, paragraph, columns, indent );
4199 pos = newline+1;
4200 newline = str.find_first_of( '\n', pos );
4201 }
Phil Nashf7418eb2012-09-09 11:44:30 +01004202 if( pos != str.size() )
4203 recursivelyWrapLine( oss, str.substr( pos, str.size()-pos ), columns, indent );
4204
Phil Nashe2d215e2012-09-07 17:52:35 +01004205 return oss.str();
4206 }
4207
4208 inline void showHelp( const CommandParser& parser ) {
4209 std::string exeName = parser.exeName();
Phil Nash89d1e6c2011-05-24 08:23:02 +01004210 std::string::size_type pos = exeName.find_last_of( "/\\" );
Phil Nash89d2a3f2012-05-16 15:09:17 +01004211 if( pos != std::string::npos ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01004212 exeName = exeName.substr( pos+1 );
4213 }
4214
Phil Nashe2d215e2012-09-07 17:52:35 +01004215 AllOptions options;
4216 Options::HelpOptionParser helpOpt;
4217 bool displayedSpecificOption = false;
4218 for( AllOptions::const_iterator it = options.begin(); it != options.end(); ++it ) {
4219 OptionParser& opt = **it;
4220 if( opt.find( parser ) && opt.optionNames() != helpOpt.optionNames() ) {
4221 displayedSpecificOption = true;
4222 std::cout << "\n" << opt.optionNames() << " " << opt.argsSynopsis() << "\n\n"
4223 << opt.optionSummary() << "\n\n"
4224
4225 << addLineBreaks( opt.optionDescription(), 80, 2 ) << "\n" << std::endl;
4226 }
4227 }
4228
4229 if( !displayedSpecificOption ) {
4230 std::cout << exeName << " is a CATCH host application. Options are as follows:\n\n";
4231 showUsage( std::cout );
4232 }
Phil Nash89d1e6c2011-05-24 08:23:02 +01004233 }
4234
Phil Nash89d2a3f2012-05-16 15:09:17 +01004235 inline int Main( int argc, char* const argv[], Config& config ) {
Phil Nash163088a2012-05-31 19:40:26 +01004236
Phil Nashabf27162012-07-05 18:37:58 +01004237 try {
4238 CommandParser parser( argc, argv );
Phil Nash89d1e6c2011-05-24 08:23:02 +01004239
Phil Nashecf934b2012-08-27 21:42:55 +01004240 if( Command cmd = Options::HelpOptionParser().find( parser ) ) {
Phil Nashabf27162012-07-05 18:37:58 +01004241 if( cmd.argsCount() != 0 )
4242 cmd.raiseError( "Does not accept arguments" );
4243
Phil Nashe2d215e2012-09-07 17:52:35 +01004244 showHelp( parser );
Phil Nash3b80af72012-08-09 07:47:30 +01004245 Catch::cleanUp();
Phil Nashabf27162012-07-05 18:37:58 +01004246 return 0;
4247 }
4248
Phil Nashecf934b2012-08-27 21:42:55 +01004249 AllOptions options;
4250
4251 options.parseIntoConfig( parser, config.data() );
Phil Nashabf27162012-07-05 18:37:58 +01004252 }
4253 catch( std::exception& ex ) {
Phil Nash6f220862012-07-23 08:24:52 +01004254 std::cerr << ex.what() << "\n\nUsage: ...\n\n";
Phil Nash163088a2012-05-31 19:40:26 +01004255 showUsage( std::cerr );
Phil Nash3b80af72012-08-09 07:47:30 +01004256 Catch::cleanUp();
Phil Nash89d1e6c2011-05-24 08:23:02 +01004257 return (std::numeric_limits<int>::max)();
4258 }
4259
Phil Nash89d1e6c2011-05-24 08:23:02 +01004260 return Main( config );
4261 }
4262
Phil Nash89d2a3f2012-05-16 15:09:17 +01004263 inline int Main( int argc, char* const argv[] ) {
Phil Nash89d1e6c2011-05-24 08:23:02 +01004264 Config config;
Phil Nash371db8b2012-05-21 18:52:09 +01004265// !TBD: This doesn't always work, for some reason
Phil Nash89d1e6c2011-05-24 08:23:02 +01004266// if( isDebuggerActive() )
4267// config.useStream( "debug" );
Phil Nash371db8b2012-05-21 18:52:09 +01004268 return Main( argc, argv, config );
Phil Nash89d1e6c2011-05-24 08:23:02 +01004269 }
4270
4271} // end namespace Catch
4272
Phil Nash3b80af72012-08-09 07:47:30 +01004273// #included from: catch_registry_hub.hpp
4274
4275// #included from: catch_test_case_registry_impl.hpp
4276
4277#include <vector>
4278#include <set>
4279#include <sstream>
4280#include <iostream>
4281
4282namespace Catch {
4283
4284 class TestRegistry : public ITestCaseRegistry {
4285 public:
4286 TestRegistry() : m_unnamedCount( 0 ) {}
Phil Nasha695eb92012-08-13 07:46:10 +01004287 virtual ~TestRegistry();
Phil Nash3b80af72012-08-09 07:47:30 +01004288
4289 virtual void registerTest( const TestCaseInfo& testInfo ) {
4290 if( testInfo.getName() == "" ) {
4291 std::ostringstream oss;
4292 oss << testInfo.getName() << "unnamed/" << ++m_unnamedCount;
4293 return registerTest( TestCaseInfo( testInfo, oss.str() ) );
4294 }
4295
4296 if( m_functions.find( testInfo ) == m_functions.end() ) {
4297 m_functions.insert( testInfo );
4298 m_functionsInOrder.push_back( testInfo );
Phil Nash5bc030d2012-08-16 18:48:50 +01004299 if( !testInfo.isHidden() )
4300 m_nonHiddenFunctions.push_back( testInfo );
Phil Nash3b80af72012-08-09 07:47:30 +01004301 }
4302 else {
4303 const TestCaseInfo& prev = *m_functions.find( testInfo );
4304 std::cerr << "error: TEST_CASE( \"" << testInfo.getName() << "\" ) already defined.\n"
4305 << "\tFirst seen at " << SourceLineInfo( prev.getLineInfo() ) << "\n"
4306 << "\tRedefined at " << SourceLineInfo( testInfo.getLineInfo() ) << std::endl;
4307 exit(1);
4308 }
4309 }
4310
4311 virtual const std::vector<TestCaseInfo>& getAllTests() const {
4312 return m_functionsInOrder;
4313 }
4314
Phil Nash5bc030d2012-08-16 18:48:50 +01004315 virtual const std::vector<TestCaseInfo>& getAllNonHiddenTests() const {
4316 return m_nonHiddenFunctions;
4317 }
4318
Phil Nash56d5c422012-08-23 20:08:50 +01004319 // !TBD deprecated
Phil Nash3b80af72012-08-09 07:47:30 +01004320 virtual std::vector<TestCaseInfo> getMatchingTestCases( const std::string& rawTestSpec ) const {
Phil Nash5bc030d2012-08-16 18:48:50 +01004321 std::vector<TestCaseInfo> matchingTests;
4322 getMatchingTestCases( rawTestSpec, matchingTests );
4323 return matchingTests;
4324 }
4325
Phil Nash56d5c422012-08-23 20:08:50 +01004326 // !TBD deprecated
Phil Nash5bc030d2012-08-16 18:48:50 +01004327 virtual void getMatchingTestCases( const std::string& rawTestSpec, std::vector<TestCaseInfo>& matchingTestsOut ) const {
Phil Nash56d5c422012-08-23 20:08:50 +01004328 TestCaseFilter filter( rawTestSpec );
Phil Nash5bc030d2012-08-16 18:48:50 +01004329
Phil Nash3b80af72012-08-09 07:47:30 +01004330 std::vector<TestCaseInfo>::const_iterator it = m_functionsInOrder.begin();
4331 std::vector<TestCaseInfo>::const_iterator itEnd = m_functionsInOrder.end();
4332 for(; it != itEnd; ++it ) {
Phil Nash56d5c422012-08-23 20:08:50 +01004333 if( filter.shouldInclude( *it ) ) {
Phil Nash5bc030d2012-08-16 18:48:50 +01004334 matchingTestsOut.push_back( *it );
Phil Nash3b80af72012-08-09 07:47:30 +01004335 }
4336 }
Phil Nash3b80af72012-08-09 07:47:30 +01004337 }
Phil Nash56d5c422012-08-23 20:08:50 +01004338 virtual void getMatchingTestCases( const TestCaseFilters& filters, std::vector<TestCaseInfo>& matchingTestsOut ) const {
4339 std::vector<TestCaseInfo>::const_iterator it = m_functionsInOrder.begin();
4340 std::vector<TestCaseInfo>::const_iterator itEnd = m_functionsInOrder.end();
4341 // !TBD: replace with algorithm
4342 for(; it != itEnd; ++it )
4343 if( filters.shouldInclude( *it ) )
4344 matchingTestsOut.push_back( *it );
4345 }
Phil Nash3b80af72012-08-09 07:47:30 +01004346
4347 private:
4348
4349 std::set<TestCaseInfo> m_functions;
4350 std::vector<TestCaseInfo> m_functionsInOrder;
Phil Nash5bc030d2012-08-16 18:48:50 +01004351 std::vector<TestCaseInfo> m_nonHiddenFunctions;
Phil Nash3b80af72012-08-09 07:47:30 +01004352 size_t m_unnamedCount;
4353 };
4354
4355 ///////////////////////////////////////////////////////////////////////////
4356
Phil Nash5bc030d2012-08-16 18:48:50 +01004357 class FreeFunctionTestCase : public SharedImpl<ITestCase> {
Phil Nash3b80af72012-08-09 07:47:30 +01004358 public:
4359
4360 FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
4361
4362 virtual void invoke() const {
4363 m_fun();
4364 }
4365
Phil Nash3b80af72012-08-09 07:47:30 +01004366 private:
Phil Nash5bc030d2012-08-16 18:48:50 +01004367 virtual ~FreeFunctionTestCase();
4368
Phil Nash3b80af72012-08-09 07:47:30 +01004369 TestFunction m_fun;
4370 };
4371
4372 ///////////////////////////////////////////////////////////////////////////
4373
4374 AutoReg::AutoReg( TestFunction function,
4375 const char* name,
4376 const char* description,
4377 const SourceLineInfo& lineInfo ) {
4378 registerTestCase( new FreeFunctionTestCase( function ), name, description, lineInfo );
4379 }
4380
4381 AutoReg::~AutoReg() {}
4382
4383 void AutoReg::registerTestCase( ITestCase* testCase,
4384 const char* name,
4385 const char* description,
4386 const SourceLineInfo& lineInfo ) {
4387 getMutableRegistryHub().registerTest( TestCaseInfo( testCase, name, description, lineInfo ) );
4388 }
4389
4390} // end namespace Catch
4391
4392// #included from: catch_reporter_registry.hpp
4393#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
4394
4395#include <map>
4396
4397namespace Catch {
4398
4399 class ReporterRegistry : public IReporterRegistry {
4400
4401 public:
4402
Phil Nasha695eb92012-08-13 07:46:10 +01004403 virtual ~ReporterRegistry() {
Phil Nash3b80af72012-08-09 07:47:30 +01004404 deleteAllValues( m_factories );
4405 }
4406
4407 virtual IReporter* create( const std::string& name, const ReporterConfig& config ) const {
4408 FactoryMap::const_iterator it = m_factories.find( name );
4409 if( it == m_factories.end() )
4410 return NULL;
4411 return it->second->create( config );
4412 }
4413
4414 void registerReporter( const std::string& name, IReporterFactory* factory ) {
4415 m_factories.insert( std::make_pair( name, factory ) );
4416 }
4417
4418 const FactoryMap& getFactories() const {
4419 return m_factories;
4420 }
4421
4422 private:
4423 FactoryMap m_factories;
4424 };
4425}
4426
4427// #included from: catch_exception_translator_registry.hpp
4428#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_HPP_INCLUDED
4429
4430#ifdef __OBJC__
4431#import "Foundation/Foundation.h"
4432#endif
4433
4434namespace Catch {
4435
4436 class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
4437 public:
4438 ~ExceptionTranslatorRegistry() {
4439 deleteAll( m_translators );
4440 }
4441
4442 virtual void registerTranslator( const IExceptionTranslator* translator ) {
4443 m_translators.push_back( translator );
4444 }
4445
4446 virtual std::string translateActiveException() const {
4447 try {
4448#ifdef __OBJC__
4449 // In Objective-C try objective-c exceptions first
4450 @try {
4451 throw;
4452 }
4453 @catch (NSException *exception) {
4454 return toString( [exception description] );
4455 }
4456#else
4457 throw;
4458#endif
4459 }
4460 catch( std::exception& ex ) {
4461 return ex.what();
4462 }
4463 catch( std::string& msg ) {
4464 return msg;
4465 }
4466 catch( const char* msg ) {
4467 return msg;
4468 }
4469 catch(...) {
4470 return tryTranslators( m_translators.begin() );
4471 }
4472 }
4473
4474 std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
4475 if( it == m_translators.end() )
4476 return "Unknown exception";
4477
4478 try {
4479 return (*it)->translate();
4480 }
4481 catch(...) {
4482 return tryTranslators( it+1 );
4483 }
4484 }
4485
4486 private:
4487 std::vector<const IExceptionTranslator*> m_translators;
4488 };
4489}
4490
4491namespace Catch {
4492
4493 namespace {
4494
4495 class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
4496
4497 RegistryHub( const RegistryHub& );
4498 void operator=( const RegistryHub& );
4499
4500 public: // IRegistryHub
4501 RegistryHub() {
4502 }
4503 virtual const IReporterRegistry& getReporterRegistry() const {
4504 return m_reporterRegistry;
4505 }
4506 virtual const ITestCaseRegistry& getTestCaseRegistry() const {
4507 return m_testCaseRegistry;
4508 }
4509 virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
4510 return m_exceptionTranslatorRegistry;
4511 }
4512
4513 public: // IMutableRegistryHub
4514 virtual void registerReporter( const std::string& name, IReporterFactory* factory ) {
4515 m_reporterRegistry.registerReporter( name, factory );
4516 }
4517 virtual void registerTest( const TestCaseInfo& testInfo ) {
4518 m_testCaseRegistry.registerTest( testInfo );
4519 }
4520 virtual void registerTranslator( const IExceptionTranslator* translator ) {
4521 m_exceptionTranslatorRegistry.registerTranslator( translator );
4522 }
4523
4524 private:
4525 TestRegistry m_testCaseRegistry;
4526 ReporterRegistry m_reporterRegistry;
4527 ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
4528 };
4529
4530 // Single, global, instance
4531 inline RegistryHub*& getTheRegistryHub() {
4532 static RegistryHub* theRegistryHub = NULL;
4533 if( !theRegistryHub )
4534 theRegistryHub = new RegistryHub();
4535 return theRegistryHub;
4536 }
4537 }
4538
4539 IRegistryHub& getRegistryHub() {
4540 return *getTheRegistryHub();
4541 }
4542 IMutableRegistryHub& getMutableRegistryHub() {
4543 return *getTheRegistryHub();
4544 }
4545 void cleanUp() {
4546 delete getTheRegistryHub();
4547 getTheRegistryHub() = NULL;
4548 cleanUpContext();
4549 }
4550
4551} // end namespace Catch
4552// #included from: catch_notimplemented_exception.hpp
4553#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
4554
4555#include <ostream>
4556
4557namespace Catch {
4558
4559 NotImplementedException::NotImplementedException( const SourceLineInfo& lineInfo )
4560 : m_lineInfo( lineInfo ) {
4561 std::ostringstream oss;
4562 oss << lineInfo << "function ";
4563 if( !lineInfo.function.empty() )
4564 oss << lineInfo.function << " ";
4565 oss << "not implemented";
4566 m_what = oss.str();
4567 }
4568
4569 const char* NotImplementedException::what() const throw() {
4570 return m_what.c_str();
4571 }
4572
4573} // end namespace Catch
4574
4575// #included from: catch_context_impl.hpp
4576
Phil Nash3b80af72012-08-09 07:47:30 +01004577namespace Catch {
4578
4579 class Context : public IMutableContext {
4580
4581 Context() : m_config( NULL ) {}
4582 Context( const Context& );
4583 void operator=( const Context& );
4584
4585 public: // IContext
4586 virtual IResultCapture& getResultCapture() {
4587 return *m_resultCapture;
4588 }
4589 virtual IRunner& getRunner() {
4590 return *m_runner;
4591 }
4592 virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) {
4593 return getGeneratorsForCurrentTest()
4594 .getGeneratorInfo( fileInfo, totalSize )
4595 .getCurrentIndex();
4596 }
4597 virtual bool advanceGeneratorsForCurrentTest() {
4598 IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
4599 return generators && generators->moveNext();
4600 }
4601
4602 virtual const IConfig* getConfig() const {
4603 return m_config;
4604 }
4605
4606 public: // IMutableContext
4607 virtual void setResultCapture( IResultCapture* resultCapture ) {
4608 m_resultCapture = resultCapture;
4609 }
4610 virtual void setRunner( IRunner* runner ) {
4611 m_runner = runner;
4612 }
4613 virtual void setConfig( const IConfig* config ) {
4614 m_config = config;
4615 }
4616
4617 friend IMutableContext& getCurrentMutableContext();
4618
4619 private:
4620 IGeneratorsForTest* findGeneratorsForCurrentTest() {
4621 std::string testName = getResultCapture().getCurrentTestName();
4622
4623 std::map<std::string, IGeneratorsForTest*>::const_iterator it =
4624 m_generatorsByTestName.find( testName );
4625 return it != m_generatorsByTestName.end()
4626 ? it->second
4627 : NULL;
4628 }
4629
4630 IGeneratorsForTest& getGeneratorsForCurrentTest() {
4631 IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
4632 if( !generators ) {
4633 std::string testName = getResultCapture().getCurrentTestName();
4634 generators = createGeneratorsForTest();
4635 m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
4636 }
4637 return *generators;
4638 }
4639
4640 private:
4641 IRunner* m_runner;
4642 IResultCapture* m_resultCapture;
4643 const IConfig* m_config;
4644 std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
4645 };
4646
4647 namespace {
4648 Context* currentContext = NULL;
4649 }
4650 IMutableContext& getCurrentMutableContext() {
4651 if( !currentContext )
4652 currentContext = new Context();
4653 return *currentContext;
4654 }
4655 IContext& getCurrentContext() {
4656 return getCurrentMutableContext();
4657 }
4658
Phil Nash67ec8702012-09-26 18:38:26 +01004659 Stream createStream( const std::string& streamName ) {
4660 if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false );
4661 if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false );
4662 if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
Phil Nash3b80af72012-08-09 07:47:30 +01004663
4664 throw std::domain_error( "Unknown stream: " + streamName );
4665 }
4666
4667 void cleanUpContext() {
4668 delete currentContext;
4669 currentContext = NULL;
4670 }
4671}
4672// #included from: catch_console_colour_impl.hpp
4673#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
4674
Phil Nash56d5c422012-08-23 20:08:50 +01004675// #included from: catch_console_colour.hpp
4676#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
4677
4678namespace Catch {
4679
4680 struct ConsoleColourImpl;
4681
4682 class TextColour : NonCopyable {
4683 public:
4684
4685 enum Colours {
4686 None,
4687
4688 FileName,
4689 ResultError,
4690 ResultSuccess,
4691
4692 Error,
4693 Success,
4694
4695 OriginalExpression,
4696 ReconstructedExpression
4697 };
4698
4699 TextColour( Colours colour = None );
4700 void set( Colours colour );
4701 ~TextColour();
4702
4703 private:
4704 ConsoleColourImpl* m_impl;
4705 };
4706
4707} // end namespace Catch
4708
Phil Nash3b80af72012-08-09 07:47:30 +01004709#ifdef CATCH_PLATFORM_WINDOWS
4710
4711#include <windows.h>
4712
4713namespace Catch {
4714
4715 namespace {
4716
4717 WORD mapConsoleColour( TextColour::Colours colour ) {
4718 switch( colour ) {
4719 case TextColour::FileName:
4720 return FOREGROUND_INTENSITY; // greyed out
4721 case TextColour::ResultError:
4722 return FOREGROUND_RED | FOREGROUND_INTENSITY; // bright red
4723 case TextColour::ResultSuccess:
4724 return FOREGROUND_GREEN | FOREGROUND_INTENSITY; // bright green
4725 case TextColour::Error:
4726 return FOREGROUND_RED; // dark red
4727 case TextColour::Success:
4728 return FOREGROUND_GREEN; // dark green
4729 case TextColour::OriginalExpression:
4730 return FOREGROUND_BLUE | FOREGROUND_GREEN; // turquoise
4731 case TextColour::ReconstructedExpression:
4732 return FOREGROUND_RED | FOREGROUND_GREEN; // greeny-yellow
4733 default: return 0;
4734 }
4735 }
4736 }
4737
4738 struct ConsoleColourImpl {
4739
4740 ConsoleColourImpl()
4741 : hStdout( GetStdHandle(STD_OUTPUT_HANDLE) ),
4742 wOldColorAttrs( 0 )
4743 {
4744 GetConsoleScreenBufferInfo( hStdout, &csbiInfo );
4745 wOldColorAttrs = csbiInfo.wAttributes;
4746 }
4747
4748 ~ConsoleColourImpl() {
4749 SetConsoleTextAttribute( hStdout, wOldColorAttrs );
4750 }
4751
4752 void set( TextColour::Colours colour ) {
4753 WORD consoleColour = mapConsoleColour( colour );
4754 if( consoleColour > 0 )
4755 SetConsoleTextAttribute( hStdout, consoleColour );
4756 }
4757
4758 HANDLE hStdout;
4759 CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
4760 WORD wOldColorAttrs;
4761 };
4762
4763 TextColour::TextColour( Colours colour )
4764 : m_impl( new ConsoleColourImpl() )
4765 {
4766 if( colour )
4767 m_impl->set( colour );
4768 }
4769
4770 TextColour::~TextColour() {
4771 delete m_impl;
4772 }
4773
4774 void TextColour::set( Colours colour ) {
4775 m_impl->set( colour );
4776 }
4777
4778} // end namespace Catch
4779
4780#else
4781
4782namespace Catch {
4783 TextColour::TextColour( Colours ){}
4784 TextColour::~TextColour(){}
4785 void TextColour::set( Colours ){}
4786
4787} // end namespace Catch
4788
4789#endif
4790
4791// #included from: catch_generators_impl.hpp
4792#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
4793
4794#include <vector>
4795#include <string>
4796#include <map>
4797
4798namespace Catch {
4799
4800 struct GeneratorInfo : IGeneratorInfo {
4801
4802 GeneratorInfo( std::size_t size )
4803 : m_size( size ),
4804 m_currentIndex( 0 )
4805 {}
4806
4807 bool moveNext() {
4808 if( ++m_currentIndex == m_size ) {
4809 m_currentIndex = 0;
4810 return false;
4811 }
4812 return true;
4813 }
4814
4815 std::size_t getCurrentIndex() const {
4816 return m_currentIndex;
4817 }
4818
4819 std::size_t m_size;
4820 std::size_t m_currentIndex;
4821 };
4822
4823 ///////////////////////////////////////////////////////////////////////////
4824
4825 class GeneratorsForTest : public IGeneratorsForTest {
4826
4827 public:
4828 ~GeneratorsForTest() {
4829 deleteAll( m_generatorsInOrder );
4830 }
4831
4832 IGeneratorInfo& getGeneratorInfo( const std::string& fileInfo, std::size_t size ) {
4833 std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
4834 if( it == m_generatorsByName.end() ) {
4835 IGeneratorInfo* info = new GeneratorInfo( size );
4836 m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
4837 m_generatorsInOrder.push_back( info );
4838 return *info;
4839 }
4840 return *it->second;
4841 }
4842
4843 bool moveNext() {
4844 std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
4845 std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
4846 for(; it != itEnd; ++it ) {
4847 if( (*it)->moveNext() )
4848 return true;
4849 }
4850 return false;
4851 }
4852
4853 private:
4854 std::map<std::string, IGeneratorInfo*> m_generatorsByName;
4855 std::vector<IGeneratorInfo*> m_generatorsInOrder;
4856 };
4857
4858 IGeneratorsForTest* createGeneratorsForTest()
4859 {
4860 return new GeneratorsForTest();
4861 }
4862
4863} // end namespace Catch
4864
4865// #included from: catch_resultinfo.hpp
4866#define TWOBLUECUBES_CATCH_RESULT_INFO_HPP_INCLUDED
4867
4868namespace Catch {
4869
4870 ResultInfo::ResultInfo()
4871 : m_macroName(),
4872 m_expr(),
4873 m_lhs(),
4874 m_rhs(),
4875 m_op(),
4876 m_message(),
4877 m_result( ResultWas::Unknown ),
4878 m_isNot( false )
4879 {}
4880
4881 ResultInfo::ResultInfo(const char* expr,
4882 ResultWas::OfType result,
4883 bool isNot,
4884 const SourceLineInfo& lineInfo,
4885 const char* macroName,
4886 const char* message )
4887 : m_macroName( macroName ),
4888 m_lineInfo( lineInfo ),
4889 m_expr( expr ),
4890 m_lhs(),
4891 m_rhs(),
4892 m_op( isNotExpression( expr ) ? "!" : "" ),
4893 m_message( message ),
4894 m_result( result ),
4895 m_isNot( isNot )
4896 {
4897 if( isNot )
4898 m_expr = "!" + m_expr;
4899 }
4900
4901 ResultInfo::~ResultInfo() {}
4902
4903 bool ResultInfo::ok() const {
4904 return ( m_result & ResultWas::FailureBit ) != ResultWas::FailureBit;
4905 }
4906
4907 ResultWas::OfType ResultInfo::getResultType() const {
4908 return m_result;
4909 }
4910
4911 bool ResultInfo::hasExpression() const {
4912 return !m_expr.empty();
4913 }
4914
4915 bool ResultInfo::hasMessage() const {
4916 return !m_message.empty();
4917 }
4918
4919 std::string ResultInfo::getExpression() const {
4920 return m_expr;
4921 }
4922
4923 bool ResultInfo::hasExpandedExpression() const {
4924 return hasExpression() && getExpandedExpressionInternal() != m_expr;
4925 }
4926
4927 std::string ResultInfo::getExpandedExpression() const {
4928 return hasExpression() ? getExpandedExpressionInternal() : "";
4929 }
4930
4931 std::string ResultInfo::getMessage() const {
4932 return m_message;
4933 }
4934
4935 std::string ResultInfo::getFilename() const {
4936 return m_lineInfo.file;
4937 }
4938
4939 std::size_t ResultInfo::getLine() const {
4940 return m_lineInfo.line;
4941 }
4942
4943 std::string ResultInfo::getTestMacroName() const {
4944 return m_macroName;
4945 }
4946
4947 std::string ResultInfo::getExpandedExpressionInternal() const {
4948 if( m_op == "" || m_isNot )
4949 return m_lhs.empty() ? m_expr : m_op + m_lhs;
4950 else if( m_op == "matches" )
4951 return m_lhs + " " + m_rhs;
4952 else if( m_op != "!" )
4953 {
4954 if( m_lhs.size() + m_rhs.size() < 30 )
4955 return m_lhs + " " + m_op + " " + m_rhs;
4956 else if( m_lhs.size() < 70 && m_rhs.size() < 70 )
4957 return "\n\t" + m_lhs + "\n\t" + m_op + "\n\t" + m_rhs;
4958 else
4959 return "\n" + m_lhs + "\n" + m_op + "\n" + m_rhs + "\n\n";
4960 }
4961 else
4962 return "{can't expand - use " + m_macroName + "_FALSE( " + m_expr.substr(1) + " ) instead of " + m_macroName + "( " + m_expr + " ) for better diagnostics}";
4963 }
4964
4965 bool ResultInfo::isNotExpression( const char* expr ) {
4966 return expr && expr[0] == '!';
4967 }
4968
4969} // end namespace Catch
4970
4971// #included from: catch_resultinfo_builder.hpp
4972#define TWOBLUECUBES_CATCH_RESULTINFO_BUILDER_HPP_INCLUDED
4973
4974namespace Catch {
4975
4976 ResultInfoBuilder::ResultInfoBuilder() {}
4977
4978 ResultInfoBuilder::ResultInfoBuilder( const char* expr,
4979 bool isNot,
4980 const SourceLineInfo& lineInfo,
4981 const char* macroName,
4982 const char* message )
4983 : ResultInfo( expr, ResultWas::Unknown, isNot, lineInfo, macroName, message )
4984 {}
4985
4986 void ResultInfoBuilder::setResultType( ResultWas::OfType result ) {
4987 // Flip bool results if isNot is set
4988 if( m_isNot && result == ResultWas::Ok )
4989 m_result = ResultWas::ExpressionFailed;
4990 else if( m_isNot && result == ResultWas::ExpressionFailed )
4991 m_result = ResultWas::Ok;
4992 else
4993 m_result = result;
4994 }
4995
4996 void ResultInfoBuilder::setMessage( const std::string& message ) {
4997 m_message = message;
4998 }
4999
5000 void ResultInfoBuilder::setLineInfo( const SourceLineInfo& lineInfo ) {
5001 m_lineInfo = lineInfo;
5002 }
5003
5004 void ResultInfoBuilder::setLhs( const std::string& lhs ) {
5005 m_lhs = lhs;
5006 }
5007
5008 void ResultInfoBuilder::setRhs( const std::string& rhs ) {
5009 m_rhs = rhs;
5010 }
5011
5012 void ResultInfoBuilder::setOp( const std::string& op ) {
5013 m_op = op;
5014 }
5015
5016 ResultInfoBuilder& ResultInfoBuilder::captureBoolExpression( bool result ) {
5017 m_lhs = Catch::toString( result );
5018 m_op = m_isNot ? "!" : "";
5019 setResultType( result ? ResultWas::Ok : ResultWas::ExpressionFailed );
5020 return *this;
5021 }
5022
5023} // end namespace Catch
5024
Phil Nash5bc030d2012-08-16 18:48:50 +01005025// #included from: catch_test_case_info.hpp
5026#define TWOBLUECUBES_CATCH_TESTCASEINFO_HPP_INCLUDED
5027
Phil Nash799ecf92012-09-24 08:30:13 +01005028namespace Catch {
5029
Phil Nash5bc030d2012-08-16 18:48:50 +01005030 TestCaseInfo::TestCaseInfo( ITestCase* testCase,
5031 const char* name,
5032 const char* description,
5033 const SourceLineInfo& lineInfo )
5034 : m_test( testCase ),
5035 m_name( name ),
5036 m_description( description ),
Phil Nashfc1baac2012-09-15 17:53:27 +01005037 m_lineInfo( lineInfo ),
5038 m_isHidden( startsWith( name, "./" ) )
5039 {
Phil Nash799ecf92012-09-24 08:30:13 +01005040 TagExtracter( m_tags ).parse( m_description );
Phil Nashfc1baac2012-09-15 17:53:27 +01005041 if( hasTag( "hide" ) )
5042 m_isHidden = true;
5043 }
Phil Nash5bc030d2012-08-16 18:48:50 +01005044
5045 TestCaseInfo::TestCaseInfo()
5046 : m_test( NULL ),
5047 m_name(),
Phil Nashfc1baac2012-09-15 17:53:27 +01005048 m_description(),
5049 m_isHidden( false )
Phil Nash5bc030d2012-08-16 18:48:50 +01005050 {}
5051
5052 TestCaseInfo::TestCaseInfo( const TestCaseInfo& other, const std::string& name )
5053 : m_test( other.m_test ),
5054 m_name( name ),
5055 m_description( other.m_description ),
Phil Nashfc1baac2012-09-15 17:53:27 +01005056 m_tags( other.m_tags ),
5057 m_lineInfo( other.m_lineInfo ),
5058 m_isHidden( other.m_isHidden )
Phil Nash5bc030d2012-08-16 18:48:50 +01005059 {}
5060
Phil Nashd2ec8492012-08-23 19:48:57 +01005061 TestCaseInfo::TestCaseInfo( const TestCaseInfo& other )
5062 : m_test( other.m_test ),
5063 m_name( other.m_name ),
5064 m_description( other.m_description ),
Phil Nashfc1baac2012-09-15 17:53:27 +01005065 m_tags( other.m_tags ),
5066 m_lineInfo( other.m_lineInfo ),
5067 m_isHidden( other.m_isHidden )
Phil Nashd2ec8492012-08-23 19:48:57 +01005068 {}
5069
Phil Nash5bc030d2012-08-16 18:48:50 +01005070 void TestCaseInfo::invoke() const {
5071 m_test->invoke();
5072 }
5073
5074 const std::string& TestCaseInfo::getName() const {
5075 return m_name;
5076 }
5077
5078 const std::string& TestCaseInfo::getDescription() const {
5079 return m_description;
5080 }
5081
5082 const SourceLineInfo& TestCaseInfo::getLineInfo() const {
5083 return m_lineInfo;
5084 }
5085
5086 bool TestCaseInfo::isHidden() const {
Phil Nashfc1baac2012-09-15 17:53:27 +01005087 return m_isHidden;
5088 }
5089
5090 bool TestCaseInfo::hasTag( const std::string& tag ) const {
5091 return m_tags.find( tag ) != m_tags.end();
5092 }
Phil Nash799ecf92012-09-24 08:30:13 +01005093 bool TestCaseInfo::matchesTags( const std::string& tagPattern ) const {
5094 TagExpression exp;
5095 TagExpressionParser( exp ).parse( tagPattern );
5096 return exp.matches( m_tags );
5097 }
Phil Nash67ec8702012-09-26 18:38:26 +01005098 const std::set<std::string>& TestCaseInfo::getTags() const {
Phil Nashfc1baac2012-09-15 17:53:27 +01005099 return m_tags;
Phil Nash5bc030d2012-08-16 18:48:50 +01005100 }
5101
5102 void TestCaseInfo::swap( TestCaseInfo& other ) {
5103 m_test.swap( other.m_test );
5104 m_name.swap( other.m_name );
5105 m_description.swap( other.m_description );
5106 m_lineInfo.swap( other.m_lineInfo );
5107 }
5108
5109 bool TestCaseInfo::operator == ( const TestCaseInfo& other ) const {
5110 return m_test.get() == other.m_test.get() && m_name == other.m_name;
5111 }
5112
5113 bool TestCaseInfo::operator < ( const TestCaseInfo& other ) const {
5114 return m_name < other.m_name;
5115 }
Phil Nashd2ec8492012-08-23 19:48:57 +01005116 TestCaseInfo& TestCaseInfo::operator = ( const TestCaseInfo& other ) {
5117 TestCaseInfo temp( other );
5118 swap( temp );
5119 return *this;
5120 }
Phil Nash799ecf92012-09-24 08:30:13 +01005121
5122} // end namespace Catch
Phil Nash5bc030d2012-08-16 18:48:50 +01005123
Phil Nash56d5c422012-08-23 20:08:50 +01005124// #included from: ../reporters/catch_reporter_basic.hpp
5125#define TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED
5126
5127// #included from: ../internal/catch_reporter_registrars.hpp
5128#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
5129
5130namespace Catch {
5131
5132 template<typename T>
5133 class ReporterRegistrar {
5134
5135 class ReporterFactory : public IReporterFactory {
5136
5137 virtual IReporter* create( const ReporterConfig& config ) const {
5138 return new T( config );
5139 }
5140
5141 virtual std::string getDescription() const {
5142 return T::getDescription();
5143 }
5144 };
5145
5146 public:
5147
5148 ReporterRegistrar( const std::string& name ) {
5149 getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
5150 }
5151 };
5152}
5153
5154#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
5155 Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name );
5156
5157namespace Catch {
5158
Phil Nash56d5c422012-08-23 20:08:50 +01005159 class BasicReporter : public SharedImpl<IReporter> {
5160
5161 struct SpanInfo {
5162
5163 SpanInfo()
5164 : emitted( false )
5165 {}
5166
5167 SpanInfo( const std::string& spanName )
5168 : name( spanName ),
5169 emitted( false )
5170 {}
5171
5172 SpanInfo( const SpanInfo& other )
5173 : name( other.name ),
5174 emitted( other.emitted )
5175 {}
5176
5177 std::string name;
5178 bool emitted;
5179 };
5180
5181 public:
5182 BasicReporter( const ReporterConfig& config )
5183 : m_config( config ),
5184 m_firstSectionInTestCase( true ),
5185 m_aborted( false )
5186 {}
5187
5188 virtual ~BasicReporter();
5189
5190 static std::string getDescription() {
5191 return "Reports test results as lines of text";
5192 }
5193
5194 private:
5195
5196 void ReportCounts( const std::string& label, const Counts& counts, const std::string& allPrefix = "All " ) {
5197 if( counts.passed )
5198 m_config.stream << counts.failed << " of " << counts.total() << " " << label << "s failed";
5199 else
5200 m_config.stream << ( counts.failed > 1 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed";
5201 }
5202
5203 void ReportCounts( const Totals& totals, const std::string& allPrefix = "All " ) {
5204 if( totals.assertions.total() == 0 ) {
5205 m_config.stream << "No tests ran";
5206 }
5207 else if( totals.assertions.failed ) {
5208 TextColour colour( TextColour::ResultError );
5209 ReportCounts( "test case", totals.testCases, allPrefix );
5210 if( totals.testCases.failed > 0 ) {
5211 m_config.stream << " (";
5212 ReportCounts( "assertion", totals.assertions, allPrefix );
5213 m_config.stream << ")";
5214 }
5215 }
5216 else {
5217 TextColour colour( TextColour::ResultSuccess );
5218 m_config.stream << allPrefix << "tests passed ("
5219 << pluralise( totals.assertions.passed, "assertion" ) << " in "
5220 << pluralise( totals.testCases.passed, "test case" ) << ")";
5221 }
5222 }
5223
5224 private: // IReporter
5225
5226 virtual bool shouldRedirectStdout() const {
5227 return false;
5228 }
5229
5230 virtual void StartTesting() {
5231 m_testingSpan = SpanInfo();
5232 }
5233
5234 virtual void Aborted() {
5235 m_aborted = true;
5236 }
5237
5238 virtual void EndTesting( const Totals& totals ) {
5239 // Output the overall test results even if "Started Testing" was not emitted
5240 if( m_aborted ) {
5241 m_config.stream << "\n[Testing aborted. ";
5242 ReportCounts( totals, "The first " );
5243 }
5244 else {
5245 m_config.stream << "\n[Testing completed. ";
5246 ReportCounts( totals );
5247 }
5248 m_config.stream << "]\n" << std::endl;
5249 }
5250
5251 virtual void StartGroup( const std::string& groupName ) {
5252 m_groupSpan = groupName;
5253 }
5254
5255 virtual void EndGroup( const std::string& groupName, const Totals& totals ) {
5256 if( m_groupSpan.emitted && !groupName.empty() ) {
5257 m_config.stream << "[End of group: '" << groupName << "'. ";
5258 ReportCounts( totals );
5259 m_config.stream << "]\n" << std::endl;
5260 m_groupSpan = SpanInfo();
5261 }
5262 }
5263
5264 virtual void StartTestCase( const TestCaseInfo& testInfo ) {
5265 m_testSpan = testInfo.getName();
5266 }
5267
5268 virtual void StartSection( const std::string& sectionName, const std::string& ) {
5269 m_sectionSpans.push_back( SpanInfo( sectionName ) );
5270 }
5271
Phil Nasha70fbe32012-08-31 08:10:36 +01005272 virtual void NoAssertionsInSection( const std::string& sectionName ) {
Phil Nashe2d215e2012-09-07 17:52:35 +01005273 startSpansLazily();
Phil Nasha70fbe32012-08-31 08:10:36 +01005274 TextColour colour( TextColour::ResultError );
5275 m_config.stream << "\nNo assertions in section, '" << sectionName << "'\n" << std::endl;
5276 }
5277 virtual void NoAssertionsInTestCase( const std::string& testName ) {
Phil Nashe2d215e2012-09-07 17:52:35 +01005278 startSpansLazily();
Phil Nasha70fbe32012-08-31 08:10:36 +01005279 TextColour colour( TextColour::ResultError );
5280 m_config.stream << "\nNo assertions in test case, '" << testName << "'\n" << std::endl;
5281 }
5282
Phil Nash56d5c422012-08-23 20:08:50 +01005283 virtual void EndSection( const std::string& sectionName, const Counts& assertions ) {
Phil Nasha70fbe32012-08-31 08:10:36 +01005284
Phil Nash56d5c422012-08-23 20:08:50 +01005285 SpanInfo& sectionSpan = m_sectionSpans.back();
5286 if( sectionSpan.emitted && !sectionSpan.name.empty() ) {
5287 m_config.stream << "[End of section: '" << sectionName << "' ";
5288
5289 if( assertions.failed ) {
5290 TextColour colour( TextColour::ResultError );
5291 ReportCounts( "assertion", assertions);
5292 }
5293 else {
5294 TextColour colour( TextColour::ResultSuccess );
5295 m_config.stream << ( assertions.passed > 1 ? "All " : "" )
5296 << pluralise( assertions.passed, "assertion" ) << " passed" ;
5297 }
5298 m_config.stream << "]\n" << std::endl;
5299 }
5300 m_sectionSpans.pop_back();
5301 }
5302
5303 virtual void Result( const ResultInfo& resultInfo ) {
5304 if( !m_config.includeSuccessfulResults && resultInfo.getResultType() == ResultWas::Ok )
5305 return;
5306
Phil Nashe2d215e2012-09-07 17:52:35 +01005307 startSpansLazily();
Phil Nash56d5c422012-08-23 20:08:50 +01005308
5309 if( !resultInfo.getFilename().empty() ) {
5310 TextColour colour( TextColour::FileName );
5311 m_config.stream << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() );
5312 }
5313
5314 if( resultInfo.hasExpression() ) {
5315 TextColour colour( TextColour::OriginalExpression );
5316 m_config.stream << resultInfo.getExpression();
5317 if( resultInfo.ok() ) {
5318 TextColour successColour( TextColour::Success );
5319 m_config.stream << " succeeded";
5320 }
5321 else {
5322 TextColour errorColour( TextColour::Error );
5323 m_config.stream << " failed";
5324 }
5325 }
5326 switch( resultInfo.getResultType() ) {
5327 case ResultWas::ThrewException:
5328 {
5329 TextColour colour( TextColour::Error );
5330 if( resultInfo.hasExpression() )
5331 m_config.stream << " with unexpected";
5332 else
5333 m_config.stream << "Unexpected";
5334 m_config.stream << " exception with message: '" << resultInfo.getMessage() << "'";
5335 }
5336 break;
5337 case ResultWas::DidntThrowException:
5338 {
5339 TextColour colour( TextColour::Error );
5340 if( resultInfo.hasExpression() )
5341 m_config.stream << " because no exception was thrown where one was expected";
5342 else
5343 m_config.stream << "No exception thrown where one was expected";
5344 }
5345 break;
5346 case ResultWas::Info:
5347 streamVariableLengthText( "info", resultInfo.getMessage() );
5348 break;
5349 case ResultWas::Warning:
5350 m_config.stream << "warning:\n'" << resultInfo.getMessage() << "'";
5351 break;
5352 case ResultWas::ExplicitFailure:
5353 {
5354 TextColour colour( TextColour::Error );
5355 m_config.stream << "failed with message: '" << resultInfo.getMessage() << "'";
5356 }
5357 break;
5358 case ResultWas::Unknown: // These cases are here to prevent compiler warnings
5359 case ResultWas::Ok:
5360 case ResultWas::FailureBit:
5361 case ResultWas::ExpressionFailed:
5362 case ResultWas::Exception:
5363 if( !resultInfo.hasExpression() ) {
5364 if( resultInfo.ok() ) {
5365 TextColour colour( TextColour::Success );
5366 m_config.stream << " succeeded";
5367 }
5368 else {
5369 TextColour colour( TextColour::Error );
5370 m_config.stream << " failed";
5371 }
5372 }
5373 break;
5374 }
5375
5376 if( resultInfo.hasExpandedExpression() ) {
5377 m_config.stream << " for: ";
5378 TextColour colour( TextColour::ReconstructedExpression );
5379 m_config.stream << resultInfo.getExpandedExpression();
5380 }
5381 m_config.stream << std::endl;
5382 }
5383
5384 virtual void EndTestCase( const TestCaseInfo& testInfo,
5385 const Totals& totals,
5386 const std::string& stdOut,
5387 const std::string& stdErr ) {
5388 if( !stdOut.empty() ) {
Phil Nashe2d215e2012-09-07 17:52:35 +01005389 startSpansLazily();
Phil Nash56d5c422012-08-23 20:08:50 +01005390 streamVariableLengthText( "stdout", stdOut );
5391 }
5392
5393 if( !stdErr.empty() ) {
Phil Nashe2d215e2012-09-07 17:52:35 +01005394 startSpansLazily();
Phil Nash56d5c422012-08-23 20:08:50 +01005395 streamVariableLengthText( "stderr", stdErr );
5396 }
5397
5398 if( m_testSpan.emitted ) {
5399 m_config.stream << "[Finished: '" << testInfo.getName() << "' ";
5400 ReportCounts( totals );
5401 m_config.stream << "]" << std::endl;
5402 }
5403 }
5404
5405 private: // helpers
5406
Phil Nashe2d215e2012-09-07 17:52:35 +01005407 void startSpansLazily() {
Phil Nash56d5c422012-08-23 20:08:50 +01005408 if( !m_testingSpan.emitted ) {
5409 if( m_config.name.empty() )
5410 m_config.stream << "[Started testing]" << std::endl;
5411 else
5412 m_config.stream << "[Started testing: " << m_config.name << "]" << std::endl;
5413 m_testingSpan.emitted = true;
5414 }
5415
5416 if( !m_groupSpan.emitted && !m_groupSpan.name.empty() ) {
5417 m_config.stream << "[Started group: '" << m_groupSpan.name << "']" << std::endl;
5418 m_groupSpan.emitted = true;
5419 }
5420
5421 if( !m_testSpan.emitted ) {
5422 m_config.stream << std::endl << "[Running: " << m_testSpan.name << "]" << std::endl;
5423 m_testSpan.emitted = true;
5424 }
5425
5426 if( !m_sectionSpans.empty() ) {
5427 SpanInfo& sectionSpan = m_sectionSpans.back();
5428 if( !sectionSpan.emitted && !sectionSpan.name.empty() ) {
5429 if( m_firstSectionInTestCase ) {
5430 m_config.stream << "\n";
5431 m_firstSectionInTestCase = false;
5432 }
5433 std::vector<SpanInfo>::iterator it = m_sectionSpans.begin();
5434 std::vector<SpanInfo>::iterator itEnd = m_sectionSpans.end();
5435 for(; it != itEnd; ++it ) {
5436 SpanInfo& prevSpan = *it;
5437 if( !prevSpan.emitted && !prevSpan.name.empty() ) {
5438 m_config.stream << "[Started section: '" << prevSpan.name << "']" << std::endl;
5439 prevSpan.emitted = true;
5440 }
5441 }
5442 }
5443 }
5444 }
5445
5446 void streamVariableLengthText( const std::string& prefix, const std::string& text ) {
5447 std::string trimmed = trim( text );
5448 if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) {
5449 m_config.stream << "[" << prefix << ": " << trimmed << "]\n";
5450 }
5451 else {
5452 m_config.stream << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed
5453 << "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n";
5454 }
5455 }
5456
5457 private:
5458 ReporterConfig m_config;
5459 bool m_firstSectionInTestCase;
5460
5461 SpanInfo m_testingSpan;
5462 SpanInfo m_groupSpan;
5463 SpanInfo m_testSpan;
5464 std::vector<SpanInfo> m_sectionSpans;
5465 bool m_aborted;
5466 };
5467
5468} // end namespace Catch
5469
5470// #included from: ../reporters/catch_reporter_xml.hpp
5471#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
5472
5473// #included from: ../internal/catch_xmlwriter.hpp
5474#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
5475
5476#include <sstream>
5477#include <string>
5478#include <vector>
5479
5480namespace Catch {
5481
5482 class XmlWriter {
5483 public:
5484
5485 class ScopedElement {
5486 public:
5487 ScopedElement( XmlWriter* writer )
5488 : m_writer( writer )
5489 {}
5490
5491 ScopedElement( const ScopedElement& other )
5492 : m_writer( other.m_writer ){
5493 other.m_writer = NULL;
5494 }
5495
5496 ~ScopedElement() {
5497 if( m_writer )
5498 m_writer->endElement();
5499 }
5500
5501 ScopedElement& writeText( const std::string& text ) {
5502 m_writer->writeText( text );
5503 return *this;
5504 }
5505
5506 template<typename T>
5507 ScopedElement& writeAttribute( const std::string& name, const T& attribute ) {
5508 m_writer->writeAttribute( name, attribute );
5509 return *this;
5510 }
5511
5512 private:
5513 mutable XmlWriter* m_writer;
5514 };
5515
5516 XmlWriter()
5517 : m_tagIsOpen( false ),
5518 m_needsNewline( false ),
5519 m_os( &std::cout )
5520 {}
5521
5522 XmlWriter( std::ostream& os )
5523 : m_tagIsOpen( false ),
5524 m_needsNewline( false ),
5525 m_os( &os )
5526 {}
5527
5528 ~XmlWriter() {
5529 while( !m_tags.empty() )
5530 endElement();
5531 }
5532
5533 XmlWriter& operator = ( const XmlWriter& other ) {
5534 XmlWriter temp( other );
5535 swap( temp );
5536 return *this;
5537 }
5538
5539 void swap( XmlWriter& other ) {
5540 std::swap( m_tagIsOpen, other.m_tagIsOpen );
5541 std::swap( m_needsNewline, other.m_needsNewline );
5542 std::swap( m_tags, other.m_tags );
5543 std::swap( m_indent, other.m_indent );
5544 std::swap( m_os, other.m_os );
5545 }
5546
5547 XmlWriter& startElement( const std::string& name ) {
5548 ensureTagClosed();
5549 newlineIfNecessary();
5550 stream() << m_indent << "<" << name;
5551 m_tags.push_back( name );
5552 m_indent += " ";
5553 m_tagIsOpen = true;
5554 return *this;
5555 }
5556
5557 ScopedElement scopedElement( const std::string& name ) {
5558 ScopedElement scoped( this );
5559 startElement( name );
5560 return scoped;
5561 }
5562
5563 XmlWriter& endElement() {
5564 newlineIfNecessary();
5565 m_indent = m_indent.substr( 0, m_indent.size()-2 );
5566 if( m_tagIsOpen ) {
5567 stream() << "/>\n";
5568 m_tagIsOpen = false;
5569 }
5570 else {
5571 stream() << m_indent << "</" << m_tags.back() << ">\n";
5572 }
5573 m_tags.pop_back();
5574 return *this;
5575 }
5576
5577 XmlWriter& writeAttribute( const std::string& name, const std::string& attribute ) {
5578 if( !name.empty() && !attribute.empty() ) {
5579 stream() << " " << name << "=\"";
5580 writeEncodedText( attribute );
5581 stream() << "\"";
5582 }
5583 return *this;
5584 }
5585
5586 XmlWriter& writeAttribute( const std::string& name, bool attribute ) {
5587 stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
5588 return *this;
5589 }
5590
5591 template<typename T>
5592 XmlWriter& writeAttribute( const std::string& name, const T& attribute ) {
5593 if( !name.empty() )
5594 stream() << " " << name << "=\"" << attribute << "\"";
5595 return *this;
5596 }
5597
5598 XmlWriter& writeText( const std::string& text ) {
5599 if( !text.empty() ){
5600 bool tagWasOpen = m_tagIsOpen;
5601 ensureTagClosed();
5602 if( tagWasOpen )
5603 stream() << m_indent;
5604 writeEncodedText( text );
5605 m_needsNewline = true;
5606 }
5607 return *this;
5608 }
5609
5610 XmlWriter& writeComment( const std::string& text ) {
5611 ensureTagClosed();
5612 stream() << m_indent << "<!--" << text << "-->";
5613 m_needsNewline = true;
5614 return *this;
5615 }
5616
5617 XmlWriter& writeBlankLine() {
5618 ensureTagClosed();
5619 stream() << "\n";
5620 return *this;
5621 }
5622
5623 private:
5624
5625 std::ostream& stream() {
5626 return *m_os;
5627 }
5628
5629 void ensureTagClosed() {
5630 if( m_tagIsOpen ) {
5631 stream() << ">\n";
5632 m_tagIsOpen = false;
5633 }
5634 }
5635
5636 void newlineIfNecessary() {
5637 if( m_needsNewline ) {
5638 stream() << "\n";
5639 m_needsNewline = false;
5640 }
5641 }
5642
5643 void writeEncodedText( const std::string& text ) {
5644 static const char* charsToEncode = "<&\"";
5645 std::string mtext = text;
5646 std::string::size_type pos = mtext.find_first_of( charsToEncode );
5647 while( pos != std::string::npos ) {
5648 stream() << mtext.substr( 0, pos );
5649
5650 switch( mtext[pos] ) {
5651 case '<':
5652 stream() << "&lt;";
5653 break;
5654 case '&':
5655 stream() << "&amp;";
5656 break;
5657 case '\"':
5658 stream() << "&quot;";
5659 break;
5660 }
5661 mtext = mtext.substr( pos+1 );
5662 pos = mtext.find_first_of( charsToEncode );
5663 }
5664 stream() << mtext;
5665 }
5666
5667 bool m_tagIsOpen;
5668 bool m_needsNewline;
5669 std::vector<std::string> m_tags;
5670 std::string m_indent;
5671 std::ostream* m_os;
5672 };
5673
5674}
5675namespace Catch {
5676 class XmlReporter : public SharedImpl<IReporter> {
5677 public:
5678 XmlReporter( const ReporterConfig& config ) : m_config( config ) {}
5679
5680 static std::string getDescription() {
5681 return "Reports test results as an XML document";
5682 }
5683 virtual ~XmlReporter();
5684
5685 private: // IReporter
5686
5687 virtual bool shouldRedirectStdout() const {
5688 return true;
5689 }
5690
5691 virtual void StartTesting() {
5692 m_xml = XmlWriter( m_config.stream );
5693 m_xml.startElement( "Catch" );
5694 if( !m_config.name.empty() )
5695 m_xml.writeAttribute( "name", m_config.name );
5696 }
5697
5698 virtual void EndTesting( const Totals& totals ) {
5699 m_xml.scopedElement( "OverallResults" )
5700 .writeAttribute( "successes", totals.assertions.passed )
5701 .writeAttribute( "failures", totals.assertions.failed );
5702 m_xml.endElement();
5703 }
5704
5705 virtual void StartGroup( const std::string& groupName ) {
5706 m_xml.startElement( "Group" )
5707 .writeAttribute( "name", groupName );
5708 }
5709
5710 virtual void EndGroup( const std::string&, const Totals& totals ) {
5711 m_xml.scopedElement( "OverallResults" )
5712 .writeAttribute( "successes", totals.assertions.passed )
5713 .writeAttribute( "failures", totals.assertions.failed );
5714 m_xml.endElement();
5715 }
5716
5717 virtual void StartSection( const std::string& sectionName, const std::string& description ) {
5718 m_xml.startElement( "Section" )
5719 .writeAttribute( "name", sectionName )
5720 .writeAttribute( "description", description );
5721 }
Phil Nasha70fbe32012-08-31 08:10:36 +01005722 virtual void NoAssertionsInSection( const std::string& ) {}
5723 virtual void NoAssertionsInTestCase( const std::string& ) {}
Phil Nash56d5c422012-08-23 20:08:50 +01005724
5725 virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
5726 m_xml.scopedElement( "OverallResults" )
5727 .writeAttribute( "successes", assertions.passed )
5728 .writeAttribute( "failures", assertions.failed );
5729 m_xml.endElement();
5730 }
5731
5732 virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
5733 m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.getName() );
5734 m_currentTestSuccess = true;
5735 }
5736
5737 virtual void Result( const Catch::ResultInfo& resultInfo ) {
5738 if( !m_config.includeSuccessfulResults && resultInfo.getResultType() == ResultWas::Ok )
5739 return;
5740
5741 if( resultInfo.hasExpression() ) {
5742 m_xml.startElement( "Expression" )
5743 .writeAttribute( "success", resultInfo.ok() )
5744 .writeAttribute( "filename", resultInfo.getFilename() )
5745 .writeAttribute( "line", resultInfo.getLine() );
5746
5747 m_xml.scopedElement( "Original" )
5748 .writeText( resultInfo.getExpression() );
5749 m_xml.scopedElement( "Expanded" )
5750 .writeText( resultInfo.getExpandedExpression() );
5751 m_currentTestSuccess &= resultInfo.ok();
5752 }
5753
5754 switch( resultInfo.getResultType() ) {
5755 case ResultWas::ThrewException:
5756 m_xml.scopedElement( "Exception" )
5757 .writeAttribute( "filename", resultInfo.getFilename() )
5758 .writeAttribute( "line", resultInfo.getLine() )
5759 .writeText( resultInfo.getMessage() );
5760 m_currentTestSuccess = false;
5761 break;
5762 case ResultWas::Info:
5763 m_xml.scopedElement( "Info" )
5764 .writeText( resultInfo.getMessage() );
5765 break;
5766 case ResultWas::Warning:
5767 m_xml.scopedElement( "Warning" )
5768 .writeText( resultInfo.getMessage() );
5769 break;
5770 case ResultWas::ExplicitFailure:
5771 m_xml.scopedElement( "Failure" )
5772 .writeText( resultInfo.getMessage() );
5773 m_currentTestSuccess = false;
5774 break;
5775 case ResultWas::Unknown:
5776 case ResultWas::Ok:
5777 case ResultWas::FailureBit:
5778 case ResultWas::ExpressionFailed:
5779 case ResultWas::Exception:
5780 case ResultWas::DidntThrowException:
5781 break;
5782 }
5783 if( resultInfo.hasExpression() )
5784 m_xml.endElement();
5785 }
5786
5787 virtual void Aborted() {
5788 // !TBD
5789 }
5790
5791 virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
5792 m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
5793 m_xml.endElement();
5794 }
5795
5796 private:
5797 ReporterConfig m_config;
5798 bool m_currentTestSuccess;
5799 XmlWriter m_xml;
5800 };
5801
5802} // end namespace Catch
5803
5804// #included from: ../reporters/catch_reporter_junit.hpp
5805#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
5806
5807namespace Catch {
5808
5809 class JunitReporter : public SharedImpl<IReporter> {
5810
5811 struct TestStats {
5812 std::string m_element;
5813 std::string m_resultType;
5814 std::string m_message;
5815 std::string m_content;
5816 };
5817
5818 struct TestCaseStats {
5819
5820 TestCaseStats( const std::string& name = std::string() ) :m_name( name ){}
5821
5822 double m_timeInSeconds;
5823 std::string m_status;
5824 std::string m_className;
5825 std::string m_name;
5826 std::vector<TestStats> m_testStats;
5827 };
5828
5829 struct Stats {
5830
5831 Stats( const std::string& name = std::string() )
5832 : m_testsCount( 0 ),
5833 m_failuresCount( 0 ),
5834 m_disabledCount( 0 ),
5835 m_errorsCount( 0 ),
5836 m_timeInSeconds( 0 ),
5837 m_name( name )
5838 {}
5839
5840 std::size_t m_testsCount;
5841 std::size_t m_failuresCount;
5842 std::size_t m_disabledCount;
5843 std::size_t m_errorsCount;
5844 double m_timeInSeconds;
5845 std::string m_name;
5846
5847 std::vector<TestCaseStats> m_testCaseStats;
5848 };
5849
5850 public:
5851 JunitReporter( const ReporterConfig& config )
5852 : m_config( config ),
5853 m_testSuiteStats( "AllTests" ),
5854 m_currentStats( &m_testSuiteStats )
5855 {}
5856 virtual ~JunitReporter();
5857
5858 static std::string getDescription() {
5859 return "Reports test results in an XML format that looks like Ant's junitreport target";
5860 }
5861
5862 private: // IReporter
5863
5864 virtual bool shouldRedirectStdout() const {
5865 return true;
5866 }
5867
5868 virtual void StartTesting(){}
5869
5870 virtual void StartGroup( const std::string& groupName ) {
5871 m_statsForSuites.push_back( Stats( groupName ) );
5872 m_currentStats = &m_statsForSuites.back();
5873 }
5874
5875 virtual void EndGroup( const std::string&, const Totals& totals ) {
5876 m_currentStats->m_testsCount = totals.assertions.total();
5877 m_currentStats = &m_testSuiteStats;
5878 }
5879
5880 virtual void StartSection( const std::string&, const std::string& ){}
5881
Phil Nasha70fbe32012-08-31 08:10:36 +01005882 virtual void NoAssertionsInSection( const std::string& ) {}
5883 virtual void NoAssertionsInTestCase( const std::string& ) {}
5884
5885 virtual void EndSection( const std::string&, const Counts& ) {}
Phil Nash56d5c422012-08-23 20:08:50 +01005886
5887 virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
5888 m_currentStats->m_testCaseStats.push_back( TestCaseStats( testInfo.getName() ) );
5889 }
5890
5891 virtual void Result( const Catch::ResultInfo& resultInfo ) {
5892 if( resultInfo.getResultType() != ResultWas::Ok || m_config.includeSuccessfulResults ) {
5893 TestCaseStats& testCaseStats = m_currentStats->m_testCaseStats.back();
5894 TestStats stats;
5895 std::ostringstream oss;
5896 if( !resultInfo.getMessage().empty() )
5897 oss << resultInfo.getMessage() << " at ";
5898 oss << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() );
5899 stats.m_content = oss.str();
5900 stats.m_message = resultInfo.getExpandedExpression();
5901 stats.m_resultType = resultInfo.getTestMacroName();
5902
5903 switch( resultInfo.getResultType() ) {
5904 case ResultWas::ThrewException:
5905 stats.m_element = "error";
5906 m_currentStats->m_errorsCount++;
5907 break;
5908 case ResultWas::Info:
5909 stats.m_element = "info"; // !TBD ?
5910 break;
5911 case ResultWas::Warning:
5912 stats.m_element = "warning"; // !TBD ?
5913 break;
5914 case ResultWas::ExplicitFailure:
5915 stats.m_element = "failure";
5916 m_currentStats->m_failuresCount++;
5917 break;
5918 case ResultWas::ExpressionFailed:
5919 stats.m_element = "failure";
5920 m_currentStats->m_failuresCount++;
5921 break;
5922 case ResultWas::Ok:
5923 stats.m_element = "success";
5924 break;
5925 case ResultWas::Unknown:
5926 case ResultWas::FailureBit:
5927 case ResultWas::Exception:
5928 case ResultWas::DidntThrowException:
5929 break;
5930 }
5931 testCaseStats.m_testStats.push_back( stats );
5932 }
5933 }
5934
5935 virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string& stdOut, const std::string& stdErr ) {
5936 if( !stdOut.empty() )
5937 m_stdOut << stdOut << "\n";
5938 if( !stdErr.empty() )
5939 m_stdErr << stdErr << "\n";
5940 }
5941
5942 virtual void Aborted() {
5943 // !TBD
5944 }
5945
5946 virtual void EndTesting( const Totals& ) {
5947 std::ostream& str = m_config.stream;
5948 {
5949 XmlWriter xml( str );
5950
5951 if( m_statsForSuites.size() > 0 )
5952 xml.startElement( "testsuites" );
5953
5954 std::vector<Stats>::const_iterator it = m_statsForSuites.begin();
5955 std::vector<Stats>::const_iterator itEnd = m_statsForSuites.end();
5956
5957 for(; it != itEnd; ++it ) {
5958 XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
5959 xml.writeAttribute( "name", it->m_name );
5960 xml.writeAttribute( "errors", it->m_errorsCount );
5961 xml.writeAttribute( "failures", it->m_failuresCount );
5962 xml.writeAttribute( "tests", it->m_testsCount );
5963 xml.writeAttribute( "hostname", "tbd" );
5964 xml.writeAttribute( "time", "tbd" );
5965 xml.writeAttribute( "timestamp", "tbd" );
5966
5967 OutputTestCases( xml, *it );
5968 }
5969
5970 xml.scopedElement( "system-out" ).writeText( trim( m_stdOut.str() ) );
5971 xml.scopedElement( "system-err" ).writeText( trim( m_stdErr.str() ) );
5972 }
5973 }
5974
5975 void OutputTestCases( XmlWriter& xml, const Stats& stats ) {
5976 std::vector<TestCaseStats>::const_iterator it = stats.m_testCaseStats.begin();
5977 std::vector<TestCaseStats>::const_iterator itEnd = stats.m_testCaseStats.end();
5978 for(; it != itEnd; ++it ) {
5979 xml.writeBlankLine();
5980 xml.writeComment( "Test case" );
5981
5982 XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
5983 xml.writeAttribute( "classname", it->m_className );
5984 xml.writeAttribute( "name", it->m_name );
5985 xml.writeAttribute( "time", "tbd" );
5986
5987 OutputTestResult( xml, *it );
5988 }
5989 }
5990
5991 void OutputTestResult( XmlWriter& xml, const TestCaseStats& stats ) {
5992 std::vector<TestStats>::const_iterator it = stats.m_testStats.begin();
5993 std::vector<TestStats>::const_iterator itEnd = stats.m_testStats.end();
5994 for(; it != itEnd; ++it ) {
5995 if( it->m_element != "success" ) {
5996 XmlWriter::ScopedElement e = xml.scopedElement( it->m_element );
5997
5998 xml.writeAttribute( "message", it->m_message );
5999 xml.writeAttribute( "type", it->m_resultType );
6000 if( !it->m_content.empty() )
6001 xml.writeText( it->m_content );
6002 }
6003 }
6004 }
6005
6006 private:
6007 ReporterConfig m_config;
6008 bool m_currentTestSuccess;
6009
6010 Stats m_testSuiteStats;
6011 Stats* m_currentStats;
6012 std::vector<Stats> m_statsForSuites;
6013 std::ostringstream m_stdOut;
6014 std::ostringstream m_stdErr;
6015 };
6016
6017} // end namespace Catch
6018
Phil Nasha695eb92012-08-13 07:46:10 +01006019namespace Catch {
6020 NonCopyable::~NonCopyable() {}
6021 IShared::~IShared() {}
6022 StreamBufBase::~StreamBufBase() {}
6023 IContext::~IContext() {}
6024 IResultCapture::~IResultCapture() {}
6025 ITestCase::~ITestCase() {}
6026 ITestCaseRegistry::~ITestCaseRegistry() {}
6027 IRegistryHub::~IRegistryHub() {}
6028 IMutableRegistryHub::~IMutableRegistryHub() {}
6029 IExceptionTranslator::~IExceptionTranslator() {}
6030 IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
6031 IReporter::~IReporter() {}
6032 IReporterFactory::~IReporterFactory() {}
6033 IReporterRegistry::~IReporterRegistry() {}
6034 BasicReporter::~BasicReporter() {}
6035 IRunner::~IRunner() {}
6036 IMutableContext::~IMutableContext() {}
6037 IConfig::~IConfig() {}
6038 XmlReporter::~XmlReporter() {}
6039 JunitReporter::~JunitReporter() {}
6040 TestRegistry::~TestRegistry() {}
6041 FreeFunctionTestCase::~FreeFunctionTestCase() {}
6042 IGeneratorInfo::~IGeneratorInfo() {}
6043 IGeneratorsForTest::~IGeneratorsForTest() {}
Phil Nash799ecf92012-09-24 08:30:13 +01006044 TagParser::~TagParser() {}
6045 TagExtracter::~TagExtracter() {}
6046 TagExpressionParser::~TagExpressionParser() {}
Phil Nasha695eb92012-08-13 07:46:10 +01006047
6048 void Config::dummy() {}
6049
Phil Nash56d5c422012-08-23 20:08:50 +01006050 INTERNAL_CATCH_REGISTER_REPORTER( "basic", BasicReporter )
6051 INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
6052 INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
6053
Phil Nasha695eb92012-08-13 07:46:10 +01006054}
6055
Phil Nash5bc030d2012-08-16 18:48:50 +01006056#ifdef __clang__
Phil Nasha695eb92012-08-13 07:46:10 +01006057#pragma clang diagnostic pop
Phil Nash89d1e6c2011-05-24 08:23:02 +01006058#endif
Phil Nash5bc030d2012-08-16 18:48:50 +01006059#endif
Phil Nash89d1e6c2011-05-24 08:23:02 +01006060
6061#ifdef CATCH_CONFIG_MAIN
6062// #included from: internal/catch_default_main.hpp
Phil Nash3b80af72012-08-09 07:47:30 +01006063#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +01006064
Phil Nash176eb812012-05-11 08:17:16 +01006065#ifndef __OBJC__
Phil Nash89d1e6c2011-05-24 08:23:02 +01006066
Phil Nash176eb812012-05-11 08:17:16 +01006067// Standard C/C++ main entry point
6068int main (int argc, char * const argv[]) {
6069 return Catch::Main( argc, argv );
6070}
6071
6072#else // __OBJC__
6073
6074// Objective-C entry point
6075int main (int argc, char * const argv[]) {
Phil Nash53c990a2012-03-17 18:20:06 +00006076#if !CATCH_ARC_ENABLED
Phil Nash89d1e6c2011-05-24 08:23:02 +01006077 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Phil Nash53c990a2012-03-17 18:20:06 +00006078#endif
Phil Nash89d1e6c2011-05-24 08:23:02 +01006079
6080 Catch::registerTestMethods();
Phil Nash89d1e6c2011-05-24 08:23:02 +01006081 int result = Catch::Main( argc, (char* const*)argv );
6082
Phil Nash53c990a2012-03-17 18:20:06 +00006083#if !CATCH_ARC_ENABLED
Phil Nash89d1e6c2011-05-24 08:23:02 +01006084 [pool drain];
Phil Nash53c990a2012-03-17 18:20:06 +00006085#endif
Phil Nash89d1e6c2011-05-24 08:23:02 +01006086
Phil Nashdd5b9c22012-02-18 09:58:30 +00006087 return result;
Phil Nash89d1e6c2011-05-24 08:23:02 +01006088}
6089
Phil Nash176eb812012-05-11 08:17:16 +01006090#endif // __OBJC__
6091
Phil Nash89d1e6c2011-05-24 08:23:02 +01006092#endif
6093
Phil Nash89d1e6c2011-05-24 08:23:02 +01006094//////
6095
Phil Nash46bcd4b2012-07-20 18:43:48 +01006096// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
6097#ifdef CATCH_CONFIG_PREFIX_ALL
6098
6099#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, false, true, "CATCH_REQUIRE" )
6100#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, true, "CATCH_REQUIRE_FALSE" )
6101
6102#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., true, "CATCH_REQUIRE_THROWS" )
6103#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, true, "CATCH_REQUIRE_THROWS_AS" )
6104#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, true, "CATCH_REQUIRE_NOTHROW" )
6105
6106#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, false, false, "CATCH_CHECK" )
6107#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, false, "CATCH_CHECK_FALSE" )
6108#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, false, false, "CATCH_CHECKED_IF" )
6109#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, false, false, "CATCH_CHECKED_ELSE" )
6110
6111#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., false, "CATCH_CHECK_THROWS" )
6112#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, false, "CATCH_CHECK_THROWS_AS" )
6113#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, false, "CATCH_CHECK_NOTHROW" )
6114
6115#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, false, "CATCH_CHECK_THAT" )
6116#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, true, "CATCH_REQUIRE_THAT" )
6117
6118#define CATCH_INFO( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Info, false, "CATCH_INFO" )
6119#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Warning, false, "CATCH_WARN" )
6120#define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::ExplicitFailure, true, "CATCH_FAIL" )
Phil Nash74d1d312012-08-31 18:37:47 +01006121#define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Ok, false, "CATCH_SUCCEED" )
Phil Nash46bcd4b2012-07-20 18:43:48 +01006122#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_SCOPED_INFO( msg )
6123#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_MSG( #msg " := " << msg, Catch::ResultWas::Info, false, "CATCH_CAPTURE" )
6124
6125#define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
6126
6127#define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
6128#define CATCH_TEST_CASE_NORETURN( name, description ) INTERNAL_CATCH_TESTCASE_NORETURN( name, description )
6129#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "Anonymous test case" )
6130#define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
6131
6132#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
6133
6134#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
6135
6136///////////////
6137// Still to be implemented
6138//#define CHECK_NOFAIL( expr ) // !TBD - reports violation, but doesn't fail Test
6139
6140// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
6141#else
6142
Phil Nash89d1e6c2011-05-24 08:23:02 +01006143#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, false, true, "REQUIRE" )
6144#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, true, "REQUIRE_FALSE" )
6145
6146#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., true, "REQUIRE_THROWS" )
6147#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, true, "REQUIRE_THROWS_AS" )
6148#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, true, "REQUIRE_NOTHROW" )
6149
6150#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, false, false, "CHECK" )
6151#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, false, "CHECK_FALSE" )
Phil Nasha162e222012-02-10 08:30:13 +00006152#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, false, false, "CHECKED_IF" )
6153#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, false, false, "CHECKED_ELSE" )
Phil Nash89d1e6c2011-05-24 08:23:02 +01006154
6155#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., false, "CHECK_THROWS" )
6156#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, false, "CHECK_THROWS_AS" )
6157#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, false, "CHECK_NOTHROW" )
6158
Phil Nash78d95a02012-03-04 21:22:36 +00006159#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, false, "CHECK_THAT" )
6160#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, true, "REQUIRE_THAT" )
6161
Phil Nash89d1e6c2011-05-24 08:23:02 +01006162#define INFO( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Info, false, "INFO" )
6163#define WARN( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Warning, false, "WARN" )
6164#define FAIL( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::ExplicitFailure, true, "FAIL" )
Phil Nasha70fbe32012-08-31 08:10:36 +01006165#define SUCCEED( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Ok, false, "SUCCEED" )
Phil Nash89d1e6c2011-05-24 08:23:02 +01006166#define SCOPED_INFO( msg ) INTERNAL_CATCH_SCOPED_INFO( msg )
6167#define CAPTURE( msg ) INTERNAL_CATCH_MSG( #msg " := " << msg, Catch::ResultWas::Info, false, "CAPTURE" )
6168
6169#define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
6170
6171#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
6172#define TEST_CASE_NORETURN( name, description ) INTERNAL_CATCH_TESTCASE_NORETURN( name, description )
6173#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "Anonymous test case" )
Phil Nash46bcd4b2012-07-20 18:43:48 +01006174#define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
Phil Nash89d1e6c2011-05-24 08:23:02 +01006175
6176#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
Phil Nash89d1e6c2011-05-24 08:23:02 +01006177
6178#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
6179
Phil Nash46bcd4b2012-07-20 18:43:48 +01006180#endif
6181
6182#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
Phil Nash89d1e6c2011-05-24 08:23:02 +01006183
6184using Catch::Detail::Approx;
6185
Phil Nash5bc030d2012-08-16 18:48:50 +01006186#ifdef __clang__
Phil Nasha695eb92012-08-13 07:46:10 +01006187#pragma clang diagnostic pop
Phil Nash5bc030d2012-08-16 18:48:50 +01006188#endif
Phil Nasha695eb92012-08-13 07:46:10 +01006189
Phil Nashaec1e5e2012-05-09 19:37:51 +01006190#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
Phil Nash89d1e6c2011-05-24 08:23:02 +01006191