annotate tests/catch.hpp @ 285:89fe52066db1 tip master

MSCV missing ssize_t fix
author Jamie Bullock <jamie@jamiebullock.com>
date Tue, 16 Jul 2019 18:29:20 +0100
parents ecd6f2cf1346
children
rev   line source
jamie@264 1 /*
jamie@264 2 * CATCH v1.0 build 53 (master branch)
jamie@264 3 * Generated: 2014-08-20 08:08:19.533804
jamie@264 4 * ----------------------------------------------------------
jamie@264 5 * This file has been merged from multiple headers. Please don't edit it directly
jamie@264 6 * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
jamie@264 7 *
jamie@264 8 * Distributed under the Boost Software License, Version 1.0. (See accompanying
jamie@264 9 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
jamie@264 10 */
jamie@264 11 #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
jamie@264 12 #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
jamie@264 13
jamie@264 14 #define TWOBLUECUBES_CATCH_HPP_INCLUDED
jamie@264 15
jamie@264 16 // #included from: internal/catch_suppress_warnings.h
jamie@264 17
jamie@264 18 #define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
jamie@264 19
jamie@264 20 #ifdef __clang__
jamie@264 21 #pragma clang diagnostic ignored "-Wglobal-constructors"
jamie@264 22 #pragma clang diagnostic ignored "-Wvariadic-macros"
jamie@264 23 #pragma clang diagnostic ignored "-Wc99-extensions"
jamie@264 24 #pragma clang diagnostic ignored "-Wunused-variable"
jamie@264 25 #pragma clang diagnostic push
jamie@264 26 #pragma clang diagnostic ignored "-Wpadded"
jamie@264 27 #pragma clang diagnostic ignored "-Wc++98-compat"
jamie@264 28 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
jamie@264 29 #elif defined __GNUC__
jamie@264 30 #pragma GCC diagnostic ignored "-Wvariadic-macros"
jamie@264 31 #pragma GCC diagnostic ignored "-Wunused-variable"
jamie@264 32 #pragma GCC diagnostic push
jamie@264 33 #pragma GCC diagnostic ignored "-Wpadded"
jamie@264 34 #endif
jamie@264 35
jamie@264 36 #ifdef CATCH_CONFIG_MAIN
jamie@264 37 # define CATCH_CONFIG_RUNNER
jamie@264 38 #endif
jamie@264 39
jamie@264 40 #ifdef CATCH_CONFIG_RUNNER
jamie@264 41 # ifndef CLARA_CONFIG_MAIN
jamie@264 42 # define CLARA_CONFIG_MAIN_NOT_DEFINED
jamie@264 43 # define CLARA_CONFIG_MAIN
jamie@264 44 # endif
jamie@264 45 #endif
jamie@264 46
jamie@264 47 // #included from: internal/catch_notimplemented_exception.h
jamie@264 48 #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
jamie@264 49
jamie@264 50 // #included from: catch_common.h
jamie@264 51 #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
jamie@264 52
jamie@264 53 #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
jamie@264 54 #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
jamie@264 55 #define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
jamie@264 56
jamie@264 57 #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
jamie@264 58 #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
jamie@264 59
jamie@264 60 #include <sstream>
jamie@264 61 #include <stdexcept>
jamie@264 62 #include <algorithm>
jamie@264 63
jamie@264 64 // #included from: catch_compiler_capabilities.h
jamie@264 65 #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
jamie@264 66
jamie@264 67 // Much of the following code is based on Boost (1.53)
jamie@264 68
jamie@264 69 #ifdef __clang__
jamie@264 70
jamie@264 71 # if __has_feature(cxx_nullptr)
jamie@264 72 # define CATCH_CONFIG_CPP11_NULLPTR
jamie@264 73 # endif
jamie@264 74
jamie@264 75 # if __has_feature(cxx_noexcept)
jamie@264 76 # define CATCH_CONFIG_CPP11_NOEXCEPT
jamie@264 77 # endif
jamie@264 78
jamie@264 79 #endif // __clang__
jamie@264 80
jamie@264 81 ////////////////////////////////////////////////////////////////////////////////
jamie@264 82 // Borland
jamie@264 83 #ifdef __BORLANDC__
jamie@264 84
jamie@264 85 #if (__BORLANDC__ > 0x582 )
jamie@264 86 //#define CATCH_CONFIG_SFINAE // Not confirmed
jamie@264 87 #endif
jamie@264 88
jamie@264 89 #endif // __BORLANDC__
jamie@264 90
jamie@264 91 ////////////////////////////////////////////////////////////////////////////////
jamie@264 92 // EDG
jamie@264 93 #ifdef __EDG_VERSION__
jamie@264 94
jamie@264 95 #if (__EDG_VERSION__ > 238 )
jamie@264 96 //#define CATCH_CONFIG_SFINAE // Not confirmed
jamie@264 97 #endif
jamie@264 98
jamie@264 99 #endif // __EDG_VERSION__
jamie@264 100
jamie@264 101 ////////////////////////////////////////////////////////////////////////////////
jamie@264 102 // Digital Mars
jamie@264 103 #ifdef __DMC__
jamie@264 104
jamie@264 105 #if (__DMC__ > 0x840 )
jamie@264 106 //#define CATCH_CONFIG_SFINAE // Not confirmed
jamie@264 107 #endif
jamie@264 108
jamie@264 109 #endif // __DMC__
jamie@264 110
jamie@264 111 ////////////////////////////////////////////////////////////////////////////////
jamie@264 112 // GCC
jamie@264 113 #ifdef __GNUC__
jamie@264 114
jamie@264 115 #if __GNUC__ < 3
jamie@264 116
jamie@264 117 #if (__GNUC_MINOR__ >= 96 )
jamie@264 118 //#define CATCH_CONFIG_SFINAE
jamie@264 119 #endif
jamie@264 120
jamie@264 121 #elif __GNUC__ >= 3
jamie@264 122
jamie@264 123 // #define CATCH_CONFIG_SFINAE // Taking this out completely for now
jamie@264 124
jamie@264 125 #endif // __GNUC__ < 3
jamie@264 126
jamie@264 127 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) )
jamie@264 128
jamie@264 129 #define CATCH_CONFIG_CPP11_NULLPTR
jamie@264 130 #endif
jamie@264 131
jamie@264 132 #endif // __GNUC__
jamie@264 133
jamie@264 134 ////////////////////////////////////////////////////////////////////////////////
jamie@264 135 // Visual C++
jamie@264 136 #ifdef _MSC_VER
jamie@264 137
jamie@264 138 #if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
jamie@264 139 //#define CATCH_CONFIG_SFINAE // Not confirmed
jamie@264 140 #endif
jamie@264 141
jamie@264 142 #endif // _MSC_VER
jamie@264 143
jamie@264 144 // Use variadic macros if the compiler supports them
jamie@264 145 #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
jamie@264 146 ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
jamie@264 147 ( defined __GNUC__ && __GNUC__ >= 3 ) || \
jamie@264 148 ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
jamie@264 149
jamie@264 150 #ifndef CATCH_CONFIG_NO_VARIADIC_MACROS
jamie@264 151 #define CATCH_CONFIG_VARIADIC_MACROS
jamie@264 152 #endif
jamie@264 153
jamie@264 154 #endif
jamie@264 155
jamie@264 156 ////////////////////////////////////////////////////////////////////////////////
jamie@264 157 // C++ language feature support
jamie@264 158
jamie@264 159 // detect language version:
jamie@264 160 #if (__cplusplus == 201103L)
jamie@264 161 # define CATCH_CPP11
jamie@264 162 # define CATCH_CPP11_OR_GREATER
jamie@264 163 #elif (__cplusplus >= 201103L)
jamie@264 164 # define CATCH_CPP11_OR_GREATER
jamie@264 165 #endif
jamie@264 166
jamie@264 167 // noexcept support:
jamie@264 168 #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
jamie@264 169 # define CATCH_NOEXCEPT noexcept
jamie@264 170 # define CATCH_NOEXCEPT_IS(x) noexcept(x)
jamie@264 171 #else
jamie@264 172 # define CATCH_NOEXCEPT throw()
jamie@264 173 # define CATCH_NOEXCEPT_IS(x)
jamie@264 174 #endif
jamie@264 175
jamie@264 176 namespace Catch {
jamie@264 177
jamie@264 178 class NonCopyable {
jamie@264 179 NonCopyable( NonCopyable const& );
jamie@264 180 void operator = ( NonCopyable const& );
jamie@264 181 protected:
jamie@264 182 NonCopyable() {}
jamie@264 183 virtual ~NonCopyable();
jamie@264 184 };
jamie@264 185
jamie@264 186 class SafeBool {
jamie@264 187 public:
jamie@264 188 typedef void (SafeBool::*type)() const;
jamie@264 189
jamie@264 190 static type makeSafe( bool value ) {
jamie@264 191 return value ? &SafeBool::trueValue : 0;
jamie@264 192 }
jamie@264 193 private:
jamie@264 194 void trueValue() const {}
jamie@264 195 };
jamie@264 196
jamie@264 197 template<typename ContainerT>
jamie@264 198 inline void deleteAll( ContainerT& container ) {
jamie@264 199 typename ContainerT::const_iterator it = container.begin();
jamie@264 200 typename ContainerT::const_iterator itEnd = container.end();
jamie@264 201 for(; it != itEnd; ++it )
jamie@264 202 delete *it;
jamie@264 203 }
jamie@264 204 template<typename AssociativeContainerT>
jamie@264 205 inline void deleteAllValues( AssociativeContainerT& container ) {
jamie@264 206 typename AssociativeContainerT::const_iterator it = container.begin();
jamie@264 207 typename AssociativeContainerT::const_iterator itEnd = container.end();
jamie@264 208 for(; it != itEnd; ++it )
jamie@264 209 delete it->second;
jamie@264 210 }
jamie@264 211
jamie@264 212 bool startsWith( std::string const& s, std::string const& prefix );
jamie@264 213 bool endsWith( std::string const& s, std::string const& suffix );
jamie@264 214 bool contains( std::string const& s, std::string const& infix );
jamie@264 215 void toLowerInPlace( std::string& s );
jamie@264 216 std::string toLower( std::string const& s );
jamie@264 217 std::string trim( std::string const& str );
jamie@264 218
jamie@264 219 struct pluralise {
jamie@264 220 pluralise( std::size_t count, std::string const& label );
jamie@264 221
jamie@264 222 friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
jamie@264 223
jamie@264 224 std::size_t m_count;
jamie@264 225 std::string m_label;
jamie@264 226 };
jamie@264 227
jamie@264 228 struct SourceLineInfo {
jamie@264 229
jamie@264 230 SourceLineInfo();
jamie@264 231 SourceLineInfo( char const* _file, std::size_t _line );
jamie@264 232 SourceLineInfo( SourceLineInfo const& other );
jamie@264 233 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 234 SourceLineInfo( SourceLineInfo && ) = default;
jamie@264 235 SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
jamie@264 236 SourceLineInfo& operator = ( SourceLineInfo && ) = default;
jamie@264 237 # endif
jamie@264 238 bool empty() const;
jamie@264 239 bool operator == ( SourceLineInfo const& other ) const;
jamie@264 240
jamie@264 241 std::string file;
jamie@264 242 std::size_t line;
jamie@264 243 };
jamie@264 244
jamie@264 245 std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
jamie@264 246
jamie@264 247 // This is just here to avoid compiler warnings with macro constants and boolean literals
jamie@264 248 inline bool isTrue( bool value ){ return value; }
jamie@264 249 inline bool alwaysTrue() { return true; }
jamie@264 250 inline bool alwaysFalse() { return false; }
jamie@264 251
jamie@264 252 void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
jamie@264 253
jamie@264 254 // Use this in variadic streaming macros to allow
jamie@264 255 // >> +StreamEndStop
jamie@264 256 // as well as
jamie@264 257 // >> stuff +StreamEndStop
jamie@264 258 struct StreamEndStop {
jamie@264 259 std::string operator+() {
jamie@264 260 return std::string();
jamie@264 261 }
jamie@264 262 };
jamie@264 263 template<typename T>
jamie@264 264 T const& operator + ( T const& value, StreamEndStop ) {
jamie@264 265 return value;
jamie@264 266 }
jamie@264 267 }
jamie@264 268
jamie@264 269 #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
jamie@264 270 #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
jamie@264 271
jamie@264 272 #include <ostream>
jamie@264 273
jamie@264 274 namespace Catch {
jamie@264 275
jamie@264 276 class NotImplementedException : public std::exception
jamie@264 277 {
jamie@264 278 public:
jamie@264 279 NotImplementedException( SourceLineInfo const& lineInfo );
jamie@264 280 NotImplementedException( NotImplementedException const& ) {}
jamie@264 281
jamie@264 282 virtual ~NotImplementedException() CATCH_NOEXCEPT {}
jamie@264 283
jamie@264 284 virtual const char* what() const CATCH_NOEXCEPT;
jamie@264 285
jamie@264 286 private:
jamie@264 287 std::string m_what;
jamie@264 288 SourceLineInfo m_lineInfo;
jamie@264 289 };
jamie@264 290
jamie@264 291 } // end namespace Catch
jamie@264 292
jamie@264 293 ///////////////////////////////////////////////////////////////////////////////
jamie@264 294 #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
jamie@264 295
jamie@264 296 // #included from: internal/catch_context.h
jamie@264 297 #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
jamie@264 298
jamie@264 299 // #included from: catch_interfaces_generators.h
jamie@264 300 #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
jamie@264 301
jamie@264 302 #include <string>
jamie@264 303
jamie@264 304 namespace Catch {
jamie@264 305
jamie@264 306 struct IGeneratorInfo {
jamie@264 307 virtual ~IGeneratorInfo();
jamie@264 308 virtual bool moveNext() = 0;
jamie@264 309 virtual std::size_t getCurrentIndex() const = 0;
jamie@264 310 };
jamie@264 311
jamie@264 312 struct IGeneratorsForTest {
jamie@264 313 virtual ~IGeneratorsForTest();
jamie@264 314
jamie@264 315 virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
jamie@264 316 virtual bool moveNext() = 0;
jamie@264 317 };
jamie@264 318
jamie@264 319 IGeneratorsForTest* createGeneratorsForTest();
jamie@264 320
jamie@264 321 } // end namespace Catch
jamie@264 322
jamie@264 323 // #included from: catch_ptr.hpp
jamie@264 324 #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
jamie@264 325
jamie@264 326 #ifdef __clang__
jamie@264 327 #pragma clang diagnostic push
jamie@264 328 #pragma clang diagnostic ignored "-Wpadded"
jamie@264 329 #endif
jamie@264 330
jamie@264 331 namespace Catch {
jamie@264 332
jamie@264 333 // An intrusive reference counting smart pointer.
jamie@264 334 // T must implement addRef() and release() methods
jamie@264 335 // typically implementing the IShared interface
jamie@264 336 template<typename T>
jamie@264 337 class Ptr {
jamie@264 338 public:
jamie@264 339 Ptr() : m_p( NULL ){}
jamie@264 340 Ptr( T* p ) : m_p( p ){
jamie@264 341 if( m_p )
jamie@264 342 m_p->addRef();
jamie@264 343 }
jamie@264 344 Ptr( Ptr const& other ) : m_p( other.m_p ){
jamie@264 345 if( m_p )
jamie@264 346 m_p->addRef();
jamie@264 347 }
jamie@264 348 ~Ptr(){
jamie@264 349 if( m_p )
jamie@264 350 m_p->release();
jamie@264 351 }
jamie@264 352 void reset() {
jamie@264 353 if( m_p )
jamie@264 354 m_p->release();
jamie@264 355 m_p = NULL;
jamie@264 356 }
jamie@264 357 Ptr& operator = ( T* p ){
jamie@264 358 Ptr temp( p );
jamie@264 359 swap( temp );
jamie@264 360 return *this;
jamie@264 361 }
jamie@264 362 Ptr& operator = ( Ptr const& other ){
jamie@264 363 Ptr temp( other );
jamie@264 364 swap( temp );
jamie@264 365 return *this;
jamie@264 366 }
jamie@264 367 void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
jamie@264 368 T* get() { return m_p; }
jamie@264 369 const T* get() const{ return m_p; }
jamie@264 370 T& operator*() const { return *m_p; }
jamie@264 371 T* operator->() const { return m_p; }
jamie@264 372 bool operator !() const { return m_p == NULL; }
jamie@264 373 operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); }
jamie@264 374
jamie@264 375 private:
jamie@264 376 T* m_p;
jamie@264 377 };
jamie@264 378
jamie@264 379 struct IShared : NonCopyable {
jamie@264 380 virtual ~IShared();
jamie@264 381 virtual void addRef() const = 0;
jamie@264 382 virtual void release() const = 0;
jamie@264 383 };
jamie@264 384
jamie@264 385 template<typename T = IShared>
jamie@264 386 struct SharedImpl : T {
jamie@264 387
jamie@264 388 SharedImpl() : m_rc( 0 ){}
jamie@264 389
jamie@264 390 virtual void addRef() const {
jamie@264 391 ++m_rc;
jamie@264 392 }
jamie@264 393 virtual void release() const {
jamie@264 394 if( --m_rc == 0 )
jamie@264 395 delete this;
jamie@264 396 }
jamie@264 397
jamie@264 398 mutable unsigned int m_rc;
jamie@264 399 };
jamie@264 400
jamie@264 401 } // end namespace Catch
jamie@264 402
jamie@264 403 #ifdef __clang__
jamie@264 404 #pragma clang diagnostic pop
jamie@264 405 #endif
jamie@264 406
jamie@264 407 #include <memory>
jamie@264 408 #include <vector>
jamie@264 409 #include <stdlib.h>
jamie@264 410
jamie@264 411 namespace Catch {
jamie@264 412
jamie@264 413 class TestCase;
jamie@264 414 class Stream;
jamie@264 415 struct IResultCapture;
jamie@264 416 struct IRunner;
jamie@264 417 struct IGeneratorsForTest;
jamie@264 418 struct IConfig;
jamie@264 419
jamie@264 420 struct IContext
jamie@264 421 {
jamie@264 422 virtual ~IContext();
jamie@264 423
jamie@264 424 virtual IResultCapture* getResultCapture() = 0;
jamie@264 425 virtual IRunner* getRunner() = 0;
jamie@264 426 virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
jamie@264 427 virtual bool advanceGeneratorsForCurrentTest() = 0;
jamie@264 428 virtual Ptr<IConfig const> getConfig() const = 0;
jamie@264 429 };
jamie@264 430
jamie@264 431 struct IMutableContext : IContext
jamie@264 432 {
jamie@264 433 virtual ~IMutableContext();
jamie@264 434 virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
jamie@264 435 virtual void setRunner( IRunner* runner ) = 0;
jamie@264 436 virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
jamie@264 437 };
jamie@264 438
jamie@264 439 IContext& getCurrentContext();
jamie@264 440 IMutableContext& getCurrentMutableContext();
jamie@264 441 void cleanUpContext();
jamie@264 442 Stream createStream( std::string const& streamName );
jamie@264 443
jamie@264 444 }
jamie@264 445
jamie@264 446 // #included from: internal/catch_test_registry.hpp
jamie@264 447 #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
jamie@264 448
jamie@264 449 // #included from: catch_interfaces_testcase.h
jamie@264 450 #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
jamie@264 451
jamie@264 452 #include <vector>
jamie@264 453
jamie@264 454 namespace Catch {
jamie@264 455
jamie@264 456 class TestSpec;
jamie@264 457
jamie@264 458 struct ITestCase : IShared {
jamie@264 459 virtual void invoke () const = 0;
jamie@264 460 protected:
jamie@264 461 virtual ~ITestCase();
jamie@264 462 };
jamie@264 463
jamie@264 464 class TestCase;
jamie@264 465 struct IConfig;
jamie@264 466
jamie@264 467 struct ITestCaseRegistry {
jamie@264 468 virtual ~ITestCaseRegistry();
jamie@264 469 virtual std::vector<TestCase> const& getAllTests() const = 0;
jamie@264 470 virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const = 0;
jamie@264 471
jamie@264 472 };
jamie@264 473 }
jamie@264 474
jamie@264 475 namespace Catch {
jamie@264 476
jamie@264 477 template<typename C>
jamie@264 478 class MethodTestCase : public SharedImpl<ITestCase> {
jamie@264 479
jamie@264 480 public:
jamie@264 481 MethodTestCase( void (C::*method)() ) : m_method( method ) {}
jamie@264 482
jamie@264 483 virtual void invoke() const {
jamie@264 484 C obj;
jamie@264 485 (obj.*m_method)();
jamie@264 486 }
jamie@264 487
jamie@264 488 private:
jamie@264 489 virtual ~MethodTestCase() {}
jamie@264 490
jamie@264 491 void (C::*m_method)();
jamie@264 492 };
jamie@264 493
jamie@264 494 typedef void(*TestFunction)();
jamie@264 495
jamie@264 496 struct NameAndDesc {
jamie@264 497 NameAndDesc( const char* _name = "", const char* _description= "" )
jamie@264 498 : name( _name ), description( _description )
jamie@264 499 {}
jamie@264 500
jamie@264 501 const char* name;
jamie@264 502 const char* description;
jamie@264 503 };
jamie@264 504
jamie@264 505 struct AutoReg {
jamie@264 506
jamie@264 507 AutoReg( TestFunction function,
jamie@264 508 SourceLineInfo const& lineInfo,
jamie@264 509 NameAndDesc const& nameAndDesc );
jamie@264 510
jamie@264 511 template<typename C>
jamie@264 512 AutoReg( void (C::*method)(),
jamie@264 513 char const* className,
jamie@264 514 NameAndDesc const& nameAndDesc,
jamie@264 515 SourceLineInfo const& lineInfo ) {
jamie@264 516 registerTestCase( new MethodTestCase<C>( method ),
jamie@264 517 className,
jamie@264 518 nameAndDesc,
jamie@264 519 lineInfo );
jamie@264 520 }
jamie@264 521
jamie@264 522 void registerTestCase( ITestCase* testCase,
jamie@264 523 char const* className,
jamie@264 524 NameAndDesc const& nameAndDesc,
jamie@264 525 SourceLineInfo const& lineInfo );
jamie@264 526
jamie@264 527 ~AutoReg();
jamie@264 528
jamie@264 529 private:
jamie@264 530 AutoReg( AutoReg const& );
jamie@264 531 void operator= ( AutoReg const& );
jamie@264 532 };
jamie@264 533
jamie@264 534 } // end namespace Catch
jamie@264 535
jamie@264 536 #ifdef CATCH_CONFIG_VARIADIC_MACROS
jamie@264 537 ///////////////////////////////////////////////////////////////////////////////
jamie@264 538 #define INTERNAL_CATCH_TESTCASE( ... ) \
jamie@264 539 static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
jamie@264 540 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
jamie@264 541 static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
jamie@264 542
jamie@264 543 ///////////////////////////////////////////////////////////////////////////////
jamie@264 544 #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
jamie@264 545 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
jamie@264 546
jamie@264 547 ///////////////////////////////////////////////////////////////////////////////
jamie@264 548 #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
jamie@264 549 namespace{ \
jamie@264 550 struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
jamie@264 551 void test(); \
jamie@264 552 }; \
jamie@264 553 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
jamie@264 554 } \
jamie@264 555 void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
jamie@264 556
jamie@264 557 #else
jamie@264 558 ///////////////////////////////////////////////////////////////////////////////
jamie@264 559 #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
jamie@264 560 static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
jamie@264 561 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
jamie@264 562 static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
jamie@264 563
jamie@264 564 ///////////////////////////////////////////////////////////////////////////////
jamie@264 565 #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
jamie@264 566 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
jamie@264 567
jamie@264 568 ///////////////////////////////////////////////////////////////////////////////
jamie@264 569 #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
jamie@264 570 namespace{ \
jamie@264 571 struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
jamie@264 572 void test(); \
jamie@264 573 }; \
jamie@264 574 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
jamie@264 575 } \
jamie@264 576 void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
jamie@264 577
jamie@264 578 #endif
jamie@264 579
jamie@264 580 // #included from: internal/catch_capture.hpp
jamie@264 581 #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
jamie@264 582
jamie@264 583 // #included from: catch_result_builder.h
jamie@264 584 #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
jamie@264 585
jamie@264 586 // #included from: catch_result_type.h
jamie@264 587 #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
jamie@264 588
jamie@264 589 namespace Catch {
jamie@264 590
jamie@264 591 // ResultWas::OfType enum
jamie@264 592 struct ResultWas { enum OfType {
jamie@264 593 Unknown = -1,
jamie@264 594 Ok = 0,
jamie@264 595 Info = 1,
jamie@264 596 Warning = 2,
jamie@264 597
jamie@264 598 FailureBit = 0x10,
jamie@264 599
jamie@264 600 ExpressionFailed = FailureBit | 1,
jamie@264 601 ExplicitFailure = FailureBit | 2,
jamie@264 602
jamie@264 603 Exception = 0x100 | FailureBit,
jamie@264 604
jamie@264 605 ThrewException = Exception | 1,
jamie@264 606 DidntThrowException = Exception | 2
jamie@264 607
jamie@264 608 }; };
jamie@264 609
jamie@264 610 inline bool isOk( ResultWas::OfType resultType ) {
jamie@264 611 return ( resultType & ResultWas::FailureBit ) == 0;
jamie@264 612 }
jamie@264 613 inline bool isJustInfo( int flags ) {
jamie@264 614 return flags == ResultWas::Info;
jamie@264 615 }
jamie@264 616
jamie@264 617 // ResultDisposition::Flags enum
jamie@264 618 struct ResultDisposition { enum Flags {
jamie@264 619 Normal = 0x00,
jamie@264 620
jamie@264 621 ContinueOnFailure = 0x01, // Failures fail test, but execution continues
jamie@264 622 FalseTest = 0x02, // Prefix expression with !
jamie@264 623 SuppressFail = 0x04 // Failures are reported but do not fail the test
jamie@264 624 }; };
jamie@264 625
jamie@264 626 inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
jamie@264 627 return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
jamie@264 628 }
jamie@264 629
jamie@264 630 inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
jamie@264 631 inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
jamie@264 632 inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
jamie@264 633
jamie@264 634 } // end namespace Catch
jamie@264 635
jamie@264 636 // #included from: catch_assertionresult.h
jamie@264 637 #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
jamie@264 638
jamie@264 639 #include <string>
jamie@264 640
jamie@264 641 namespace Catch {
jamie@264 642
jamie@264 643 struct AssertionInfo
jamie@264 644 {
jamie@264 645 AssertionInfo() {}
jamie@264 646 AssertionInfo( std::string const& _macroName,
jamie@264 647 SourceLineInfo const& _lineInfo,
jamie@264 648 std::string const& _capturedExpression,
jamie@264 649 ResultDisposition::Flags _resultDisposition );
jamie@264 650
jamie@264 651 std::string macroName;
jamie@264 652 SourceLineInfo lineInfo;
jamie@264 653 std::string capturedExpression;
jamie@264 654 ResultDisposition::Flags resultDisposition;
jamie@264 655 };
jamie@264 656
jamie@264 657 struct AssertionResultData
jamie@264 658 {
jamie@264 659 AssertionResultData() : resultType( ResultWas::Unknown ) {}
jamie@264 660
jamie@264 661 std::string reconstructedExpression;
jamie@264 662 std::string message;
jamie@264 663 ResultWas::OfType resultType;
jamie@264 664 };
jamie@264 665
jamie@264 666 class AssertionResult {
jamie@264 667 public:
jamie@264 668 AssertionResult();
jamie@264 669 AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
jamie@264 670 ~AssertionResult();
jamie@264 671 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 672 AssertionResult( AssertionResult const& ) = default;
jamie@264 673 AssertionResult( AssertionResult && ) = default;
jamie@264 674 AssertionResult& operator = ( AssertionResult const& ) = default;
jamie@264 675 AssertionResult& operator = ( AssertionResult && ) = default;
jamie@264 676 # endif
jamie@264 677
jamie@264 678 bool isOk() const;
jamie@264 679 bool succeeded() const;
jamie@264 680 ResultWas::OfType getResultType() const;
jamie@264 681 bool hasExpression() const;
jamie@264 682 bool hasMessage() const;
jamie@264 683 std::string getExpression() const;
jamie@264 684 std::string getExpressionInMacro() const;
jamie@264 685 bool hasExpandedExpression() const;
jamie@264 686 std::string getExpandedExpression() const;
jamie@264 687 std::string getMessage() const;
jamie@264 688 SourceLineInfo getSourceInfo() const;
jamie@264 689 std::string getTestMacroName() const;
jamie@264 690
jamie@264 691 protected:
jamie@264 692 AssertionInfo m_info;
jamie@264 693 AssertionResultData m_resultData;
jamie@264 694 };
jamie@264 695
jamie@264 696 } // end namespace Catch
jamie@264 697
jamie@264 698 namespace Catch {
jamie@264 699
jamie@264 700 struct TestFailureException{};
jamie@264 701
jamie@264 702 template<typename T> class ExpressionLhs;
jamie@264 703
jamie@264 704 struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
jamie@264 705
jamie@264 706 struct CopyableStream {
jamie@264 707 CopyableStream() {}
jamie@264 708 CopyableStream( CopyableStream const& other ) {
jamie@264 709 oss << other.oss.str();
jamie@264 710 }
jamie@264 711 CopyableStream& operator=( CopyableStream const& other ) {
jamie@264 712 oss.str("");
jamie@264 713 oss << other.oss.str();
jamie@264 714 return *this;
jamie@264 715 }
jamie@264 716 std::ostringstream oss;
jamie@264 717 };
jamie@264 718
jamie@264 719 class ResultBuilder {
jamie@264 720 public:
jamie@264 721 ResultBuilder( char const* macroName,
jamie@264 722 SourceLineInfo const& lineInfo,
jamie@264 723 char const* capturedExpression,
jamie@264 724 ResultDisposition::Flags resultDisposition );
jamie@264 725
jamie@264 726 template<typename T>
jamie@264 727 ExpressionLhs<T const&> operator->* ( T const& operand );
jamie@264 728 ExpressionLhs<bool> operator->* ( bool value );
jamie@264 729
jamie@264 730 template<typename T>
jamie@264 731 ResultBuilder& operator << ( T const& value ) {
jamie@264 732 m_stream.oss << value;
jamie@264 733 return *this;
jamie@264 734 }
jamie@264 735
jamie@264 736 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
jamie@264 737 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
jamie@264 738
jamie@264 739 ResultBuilder& setResultType( ResultWas::OfType result );
jamie@264 740 ResultBuilder& setResultType( bool result );
jamie@264 741 ResultBuilder& setLhs( std::string const& lhs );
jamie@264 742 ResultBuilder& setRhs( std::string const& rhs );
jamie@264 743 ResultBuilder& setOp( std::string const& op );
jamie@264 744
jamie@264 745 void endExpression();
jamie@264 746
jamie@264 747 std::string reconstructExpression() const;
jamie@264 748 AssertionResult build() const;
jamie@264 749
jamie@264 750 void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
jamie@264 751 void captureResult( ResultWas::OfType resultType );
jamie@264 752 void captureExpression();
jamie@264 753 void react();
jamie@264 754 bool shouldDebugBreak() const;
jamie@264 755 bool allowThrows() const;
jamie@264 756
jamie@264 757 private:
jamie@264 758 AssertionInfo m_assertionInfo;
jamie@264 759 AssertionResultData m_data;
jamie@264 760 struct ExprComponents {
jamie@264 761 ExprComponents() : testFalse( false ) {}
jamie@264 762 bool testFalse;
jamie@264 763 std::string lhs, rhs, op;
jamie@264 764 } m_exprComponents;
jamie@264 765 CopyableStream m_stream;
jamie@264 766
jamie@264 767 bool m_shouldDebugBreak;
jamie@264 768 bool m_shouldThrow;
jamie@264 769 };
jamie@264 770
jamie@264 771 } // namespace Catch
jamie@264 772
jamie@264 773 // Include after due to circular dependency:
jamie@264 774 // #included from: catch_expression_lhs.hpp
jamie@264 775 #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
jamie@264 776
jamie@264 777 // #included from: catch_evaluate.hpp
jamie@264 778 #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
jamie@264 779
jamie@264 780 #ifdef _MSC_VER
jamie@264 781 #pragma warning(push)
jamie@264 782 #pragma warning(disable:4389) // '==' : signed/unsigned mismatch
jamie@264 783 #endif
jamie@264 784
jamie@264 785 #include <cstddef>
jamie@264 786
jamie@264 787 namespace Catch {
jamie@264 788 namespace Internal {
jamie@264 789
jamie@264 790 enum Operator {
jamie@264 791 IsEqualTo,
jamie@264 792 IsNotEqualTo,
jamie@264 793 IsLessThan,
jamie@264 794 IsGreaterThan,
jamie@264 795 IsLessThanOrEqualTo,
jamie@264 796 IsGreaterThanOrEqualTo
jamie@264 797 };
jamie@264 798
jamie@264 799 template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
jamie@264 800 template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
jamie@264 801 template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
jamie@264 802 template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
jamie@264 803 template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
jamie@264 804 template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
jamie@264 805 template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
jamie@264 806
jamie@264 807 template<typename T>
jamie@264 808 inline T& opCast(T const& t) { return const_cast<T&>(t); }
jamie@264 809
jamie@264 810 // nullptr_t support based on pull request #154 from Konstantin Baumann
jamie@264 811 #ifdef CATCH_CONFIG_CPP11_NULLPTR
jamie@264 812 inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
jamie@264 813 #endif // CATCH_CONFIG_CPP11_NULLPTR
jamie@264 814
jamie@264 815 // So the compare overloads can be operator agnostic we convey the operator as a template
jamie@264 816 // enum, which is used to specialise an Evaluator for doing the comparison.
jamie@264 817 template<typename T1, typename T2, Operator Op>
jamie@264 818 class Evaluator{};
jamie@264 819
jamie@264 820 template<typename T1, typename T2>
jamie@264 821 struct Evaluator<T1, T2, IsEqualTo> {
jamie@264 822 static bool evaluate( T1 const& lhs, T2 const& rhs) {
jamie@264 823 return opCast( lhs ) == opCast( rhs );
jamie@264 824 }
jamie@264 825 };
jamie@264 826 template<typename T1, typename T2>
jamie@264 827 struct Evaluator<T1, T2, IsNotEqualTo> {
jamie@264 828 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
jamie@264 829 return opCast( lhs ) != opCast( rhs );
jamie@264 830 }
jamie@264 831 };
jamie@264 832 template<typename T1, typename T2>
jamie@264 833 struct Evaluator<T1, T2, IsLessThan> {
jamie@264 834 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
jamie@264 835 return opCast( lhs ) < opCast( rhs );
jamie@264 836 }
jamie@264 837 };
jamie@264 838 template<typename T1, typename T2>
jamie@264 839 struct Evaluator<T1, T2, IsGreaterThan> {
jamie@264 840 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
jamie@264 841 return opCast( lhs ) > opCast( rhs );
jamie@264 842 }
jamie@264 843 };
jamie@264 844 template<typename T1, typename T2>
jamie@264 845 struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
jamie@264 846 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
jamie@264 847 return opCast( lhs ) >= opCast( rhs );
jamie@264 848 }
jamie@264 849 };
jamie@264 850 template<typename T1, typename T2>
jamie@264 851 struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
jamie@264 852 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
jamie@264 853 return opCast( lhs ) <= opCast( rhs );
jamie@264 854 }
jamie@264 855 };
jamie@264 856
jamie@264 857 template<Operator Op, typename T1, typename T2>
jamie@264 858 bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
jamie@264 859 return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
jamie@264 860 }
jamie@264 861
jamie@264 862 // This level of indirection allows us to specialise for integer types
jamie@264 863 // to avoid signed/ unsigned warnings
jamie@264 864
jamie@264 865 // "base" overload
jamie@264 866 template<Operator Op, typename T1, typename T2>
jamie@264 867 bool compare( T1 const& lhs, T2 const& rhs ) {
jamie@264 868 return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
jamie@264 869 }
jamie@264 870
jamie@264 871 // unsigned X to int
jamie@264 872 template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
jamie@264 873 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
jamie@264 874 }
jamie@264 875 template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
jamie@264 876 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
jamie@264 877 }
jamie@264 878 template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
jamie@264 879 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
jamie@264 880 }
jamie@264 881
jamie@264 882 // unsigned X to long
jamie@264 883 template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
jamie@264 884 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
jamie@264 885 }
jamie@264 886 template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
jamie@264 887 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
jamie@264 888 }
jamie@264 889 template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
jamie@264 890 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
jamie@264 891 }
jamie@264 892
jamie@264 893 // int to unsigned X
jamie@264 894 template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
jamie@264 895 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
jamie@264 896 }
jamie@264 897 template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
jamie@264 898 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
jamie@264 899 }
jamie@264 900 template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
jamie@264 901 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
jamie@264 902 }
jamie@264 903
jamie@264 904 // long to unsigned X
jamie@264 905 template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
jamie@264 906 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
jamie@264 907 }
jamie@264 908 template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
jamie@264 909 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
jamie@264 910 }
jamie@264 911 template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
jamie@264 912 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
jamie@264 913 }
jamie@264 914
jamie@264 915 // pointer to long (when comparing against NULL)
jamie@264 916 template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
jamie@264 917 return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
jamie@264 918 }
jamie@264 919 template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
jamie@264 920 return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
jamie@264 921 }
jamie@264 922
jamie@264 923 // pointer to int (when comparing against NULL)
jamie@264 924 template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
jamie@264 925 return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
jamie@264 926 }
jamie@264 927 template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
jamie@264 928 return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
jamie@264 929 }
jamie@264 930
jamie@264 931 #ifdef CATCH_CONFIG_CPP11_NULLPTR
jamie@264 932 // pointer to nullptr_t (when comparing against nullptr)
jamie@264 933 template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
jamie@264 934 return Evaluator<T*, T*, Op>::evaluate( NULL, rhs );
jamie@264 935 }
jamie@264 936 template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
jamie@264 937 return Evaluator<T*, T*, Op>::evaluate( lhs, NULL );
jamie@264 938 }
jamie@264 939 #endif // CATCH_CONFIG_CPP11_NULLPTR
jamie@264 940
jamie@264 941 } // end of namespace Internal
jamie@264 942 } // end of namespace Catch
jamie@264 943
jamie@264 944 #ifdef _MSC_VER
jamie@264 945 #pragma warning(pop)
jamie@264 946 #endif
jamie@264 947
jamie@264 948 // #included from: catch_tostring.h
jamie@264 949 #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
jamie@264 950
jamie@264 951 // #included from: catch_sfinae.hpp
jamie@264 952 #define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
jamie@264 953
jamie@264 954 // Try to detect if the current compiler supports SFINAE
jamie@264 955
jamie@264 956 namespace Catch {
jamie@264 957
jamie@264 958 struct TrueType {
jamie@264 959 static const bool value = true;
jamie@264 960 typedef void Enable;
jamie@264 961 char sizer[1];
jamie@264 962 };
jamie@264 963 struct FalseType {
jamie@264 964 static const bool value = false;
jamie@264 965 typedef void Disable;
jamie@264 966 char sizer[2];
jamie@264 967 };
jamie@264 968
jamie@264 969 #ifdef CATCH_CONFIG_SFINAE
jamie@264 970
jamie@264 971 template<bool> struct NotABooleanExpression;
jamie@264 972
jamie@264 973 template<bool c> struct If : NotABooleanExpression<c> {};
jamie@264 974 template<> struct If<true> : TrueType {};
jamie@264 975 template<> struct If<false> : FalseType {};
jamie@264 976
jamie@264 977 template<int size> struct SizedIf;
jamie@264 978 template<> struct SizedIf<sizeof(TrueType)> : TrueType {};
jamie@264 979 template<> struct SizedIf<sizeof(FalseType)> : FalseType {};
jamie@264 980
jamie@264 981 #endif // CATCH_CONFIG_SFINAE
jamie@264 982
jamie@264 983 } // end namespace Catch
jamie@264 984
jamie@264 985 #include <sstream>
jamie@264 986 #include <iomanip>
jamie@264 987 #include <limits>
jamie@264 988 #include <vector>
jamie@264 989 #include <cstddef>
jamie@264 990
jamie@264 991 #ifdef __OBJC__
jamie@264 992 // #included from: catch_objc_arc.hpp
jamie@264 993 #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
jamie@264 994
jamie@264 995 #import <Foundation/Foundation.h>
jamie@264 996
jamie@264 997 #ifdef __has_feature
jamie@264 998 #define CATCH_ARC_ENABLED __has_feature(objc_arc)
jamie@264 999 #else
jamie@264 1000 #define CATCH_ARC_ENABLED 0
jamie@264 1001 #endif
jamie@264 1002
jamie@264 1003 void arcSafeRelease( NSObject* obj );
jamie@264 1004 id performOptionalSelector( id obj, SEL sel );
jamie@264 1005
jamie@264 1006 #if !CATCH_ARC_ENABLED
jamie@264 1007 inline void arcSafeRelease( NSObject* obj ) {
jamie@264 1008 [obj release];
jamie@264 1009 }
jamie@264 1010 inline id performOptionalSelector( id obj, SEL sel ) {
jamie@264 1011 if( [obj respondsToSelector: sel] )
jamie@264 1012 return [obj performSelector: sel];
jamie@264 1013 return nil;
jamie@264 1014 }
jamie@264 1015 #define CATCH_UNSAFE_UNRETAINED
jamie@264 1016 #define CATCH_ARC_STRONG
jamie@264 1017 #else
jamie@264 1018 inline void arcSafeRelease( NSObject* ){}
jamie@264 1019 inline id performOptionalSelector( id obj, SEL sel ) {
jamie@264 1020 #ifdef __clang__
jamie@264 1021 #pragma clang diagnostic push
jamie@264 1022 #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
jamie@264 1023 #endif
jamie@264 1024 if( [obj respondsToSelector: sel] )
jamie@264 1025 return [obj performSelector: sel];
jamie@264 1026 #ifdef __clang__
jamie@264 1027 #pragma clang diagnostic pop
jamie@264 1028 #endif
jamie@264 1029 return nil;
jamie@264 1030 }
jamie@264 1031 #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
jamie@264 1032 #define CATCH_ARC_STRONG __strong
jamie@264 1033 #endif
jamie@264 1034
jamie@264 1035 #endif
jamie@264 1036
jamie@264 1037 namespace Catch {
jamie@264 1038 namespace Detail {
jamie@264 1039
jamie@264 1040 // SFINAE is currently disabled by default for all compilers.
jamie@264 1041 // If the non SFINAE version of IsStreamInsertable is ambiguous for you
jamie@264 1042 // and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
jamie@264 1043 #ifdef CATCH_CONFIG_SFINAE
jamie@264 1044
jamie@264 1045 template<typename T>
jamie@264 1046 class IsStreamInsertableHelper {
jamie@264 1047 template<int N> struct TrueIfSizeable : TrueType {};
jamie@264 1048
jamie@264 1049 template<typename T2>
jamie@264 1050 static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
jamie@264 1051 static FalseType dummy(...);
jamie@264 1052
jamie@264 1053 public:
jamie@264 1054 typedef SizedIf<sizeof(dummy((T*)0))> type;
jamie@264 1055 };
jamie@264 1056
jamie@264 1057 template<typename T>
jamie@264 1058 struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
jamie@264 1059
jamie@264 1060 #else
jamie@264 1061
jamie@264 1062 struct BorgType {
jamie@264 1063 template<typename T> BorgType( T const& );
jamie@264 1064 };
jamie@264 1065
jamie@264 1066 TrueType& testStreamable( std::ostream& );
jamie@264 1067 FalseType testStreamable( FalseType );
jamie@264 1068
jamie@264 1069 FalseType operator<<( std::ostream const&, BorgType const& );
jamie@264 1070
jamie@264 1071 template<typename T>
jamie@264 1072 struct IsStreamInsertable {
jamie@264 1073 static std::ostream &s;
jamie@264 1074 static T const&t;
jamie@264 1075 enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
jamie@264 1076 };
jamie@264 1077
jamie@264 1078 #endif
jamie@264 1079
jamie@264 1080 template<bool C>
jamie@264 1081 struct StringMakerBase {
jamie@264 1082 template<typename T>
jamie@264 1083 static std::string convert( T const& ) { return "{?}"; }
jamie@264 1084 };
jamie@264 1085
jamie@264 1086 template<>
jamie@264 1087 struct StringMakerBase<true> {
jamie@264 1088 template<typename T>
jamie@264 1089 static std::string convert( T const& _value ) {
jamie@264 1090 std::ostringstream oss;
jamie@264 1091 oss << _value;
jamie@264 1092 return oss.str();
jamie@264 1093 }
jamie@264 1094 };
jamie@264 1095
jamie@264 1096 std::string rawMemoryToString( const void *object, std::size_t size );
jamie@264 1097
jamie@264 1098 template<typename T>
jamie@264 1099 inline std::string rawMemoryToString( const T& object ) {
jamie@264 1100 return rawMemoryToString( &object, sizeof(object) );
jamie@264 1101 }
jamie@264 1102
jamie@264 1103 } // end namespace Detail
jamie@264 1104
jamie@264 1105 template<typename T>
jamie@264 1106 std::string toString( T const& value );
jamie@264 1107
jamie@264 1108 template<typename T>
jamie@264 1109 struct StringMaker :
jamie@264 1110 Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
jamie@264 1111
jamie@264 1112 template<typename T>
jamie@264 1113 struct StringMaker<T*> {
jamie@264 1114 template<typename U>
jamie@264 1115 static std::string convert( U* p ) {
jamie@264 1116 if( !p )
jamie@264 1117 return INTERNAL_CATCH_STRINGIFY( NULL );
jamie@264 1118 else
jamie@264 1119 return Detail::rawMemoryToString( p );
jamie@264 1120 }
jamie@264 1121 };
jamie@264 1122
jamie@264 1123 template<typename R, typename C>
jamie@264 1124 struct StringMaker<R C::*> {
jamie@264 1125 static std::string convert( R C::* p ) {
jamie@264 1126 if( !p )
jamie@264 1127 return INTERNAL_CATCH_STRINGIFY( NULL );
jamie@264 1128 else
jamie@264 1129 return Detail::rawMemoryToString( p );
jamie@264 1130 }
jamie@264 1131 };
jamie@264 1132
jamie@264 1133 namespace Detail {
jamie@264 1134 template<typename InputIterator>
jamie@264 1135 std::string rangeToString( InputIterator first, InputIterator last );
jamie@264 1136 }
jamie@264 1137
jamie@264 1138 template<typename T, typename Allocator>
jamie@264 1139 struct StringMaker<std::vector<T, Allocator> > {
jamie@264 1140 static std::string convert( std::vector<T,Allocator> const& v ) {
jamie@264 1141 return Detail::rangeToString( v.begin(), v.end() );
jamie@264 1142 }
jamie@264 1143 };
jamie@264 1144
jamie@264 1145 namespace Detail {
jamie@264 1146 template<typename T>
jamie@264 1147 std::string makeString( T const& value ) {
jamie@264 1148 return StringMaker<T>::convert( value );
jamie@264 1149 }
jamie@264 1150 } // end namespace Detail
jamie@264 1151
jamie@264 1152 /// \brief converts any type to a string
jamie@264 1153 ///
jamie@264 1154 /// The default template forwards on to ostringstream - except when an
jamie@264 1155 /// ostringstream overload does not exist - in which case it attempts to detect
jamie@264 1156 /// that and writes {?}.
jamie@264 1157 /// Overload (not specialise) this template for custom typs that you don't want
jamie@264 1158 /// to provide an ostream overload for.
jamie@264 1159 template<typename T>
jamie@264 1160 std::string toString( T const& value ) {
jamie@264 1161 return StringMaker<T>::convert( value );
jamie@264 1162 }
jamie@264 1163
jamie@264 1164 // Built in overloads
jamie@264 1165
jamie@264 1166 std::string toString( std::string const& value );
jamie@264 1167 std::string toString( std::wstring const& value );
jamie@264 1168 std::string toString( const char* const value );
jamie@264 1169 std::string toString( char* const value );
jamie@264 1170 std::string toString( const wchar_t* const value );
jamie@264 1171 std::string toString( wchar_t* const value );
jamie@264 1172 std::string toString( int value );
jamie@264 1173 std::string toString( unsigned long value );
jamie@264 1174 std::string toString( unsigned int value );
jamie@264 1175 std::string toString( const double value );
jamie@264 1176 std::string toString( const float value );
jamie@264 1177 std::string toString( bool value );
jamie@264 1178 std::string toString( char value );
jamie@264 1179 std::string toString( signed char value );
jamie@264 1180 std::string toString( unsigned char value );
jamie@264 1181
jamie@264 1182 #ifdef CATCH_CONFIG_CPP11_NULLPTR
jamie@264 1183 std::string toString( std::nullptr_t );
jamie@264 1184 #endif
jamie@264 1185
jamie@264 1186 #ifdef __OBJC__
jamie@264 1187 std::string toString( NSString const * const& nsstring );
jamie@264 1188 std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
jamie@264 1189 std::string toString( NSObject* const& nsObject );
jamie@264 1190 #endif
jamie@264 1191
jamie@264 1192 namespace Detail {
jamie@264 1193 template<typename InputIterator>
jamie@264 1194 std::string rangeToString( InputIterator first, InputIterator last ) {
jamie@264 1195 std::ostringstream oss;
jamie@264 1196 oss << "{ ";
jamie@264 1197 if( first != last ) {
jamie@264 1198 oss << toString( *first );
jamie@264 1199 for( ++first ; first != last ; ++first ) {
jamie@264 1200 oss << ", " << toString( *first );
jamie@264 1201 }
jamie@264 1202 }
jamie@264 1203 oss << " }";
jamie@264 1204 return oss.str();
jamie@264 1205 }
jamie@264 1206 }
jamie@264 1207
jamie@264 1208 } // end namespace Catch
jamie@264 1209
jamie@264 1210 namespace Catch {
jamie@264 1211
jamie@264 1212 // Wraps the LHS of an expression and captures the operator and RHS (if any) -
jamie@264 1213 // wrapping them all in a ResultBuilder object
jamie@264 1214 template<typename T>
jamie@264 1215 class ExpressionLhs {
jamie@264 1216 ExpressionLhs& operator = ( ExpressionLhs const& );
jamie@264 1217 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 1218 ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
jamie@264 1219 # endif
jamie@264 1220
jamie@264 1221 public:
jamie@264 1222 ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
jamie@264 1223 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 1224 ExpressionLhs( ExpressionLhs const& ) = default;
jamie@264 1225 ExpressionLhs( ExpressionLhs && ) = default;
jamie@264 1226 # endif
jamie@264 1227
jamie@264 1228 template<typename RhsT>
jamie@264 1229 ResultBuilder& operator == ( RhsT const& rhs ) {
jamie@264 1230 return captureExpression<Internal::IsEqualTo>( rhs );
jamie@264 1231 }
jamie@264 1232
jamie@264 1233 template<typename RhsT>
jamie@264 1234 ResultBuilder& operator != ( RhsT const& rhs ) {
jamie@264 1235 return captureExpression<Internal::IsNotEqualTo>( rhs );
jamie@264 1236 }
jamie@264 1237
jamie@264 1238 template<typename RhsT>
jamie@264 1239 ResultBuilder& operator < ( RhsT const& rhs ) {
jamie@264 1240 return captureExpression<Internal::IsLessThan>( rhs );
jamie@264 1241 }
jamie@264 1242
jamie@264 1243 template<typename RhsT>
jamie@264 1244 ResultBuilder& operator > ( RhsT const& rhs ) {
jamie@264 1245 return captureExpression<Internal::IsGreaterThan>( rhs );
jamie@264 1246 }
jamie@264 1247
jamie@264 1248 template<typename RhsT>
jamie@264 1249 ResultBuilder& operator <= ( RhsT const& rhs ) {
jamie@264 1250 return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
jamie@264 1251 }
jamie@264 1252
jamie@264 1253 template<typename RhsT>
jamie@264 1254 ResultBuilder& operator >= ( RhsT const& rhs ) {
jamie@264 1255 return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
jamie@264 1256 }
jamie@264 1257
jamie@264 1258 ResultBuilder& operator == ( bool rhs ) {
jamie@264 1259 return captureExpression<Internal::IsEqualTo>( rhs );
jamie@264 1260 }
jamie@264 1261
jamie@264 1262 ResultBuilder& operator != ( bool rhs ) {
jamie@264 1263 return captureExpression<Internal::IsNotEqualTo>( rhs );
jamie@264 1264 }
jamie@264 1265
jamie@264 1266 void endExpression() {
jamie@264 1267 bool value = m_lhs ? true : false;
jamie@264 1268 m_rb
jamie@264 1269 .setLhs( Catch::toString( value ) )
jamie@264 1270 .setResultType( value )
jamie@264 1271 .endExpression();
jamie@264 1272 }
jamie@264 1273
jamie@264 1274 // Only simple binary expressions are allowed on the LHS.
jamie@264 1275 // If more complex compositions are required then place the sub expression in parentheses
jamie@264 1276 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
jamie@264 1277 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
jamie@264 1278 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
jamie@264 1279 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
jamie@264 1280 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
jamie@264 1281 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
jamie@264 1282
jamie@264 1283 private:
jamie@264 1284 template<Internal::Operator Op, typename RhsT>
jamie@264 1285 ResultBuilder& captureExpression( RhsT const& rhs ) {
jamie@264 1286 return m_rb
jamie@264 1287 .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
jamie@264 1288 .setLhs( Catch::toString( m_lhs ) )
jamie@264 1289 .setRhs( Catch::toString( rhs ) )
jamie@264 1290 .setOp( Internal::OperatorTraits<Op>::getName() );
jamie@264 1291 }
jamie@264 1292
jamie@264 1293 private:
jamie@264 1294 ResultBuilder& m_rb;
jamie@264 1295 T m_lhs;
jamie@264 1296 };
jamie@264 1297
jamie@264 1298 } // end namespace Catch
jamie@264 1299
jamie@264 1300
jamie@264 1301 namespace Catch {
jamie@264 1302
jamie@264 1303 template<typename T>
jamie@264 1304 inline ExpressionLhs<T const&> ResultBuilder::operator->* ( T const& operand ) {
jamie@264 1305 return ExpressionLhs<T const&>( *this, operand );
jamie@264 1306 }
jamie@264 1307
jamie@264 1308 inline ExpressionLhs<bool> ResultBuilder::operator->* ( bool value ) {
jamie@264 1309 return ExpressionLhs<bool>( *this, value );
jamie@264 1310 }
jamie@264 1311
jamie@264 1312 } // namespace Catch
jamie@264 1313
jamie@264 1314 // #included from: catch_message.h
jamie@264 1315 #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
jamie@264 1316
jamie@264 1317 #include <string>
jamie@264 1318
jamie@264 1319 namespace Catch {
jamie@264 1320
jamie@264 1321 struct MessageInfo {
jamie@264 1322 MessageInfo( std::string const& _macroName,
jamie@264 1323 SourceLineInfo const& _lineInfo,
jamie@264 1324 ResultWas::OfType _type );
jamie@264 1325
jamie@264 1326 std::string macroName;
jamie@264 1327 SourceLineInfo lineInfo;
jamie@264 1328 ResultWas::OfType type;
jamie@264 1329 std::string message;
jamie@264 1330 unsigned int sequence;
jamie@264 1331
jamie@264 1332 bool operator == ( MessageInfo const& other ) const {
jamie@264 1333 return sequence == other.sequence;
jamie@264 1334 }
jamie@264 1335 bool operator < ( MessageInfo const& other ) const {
jamie@264 1336 return sequence < other.sequence;
jamie@264 1337 }
jamie@264 1338 private:
jamie@264 1339 static unsigned int globalCount;
jamie@264 1340 };
jamie@264 1341
jamie@264 1342 struct MessageBuilder {
jamie@264 1343 MessageBuilder( std::string const& macroName,
jamie@264 1344 SourceLineInfo const& lineInfo,
jamie@264 1345 ResultWas::OfType type )
jamie@264 1346 : m_info( macroName, lineInfo, type )
jamie@264 1347 {}
jamie@264 1348
jamie@264 1349 template<typename T>
jamie@264 1350 MessageBuilder& operator << ( T const& value ) {
jamie@264 1351 m_stream << value;
jamie@264 1352 return *this;
jamie@264 1353 }
jamie@264 1354
jamie@264 1355 MessageInfo m_info;
jamie@264 1356 std::ostringstream m_stream;
jamie@264 1357 };
jamie@264 1358
jamie@264 1359 class ScopedMessage {
jamie@264 1360 public:
jamie@264 1361 ScopedMessage( MessageBuilder const& builder );
jamie@264 1362 ScopedMessage( ScopedMessage const& other );
jamie@264 1363 ~ScopedMessage();
jamie@264 1364
jamie@264 1365 MessageInfo m_info;
jamie@264 1366 };
jamie@264 1367
jamie@264 1368 } // end namespace Catch
jamie@264 1369
jamie@264 1370 // #included from: catch_interfaces_capture.h
jamie@264 1371 #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
jamie@264 1372
jamie@264 1373 #include <string>
jamie@264 1374
jamie@264 1375 namespace Catch {
jamie@264 1376
jamie@264 1377 class TestCase;
jamie@264 1378 class AssertionResult;
jamie@264 1379 struct AssertionInfo;
jamie@264 1380 struct SectionInfo;
jamie@264 1381 struct MessageInfo;
jamie@264 1382 class ScopedMessageBuilder;
jamie@264 1383 struct Counts;
jamie@264 1384
jamie@264 1385 struct IResultCapture {
jamie@264 1386
jamie@264 1387 virtual ~IResultCapture();
jamie@264 1388
jamie@264 1389 virtual void assertionEnded( AssertionResult const& result ) = 0;
jamie@264 1390 virtual bool sectionStarted( SectionInfo const& sectionInfo,
jamie@264 1391 Counts& assertions ) = 0;
jamie@264 1392 virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
jamie@264 1393 virtual void pushScopedMessage( MessageInfo const& message ) = 0;
jamie@264 1394 virtual void popScopedMessage( MessageInfo const& message ) = 0;
jamie@264 1395
jamie@264 1396 virtual std::string getCurrentTestName() const = 0;
jamie@264 1397 virtual const AssertionResult* getLastResult() const = 0;
jamie@264 1398 };
jamie@264 1399
jamie@264 1400 IResultCapture& getResultCapture();
jamie@264 1401 }
jamie@264 1402
jamie@264 1403 // #included from: catch_debugger.h
jamie@264 1404 #define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
jamie@264 1405
jamie@264 1406 // #included from: catch_platform.h
jamie@264 1407 #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
jamie@264 1408
jamie@264 1409 #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
jamie@264 1410 #define CATCH_PLATFORM_MAC
jamie@264 1411 #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
jamie@264 1412 #define CATCH_PLATFORM_IPHONE
jamie@264 1413 #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
jamie@264 1414 #define CATCH_PLATFORM_WINDOWS
jamie@264 1415 #endif
jamie@264 1416
jamie@264 1417 #include <string>
jamie@264 1418
jamie@264 1419 namespace Catch{
jamie@264 1420
jamie@264 1421 bool isDebuggerActive();
jamie@264 1422 void writeToDebugConsole( std::string const& text );
jamie@264 1423 }
jamie@264 1424
jamie@264 1425 #ifdef CATCH_PLATFORM_MAC
jamie@264 1426
jamie@264 1427 // The following code snippet based on:
jamie@264 1428 // http://cocoawithlove.com/2008/03/break-into-debugger.html
jamie@264 1429 #ifdef DEBUG
jamie@264 1430 #if defined(__ppc64__) || defined(__ppc__)
jamie@264 1431 #define CATCH_BREAK_INTO_DEBUGGER() \
jamie@264 1432 if( Catch::isDebuggerActive() ) { \
jamie@264 1433 __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
jamie@264 1434 : : : "memory","r0","r3","r4" ); \
jamie@264 1435 }
jamie@264 1436 #else
jamie@264 1437 #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
jamie@264 1438 #endif
jamie@264 1439 #endif
jamie@264 1440
jamie@264 1441 #elif defined(_MSC_VER)
jamie@264 1442 #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
jamie@264 1443 #elif defined(__MINGW32__)
jamie@264 1444 extern "C" __declspec(dllimport) void __stdcall DebugBreak();
jamie@264 1445 #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
jamie@264 1446 #endif
jamie@264 1447
jamie@264 1448 #ifndef CATCH_BREAK_INTO_DEBUGGER
jamie@264 1449 #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
jamie@264 1450 #endif
jamie@264 1451
jamie@264 1452 // #included from: catch_interfaces_runner.h
jamie@264 1453 #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
jamie@264 1454
jamie@264 1455 namespace Catch {
jamie@264 1456 class TestCase;
jamie@264 1457
jamie@264 1458 struct IRunner {
jamie@264 1459 virtual ~IRunner();
jamie@264 1460 virtual bool aborting() const = 0;
jamie@264 1461 };
jamie@264 1462 }
jamie@264 1463
jamie@264 1464 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1465 // In the event of a failure works out if the debugger needs to be invoked
jamie@264 1466 // and/or an exception thrown and takes appropriate action.
jamie@264 1467 // This needs to be done as a macro so the debugger will stop in the user
jamie@264 1468 // source code rather than in Catch library code
jamie@264 1469 #define INTERNAL_CATCH_REACT( resultBuilder ) \
jamie@264 1470 if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
jamie@264 1471 resultBuilder.react();
jamie@264 1472
jamie@264 1473 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1474 #define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
jamie@264 1475 do { \
jamie@264 1476 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
jamie@264 1477 try { \
jamie@264 1478 ( __catchResult->*expr ).endExpression(); \
jamie@264 1479 } \
jamie@264 1480 catch( ... ) { \
jamie@264 1481 __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
jamie@264 1482 } \
jamie@264 1483 INTERNAL_CATCH_REACT( __catchResult ) \
jamie@264 1484 } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
jamie@264 1485
jamie@264 1486 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1487 #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
jamie@264 1488 INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
jamie@264 1489 if( Catch::getResultCapture().getLastResult()->succeeded() )
jamie@264 1490
jamie@264 1491 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1492 #define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
jamie@264 1493 INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
jamie@264 1494 if( !Catch::getResultCapture().getLastResult()->succeeded() )
jamie@264 1495
jamie@264 1496 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1497 #define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
jamie@264 1498 do { \
jamie@264 1499 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
jamie@264 1500 try { \
jamie@264 1501 expr; \
jamie@264 1502 __catchResult.captureResult( Catch::ResultWas::Ok ); \
jamie@264 1503 } \
jamie@264 1504 catch( ... ) { \
jamie@264 1505 __catchResult.useActiveException( resultDisposition ); \
jamie@264 1506 } \
jamie@264 1507 INTERNAL_CATCH_REACT( __catchResult ) \
jamie@264 1508 } while( Catch::alwaysFalse() )
jamie@264 1509
jamie@264 1510 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1511 #define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \
jamie@264 1512 do { \
jamie@264 1513 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
jamie@264 1514 if( __catchResult.allowThrows() ) \
jamie@264 1515 try { \
jamie@264 1516 expr; \
jamie@264 1517 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
jamie@264 1518 } \
jamie@264 1519 catch( ... ) { \
jamie@264 1520 __catchResult.captureResult( Catch::ResultWas::Ok ); \
jamie@264 1521 } \
jamie@264 1522 else \
jamie@264 1523 __catchResult.captureResult( Catch::ResultWas::Ok ); \
jamie@264 1524 INTERNAL_CATCH_REACT( __catchResult ) \
jamie@264 1525 } while( Catch::alwaysFalse() )
jamie@264 1526
jamie@264 1527 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1528 #define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
jamie@264 1529 do { \
jamie@264 1530 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
jamie@264 1531 if( __catchResult.allowThrows() ) \
jamie@264 1532 try { \
jamie@264 1533 expr; \
jamie@264 1534 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
jamie@264 1535 } \
jamie@264 1536 catch( exceptionType ) { \
jamie@264 1537 __catchResult.captureResult( Catch::ResultWas::Ok ); \
jamie@264 1538 } \
jamie@264 1539 catch( ... ) { \
jamie@264 1540 __catchResult.useActiveException( resultDisposition ); \
jamie@264 1541 } \
jamie@264 1542 else \
jamie@264 1543 __catchResult.captureResult( Catch::ResultWas::Ok ); \
jamie@264 1544 INTERNAL_CATCH_REACT( __catchResult ) \
jamie@264 1545 } while( Catch::alwaysFalse() )
jamie@264 1546
jamie@264 1547 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1548 #ifdef CATCH_CONFIG_VARIADIC_MACROS
jamie@264 1549 #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
jamie@264 1550 do { \
jamie@264 1551 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
jamie@264 1552 __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
jamie@264 1553 __catchResult.captureResult( messageType ); \
jamie@264 1554 INTERNAL_CATCH_REACT( __catchResult ) \
jamie@264 1555 } while( Catch::alwaysFalse() )
jamie@264 1556 #else
jamie@264 1557 #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
jamie@264 1558 do { \
jamie@264 1559 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
jamie@264 1560 __catchResult << log + ::Catch::StreamEndStop(); \
jamie@264 1561 __catchResult.captureResult( messageType ); \
jamie@264 1562 INTERNAL_CATCH_REACT( __catchResult ) \
jamie@264 1563 } while( Catch::alwaysFalse() )
jamie@264 1564 #endif
jamie@264 1565
jamie@264 1566 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1567 #define INTERNAL_CATCH_INFO( log, macroName ) \
jamie@264 1568 Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
jamie@264 1569
jamie@264 1570 ///////////////////////////////////////////////////////////////////////////////
jamie@264 1571 #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
jamie@264 1572 do { \
jamie@264 1573 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
jamie@264 1574 try { \
jamie@264 1575 std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \
jamie@264 1576 __catchResult \
jamie@264 1577 .setLhs( Catch::toString( arg ) ) \
jamie@264 1578 .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \
jamie@264 1579 .setOp( "matches" ) \
jamie@264 1580 .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
jamie@264 1581 __catchResult.captureExpression(); \
jamie@264 1582 } catch( ... ) { \
jamie@264 1583 __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
jamie@264 1584 } \
jamie@264 1585 INTERNAL_CATCH_REACT( __catchResult ) \
jamie@264 1586 } while( Catch::alwaysFalse() )
jamie@264 1587
jamie@264 1588 // #included from: internal/catch_section.h
jamie@264 1589 #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
jamie@264 1590
jamie@264 1591 // #included from: catch_section_info.h
jamie@264 1592 #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
jamie@264 1593
jamie@264 1594 namespace Catch {
jamie@264 1595
jamie@264 1596 struct SectionInfo {
jamie@264 1597 SectionInfo
jamie@264 1598 ( SourceLineInfo const& _lineInfo,
jamie@264 1599 std::string const& _name,
jamie@264 1600 std::string const& _description = std::string() );
jamie@264 1601
jamie@264 1602 std::string name;
jamie@264 1603 std::string description;
jamie@264 1604 SourceLineInfo lineInfo;
jamie@264 1605 };
jamie@264 1606
jamie@264 1607 } // end namespace Catch
jamie@264 1608
jamie@264 1609 // #included from: catch_totals.hpp
jamie@264 1610 #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
jamie@264 1611
jamie@264 1612 #include <cstddef>
jamie@264 1613
jamie@264 1614 namespace Catch {
jamie@264 1615
jamie@264 1616 struct Counts {
jamie@264 1617 Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
jamie@264 1618
jamie@264 1619 Counts operator - ( Counts const& other ) const {
jamie@264 1620 Counts diff;
jamie@264 1621 diff.passed = passed - other.passed;
jamie@264 1622 diff.failed = failed - other.failed;
jamie@264 1623 diff.failedButOk = failedButOk - other.failedButOk;
jamie@264 1624 return diff;
jamie@264 1625 }
jamie@264 1626 Counts& operator += ( Counts const& other ) {
jamie@264 1627 passed += other.passed;
jamie@264 1628 failed += other.failed;
jamie@264 1629 failedButOk += other.failedButOk;
jamie@264 1630 return *this;
jamie@264 1631 }
jamie@264 1632
jamie@264 1633 std::size_t total() const {
jamie@264 1634 return passed + failed + failedButOk;
jamie@264 1635 }
jamie@264 1636 bool allPassed() const {
jamie@264 1637 return failed == 0 && failedButOk == 0;
jamie@264 1638 }
jamie@264 1639
jamie@264 1640 std::size_t passed;
jamie@264 1641 std::size_t failed;
jamie@264 1642 std::size_t failedButOk;
jamie@264 1643 };
jamie@264 1644
jamie@264 1645 struct Totals {
jamie@264 1646
jamie@264 1647 Totals operator - ( Totals const& other ) const {
jamie@264 1648 Totals diff;
jamie@264 1649 diff.assertions = assertions - other.assertions;
jamie@264 1650 diff.testCases = testCases - other.testCases;
jamie@264 1651 return diff;
jamie@264 1652 }
jamie@264 1653
jamie@264 1654 Totals delta( Totals const& prevTotals ) const {
jamie@264 1655 Totals diff = *this - prevTotals;
jamie@264 1656 if( diff.assertions.failed > 0 )
jamie@264 1657 ++diff.testCases.failed;
jamie@264 1658 else if( diff.assertions.failedButOk > 0 )
jamie@264 1659 ++diff.testCases.failedButOk;
jamie@264 1660 else
jamie@264 1661 ++diff.testCases.passed;
jamie@264 1662 return diff;
jamie@264 1663 }
jamie@264 1664
jamie@264 1665 Totals& operator += ( Totals const& other ) {
jamie@264 1666 assertions += other.assertions;
jamie@264 1667 testCases += other.testCases;
jamie@264 1668 return *this;
jamie@264 1669 }
jamie@264 1670
jamie@264 1671 Counts assertions;
jamie@264 1672 Counts testCases;
jamie@264 1673 };
jamie@264 1674 }
jamie@264 1675
jamie@264 1676 // #included from: catch_timer.h
jamie@264 1677 #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
jamie@264 1678
jamie@264 1679 #ifdef CATCH_PLATFORM_WINDOWS
jamie@264 1680 typedef unsigned long long uint64_t;
jamie@264 1681 #else
jamie@264 1682 #include <stdint.h>
jamie@264 1683 #endif
jamie@264 1684
jamie@264 1685 namespace Catch {
jamie@264 1686
jamie@264 1687 class Timer {
jamie@264 1688 public:
jamie@264 1689 Timer() : m_ticks( 0 ) {}
jamie@264 1690 void start();
jamie@264 1691 unsigned int getElapsedNanoseconds() const;
jamie@264 1692 unsigned int getElapsedMilliseconds() const;
jamie@264 1693 double getElapsedSeconds() const;
jamie@264 1694
jamie@264 1695 private:
jamie@264 1696 uint64_t m_ticks;
jamie@264 1697 };
jamie@264 1698
jamie@264 1699 } // namespace Catch
jamie@264 1700
jamie@264 1701 #include <string>
jamie@264 1702
jamie@264 1703 namespace Catch {
jamie@264 1704
jamie@264 1705 class Section {
jamie@264 1706 public:
jamie@264 1707 Section( SectionInfo const& info );
jamie@264 1708 ~Section();
jamie@264 1709
jamie@264 1710 // This indicates whether the section should be executed or not
jamie@264 1711 operator bool() const;
jamie@264 1712
jamie@264 1713 private:
jamie@264 1714 #ifdef CATCH_CPP11_OR_GREATER
jamie@264 1715 Section( Section const& ) = delete;
jamie@264 1716 Section( Section && ) = delete;
jamie@264 1717 Section& operator = ( Section const& ) = delete;
jamie@264 1718 Section& operator = ( Section && ) = delete;
jamie@264 1719 #else
jamie@264 1720 Section( Section const& info );
jamie@264 1721 Section& operator = ( Section const& );
jamie@264 1722 #endif
jamie@264 1723 SectionInfo m_info;
jamie@264 1724
jamie@264 1725 std::string m_name;
jamie@264 1726 Counts m_assertions;
jamie@264 1727 bool m_sectionIncluded;
jamie@264 1728 Timer m_timer;
jamie@264 1729 };
jamie@264 1730
jamie@264 1731 } // end namespace Catch
jamie@264 1732
jamie@264 1733 #ifdef CATCH_CONFIG_VARIADIC_MACROS
jamie@264 1734 #define INTERNAL_CATCH_SECTION( ... ) \
jamie@264 1735 if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
jamie@264 1736 #else
jamie@264 1737 #define INTERNAL_CATCH_SECTION( name, desc ) \
jamie@264 1738 if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
jamie@264 1739 #endif
jamie@264 1740
jamie@264 1741 // #included from: internal/catch_generators.hpp
jamie@264 1742 #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
jamie@264 1743
jamie@264 1744 #include <iterator>
jamie@264 1745 #include <vector>
jamie@264 1746 #include <string>
jamie@264 1747 #include <stdlib.h>
jamie@264 1748
jamie@264 1749 namespace Catch {
jamie@264 1750
jamie@264 1751 template<typename T>
jamie@264 1752 struct IGenerator {
jamie@264 1753 virtual ~IGenerator() {}
jamie@264 1754 virtual T getValue( std::size_t index ) const = 0;
jamie@264 1755 virtual std::size_t size () const = 0;
jamie@264 1756 };
jamie@264 1757
jamie@264 1758 template<typename T>
jamie@264 1759 class BetweenGenerator : public IGenerator<T> {
jamie@264 1760 public:
jamie@264 1761 BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
jamie@264 1762
jamie@264 1763 virtual T getValue( std::size_t index ) const {
jamie@264 1764 return m_from+static_cast<int>( index );
jamie@264 1765 }
jamie@264 1766
jamie@264 1767 virtual std::size_t size() const {
jamie@264 1768 return static_cast<std::size_t>( 1+m_to-m_from );
jamie@264 1769 }
jamie@264 1770
jamie@264 1771 private:
jamie@264 1772
jamie@264 1773 T m_from;
jamie@264 1774 T m_to;
jamie@264 1775 };
jamie@264 1776
jamie@264 1777 template<typename T>
jamie@264 1778 class ValuesGenerator : public IGenerator<T> {
jamie@264 1779 public:
jamie@264 1780 ValuesGenerator(){}
jamie@264 1781
jamie@264 1782 void add( T value ) {
jamie@264 1783 m_values.push_back( value );
jamie@264 1784 }
jamie@264 1785
jamie@264 1786 virtual T getValue( std::size_t index ) const {
jamie@264 1787 return m_values[index];
jamie@264 1788 }
jamie@264 1789
jamie@264 1790 virtual std::size_t size() const {
jamie@264 1791 return m_values.size();
jamie@264 1792 }
jamie@264 1793
jamie@264 1794 private:
jamie@264 1795 std::vector<T> m_values;
jamie@264 1796 };
jamie@264 1797
jamie@264 1798 template<typename T>
jamie@264 1799 class CompositeGenerator {
jamie@264 1800 public:
jamie@264 1801 CompositeGenerator() : m_totalSize( 0 ) {}
jamie@264 1802
jamie@264 1803 // *** Move semantics, similar to auto_ptr ***
jamie@264 1804 CompositeGenerator( CompositeGenerator& other )
jamie@264 1805 : m_fileInfo( other.m_fileInfo ),
jamie@264 1806 m_totalSize( 0 )
jamie@264 1807 {
jamie@264 1808 move( other );
jamie@264 1809 }
jamie@264 1810
jamie@264 1811 CompositeGenerator& setFileInfo( const char* fileInfo ) {
jamie@264 1812 m_fileInfo = fileInfo;
jamie@264 1813 return *this;
jamie@264 1814 }
jamie@264 1815
jamie@264 1816 ~CompositeGenerator() {
jamie@264 1817 deleteAll( m_composed );
jamie@264 1818 }
jamie@264 1819
jamie@264 1820 operator T () const {
jamie@264 1821 size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
jamie@264 1822
jamie@264 1823 typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
jamie@264 1824 typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
jamie@264 1825 for( size_t index = 0; it != itEnd; ++it )
jamie@264 1826 {
jamie@264 1827 const IGenerator<T>* generator = *it;
jamie@264 1828 if( overallIndex >= index && overallIndex < index + generator->size() )
jamie@264 1829 {
jamie@264 1830 return generator->getValue( overallIndex-index );
jamie@264 1831 }
jamie@264 1832 index += generator->size();
jamie@264 1833 }
jamie@264 1834 CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
jamie@264 1835 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
jamie@264 1836 }
jamie@264 1837
jamie@264 1838 void add( const IGenerator<T>* generator ) {
jamie@264 1839 m_totalSize += generator->size();
jamie@264 1840 m_composed.push_back( generator );
jamie@264 1841 }
jamie@264 1842
jamie@264 1843 CompositeGenerator& then( CompositeGenerator& other ) {
jamie@264 1844 move( other );
jamie@264 1845 return *this;
jamie@264 1846 }
jamie@264 1847
jamie@264 1848 CompositeGenerator& then( T value ) {
jamie@264 1849 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
jamie@264 1850 valuesGen->add( value );
jamie@264 1851 add( valuesGen );
jamie@264 1852 return *this;
jamie@264 1853 }
jamie@264 1854
jamie@264 1855 private:
jamie@264 1856
jamie@264 1857 void move( CompositeGenerator& other ) {
jamie@264 1858 std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
jamie@264 1859 m_totalSize += other.m_totalSize;
jamie@264 1860 other.m_composed.clear();
jamie@264 1861 }
jamie@264 1862
jamie@264 1863 std::vector<const IGenerator<T>*> m_composed;
jamie@264 1864 std::string m_fileInfo;
jamie@264 1865 size_t m_totalSize;
jamie@264 1866 };
jamie@264 1867
jamie@264 1868 namespace Generators
jamie@264 1869 {
jamie@264 1870 template<typename T>
jamie@264 1871 CompositeGenerator<T> between( T from, T to ) {
jamie@264 1872 CompositeGenerator<T> generators;
jamie@264 1873 generators.add( new BetweenGenerator<T>( from, to ) );
jamie@264 1874 return generators;
jamie@264 1875 }
jamie@264 1876
jamie@264 1877 template<typename T>
jamie@264 1878 CompositeGenerator<T> values( T val1, T val2 ) {
jamie@264 1879 CompositeGenerator<T> generators;
jamie@264 1880 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
jamie@264 1881 valuesGen->add( val1 );
jamie@264 1882 valuesGen->add( val2 );
jamie@264 1883 generators.add( valuesGen );
jamie@264 1884 return generators;
jamie@264 1885 }
jamie@264 1886
jamie@264 1887 template<typename T>
jamie@264 1888 CompositeGenerator<T> values( T val1, T val2, T val3 ){
jamie@264 1889 CompositeGenerator<T> generators;
jamie@264 1890 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
jamie@264 1891 valuesGen->add( val1 );
jamie@264 1892 valuesGen->add( val2 );
jamie@264 1893 valuesGen->add( val3 );
jamie@264 1894 generators.add( valuesGen );
jamie@264 1895 return generators;
jamie@264 1896 }
jamie@264 1897
jamie@264 1898 template<typename T>
jamie@264 1899 CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
jamie@264 1900 CompositeGenerator<T> generators;
jamie@264 1901 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
jamie@264 1902 valuesGen->add( val1 );
jamie@264 1903 valuesGen->add( val2 );
jamie@264 1904 valuesGen->add( val3 );
jamie@264 1905 valuesGen->add( val4 );
jamie@264 1906 generators.add( valuesGen );
jamie@264 1907 return generators;
jamie@264 1908 }
jamie@264 1909
jamie@264 1910 } // end namespace Generators
jamie@264 1911
jamie@264 1912 using namespace Generators;
jamie@264 1913
jamie@264 1914 } // end namespace Catch
jamie@264 1915
jamie@264 1916 #define INTERNAL_CATCH_LINESTR2( line ) #line
jamie@264 1917 #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
jamie@264 1918
jamie@264 1919 #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
jamie@264 1920
jamie@264 1921 // #included from: internal/catch_interfaces_exception.h
jamie@264 1922 #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
jamie@264 1923
jamie@264 1924 #include <string>
jamie@264 1925 // #included from: catch_interfaces_registry_hub.h
jamie@264 1926 #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
jamie@264 1927
jamie@264 1928 #include <string>
jamie@264 1929
jamie@264 1930 namespace Catch {
jamie@264 1931
jamie@264 1932 class TestCase;
jamie@264 1933 struct ITestCaseRegistry;
jamie@264 1934 struct IExceptionTranslatorRegistry;
jamie@264 1935 struct IExceptionTranslator;
jamie@264 1936 struct IReporterRegistry;
jamie@264 1937 struct IReporterFactory;
jamie@264 1938
jamie@264 1939 struct IRegistryHub {
jamie@264 1940 virtual ~IRegistryHub();
jamie@264 1941
jamie@264 1942 virtual IReporterRegistry const& getReporterRegistry() const = 0;
jamie@264 1943 virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
jamie@264 1944 virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
jamie@264 1945 };
jamie@264 1946
jamie@264 1947 struct IMutableRegistryHub {
jamie@264 1948 virtual ~IMutableRegistryHub();
jamie@264 1949 virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0;
jamie@264 1950 virtual void registerTest( TestCase const& testInfo ) = 0;
jamie@264 1951 virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
jamie@264 1952 };
jamie@264 1953
jamie@264 1954 IRegistryHub& getRegistryHub();
jamie@264 1955 IMutableRegistryHub& getMutableRegistryHub();
jamie@264 1956 void cleanUp();
jamie@264 1957 std::string translateActiveException();
jamie@264 1958
jamie@264 1959 }
jamie@264 1960
jamie@264 1961
jamie@264 1962 namespace Catch {
jamie@264 1963
jamie@264 1964 typedef std::string(*exceptionTranslateFunction)();
jamie@264 1965
jamie@264 1966 struct IExceptionTranslator {
jamie@264 1967 virtual ~IExceptionTranslator();
jamie@264 1968 virtual std::string translate() const = 0;
jamie@264 1969 };
jamie@264 1970
jamie@264 1971 struct IExceptionTranslatorRegistry {
jamie@264 1972 virtual ~IExceptionTranslatorRegistry();
jamie@264 1973
jamie@264 1974 virtual std::string translateActiveException() const = 0;
jamie@264 1975 };
jamie@264 1976
jamie@264 1977 class ExceptionTranslatorRegistrar {
jamie@264 1978 template<typename T>
jamie@264 1979 class ExceptionTranslator : public IExceptionTranslator {
jamie@264 1980 public:
jamie@264 1981
jamie@264 1982 ExceptionTranslator( std::string(*translateFunction)( T& ) )
jamie@264 1983 : m_translateFunction( translateFunction )
jamie@264 1984 {}
jamie@264 1985
jamie@264 1986 virtual std::string translate() const {
jamie@264 1987 try {
jamie@264 1988 throw;
jamie@264 1989 }
jamie@264 1990 catch( T& ex ) {
jamie@264 1991 return m_translateFunction( ex );
jamie@264 1992 }
jamie@264 1993 }
jamie@264 1994
jamie@264 1995 protected:
jamie@264 1996 std::string(*m_translateFunction)( T& );
jamie@264 1997 };
jamie@264 1998
jamie@264 1999 public:
jamie@264 2000 template<typename T>
jamie@264 2001 ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
jamie@264 2002 getMutableRegistryHub().registerTranslator
jamie@264 2003 ( new ExceptionTranslator<T>( translateFunction ) );
jamie@264 2004 }
jamie@264 2005 };
jamie@264 2006 }
jamie@264 2007
jamie@264 2008 ///////////////////////////////////////////////////////////////////////////////
jamie@264 2009 #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
jamie@264 2010 static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
jamie@264 2011 namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
jamie@264 2012 static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
jamie@264 2013
jamie@264 2014 // #included from: internal/catch_approx.hpp
jamie@264 2015 #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
jamie@264 2016
jamie@264 2017 #include <cmath>
jamie@264 2018 #include <limits>
jamie@264 2019
jamie@264 2020 namespace Catch {
jamie@264 2021 namespace Detail {
jamie@264 2022
jamie@264 2023 class Approx {
jamie@264 2024 public:
jamie@264 2025 explicit Approx ( double value )
jamie@264 2026 : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
jamie@264 2027 m_scale( 1.0 ),
jamie@264 2028 m_value( value )
jamie@264 2029 {}
jamie@264 2030
jamie@264 2031 Approx( Approx const& other )
jamie@264 2032 : m_epsilon( other.m_epsilon ),
jamie@264 2033 m_scale( other.m_scale ),
jamie@264 2034 m_value( other.m_value )
jamie@264 2035 {}
jamie@264 2036
jamie@264 2037 static Approx custom() {
jamie@264 2038 return Approx( 0 );
jamie@264 2039 }
jamie@264 2040
jamie@264 2041 Approx operator()( double value ) {
jamie@264 2042 Approx approx( value );
jamie@264 2043 approx.epsilon( m_epsilon );
jamie@264 2044 approx.scale( m_scale );
jamie@264 2045 return approx;
jamie@264 2046 }
jamie@264 2047
jamie@264 2048 friend bool operator == ( double lhs, Approx const& rhs ) {
jamie@264 2049 // Thanks to Richard Harris for his help refining this formula
jamie@264 2050 return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
jamie@264 2051 }
jamie@264 2052
jamie@264 2053 friend bool operator == ( Approx const& lhs, double rhs ) {
jamie@264 2054 return operator==( rhs, lhs );
jamie@264 2055 }
jamie@264 2056
jamie@264 2057 friend bool operator != ( double lhs, Approx const& rhs ) {
jamie@264 2058 return !operator==( lhs, rhs );
jamie@264 2059 }
jamie@264 2060
jamie@264 2061 friend bool operator != ( Approx const& lhs, double rhs ) {
jamie@264 2062 return !operator==( rhs, lhs );
jamie@264 2063 }
jamie@264 2064
jamie@264 2065 Approx& epsilon( double newEpsilon ) {
jamie@264 2066 m_epsilon = newEpsilon;
jamie@264 2067 return *this;
jamie@264 2068 }
jamie@264 2069
jamie@264 2070 Approx& scale( double newScale ) {
jamie@264 2071 m_scale = newScale;
jamie@264 2072 return *this;
jamie@264 2073 }
jamie@264 2074
jamie@264 2075 std::string toString() const {
jamie@264 2076 std::ostringstream oss;
jamie@264 2077 oss << "Approx( " << Catch::toString( m_value ) << " )";
jamie@264 2078 return oss.str();
jamie@264 2079 }
jamie@264 2080
jamie@264 2081 private:
jamie@264 2082 double m_epsilon;
jamie@264 2083 double m_scale;
jamie@264 2084 double m_value;
jamie@264 2085 };
jamie@264 2086 }
jamie@264 2087
jamie@264 2088 template<>
jamie@264 2089 inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
jamie@264 2090 return value.toString();
jamie@264 2091 }
jamie@264 2092
jamie@264 2093 } // end namespace Catch
jamie@264 2094
jamie@264 2095 // #included from: internal/catch_matchers.hpp
jamie@264 2096 #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
jamie@264 2097
jamie@264 2098 namespace Catch {
jamie@264 2099 namespace Matchers {
jamie@264 2100 namespace Impl {
jamie@264 2101
jamie@264 2102 template<typename ExpressionT>
jamie@264 2103 struct Matcher : SharedImpl<IShared>
jamie@264 2104 {
jamie@264 2105 typedef ExpressionT ExpressionType;
jamie@264 2106
jamie@264 2107 virtual ~Matcher() {}
jamie@264 2108 virtual Ptr<Matcher> clone() const = 0;
jamie@264 2109 virtual bool match( ExpressionT const& expr ) const = 0;
jamie@264 2110 virtual std::string toString() const = 0;
jamie@264 2111 };
jamie@264 2112
jamie@264 2113 template<typename DerivedT, typename ExpressionT>
jamie@264 2114 struct MatcherImpl : Matcher<ExpressionT> {
jamie@264 2115
jamie@264 2116 virtual Ptr<Matcher<ExpressionT> > clone() const {
jamie@264 2117 return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
jamie@264 2118 }
jamie@264 2119 };
jamie@264 2120
jamie@264 2121 namespace Generic {
jamie@264 2122
jamie@264 2123 template<typename ExpressionT>
jamie@264 2124 class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
jamie@264 2125 public:
jamie@264 2126
jamie@264 2127 AllOf() {}
jamie@264 2128 AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
jamie@264 2129
jamie@264 2130 AllOf& add( Matcher<ExpressionT> const& matcher ) {
jamie@264 2131 m_matchers.push_back( matcher.clone() );
jamie@264 2132 return *this;
jamie@264 2133 }
jamie@264 2134 virtual bool match( ExpressionT const& expr ) const
jamie@264 2135 {
jamie@264 2136 for( std::size_t i = 0; i < m_matchers.size(); ++i )
jamie@264 2137 if( !m_matchers[i]->match( expr ) )
jamie@264 2138 return false;
jamie@264 2139 return true;
jamie@264 2140 }
jamie@264 2141 virtual std::string toString() const {
jamie@264 2142 std::ostringstream oss;
jamie@264 2143 oss << "( ";
jamie@264 2144 for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
jamie@264 2145 if( i != 0 )
jamie@264 2146 oss << " and ";
jamie@264 2147 oss << m_matchers[i]->toString();
jamie@264 2148 }
jamie@264 2149 oss << " )";
jamie@264 2150 return oss.str();
jamie@264 2151 }
jamie@264 2152
jamie@264 2153 private:
jamie@264 2154 std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
jamie@264 2155 };
jamie@264 2156
jamie@264 2157 template<typename ExpressionT>
jamie@264 2158 class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
jamie@264 2159 public:
jamie@264 2160
jamie@264 2161 AnyOf() {}
jamie@264 2162 AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
jamie@264 2163
jamie@264 2164 AnyOf& add( Matcher<ExpressionT> const& matcher ) {
jamie@264 2165 m_matchers.push_back( matcher.clone() );
jamie@264 2166 return *this;
jamie@264 2167 }
jamie@264 2168 virtual bool match( ExpressionT const& expr ) const
jamie@264 2169 {
jamie@264 2170 for( std::size_t i = 0; i < m_matchers.size(); ++i )
jamie@264 2171 if( m_matchers[i]->match( expr ) )
jamie@264 2172 return true;
jamie@264 2173 return false;
jamie@264 2174 }
jamie@264 2175 virtual std::string toString() const {
jamie@264 2176 std::ostringstream oss;
jamie@264 2177 oss << "( ";
jamie@264 2178 for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
jamie@264 2179 if( i != 0 )
jamie@264 2180 oss << " or ";
jamie@264 2181 oss << m_matchers[i]->toString();
jamie@264 2182 }
jamie@264 2183 oss << " )";
jamie@264 2184 return oss.str();
jamie@264 2185 }
jamie@264 2186
jamie@264 2187 private:
jamie@264 2188 std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
jamie@264 2189 };
jamie@264 2190
jamie@264 2191 }
jamie@264 2192
jamie@264 2193 namespace StdString {
jamie@264 2194
jamie@264 2195 inline std::string makeString( std::string const& str ) { return str; }
jamie@264 2196 inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
jamie@264 2197
jamie@264 2198 struct Equals : MatcherImpl<Equals, std::string> {
jamie@264 2199 Equals( std::string const& str ) : m_str( str ){}
jamie@264 2200 Equals( Equals const& other ) : m_str( other.m_str ){}
jamie@264 2201
jamie@264 2202 virtual ~Equals();
jamie@264 2203
jamie@264 2204 virtual bool match( std::string const& expr ) const {
jamie@264 2205 return m_str == expr;
jamie@264 2206 }
jamie@264 2207 virtual std::string toString() const {
jamie@264 2208 return "equals: \"" + m_str + "\"";
jamie@264 2209 }
jamie@264 2210
jamie@264 2211 std::string m_str;
jamie@264 2212 };
jamie@264 2213
jamie@264 2214 struct Contains : MatcherImpl<Contains, std::string> {
jamie@264 2215 Contains( std::string const& substr ) : m_substr( substr ){}
jamie@264 2216 Contains( Contains const& other ) : m_substr( other.m_substr ){}
jamie@264 2217
jamie@264 2218 virtual ~Contains();
jamie@264 2219
jamie@264 2220 virtual bool match( std::string const& expr ) const {
jamie@264 2221 return expr.find( m_substr ) != std::string::npos;
jamie@264 2222 }
jamie@264 2223 virtual std::string toString() const {
jamie@264 2224 return "contains: \"" + m_substr + "\"";
jamie@264 2225 }
jamie@264 2226
jamie@264 2227 std::string m_substr;
jamie@264 2228 };
jamie@264 2229
jamie@264 2230 struct StartsWith : MatcherImpl<StartsWith, std::string> {
jamie@264 2231 StartsWith( std::string const& substr ) : m_substr( substr ){}
jamie@264 2232 StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){}
jamie@264 2233
jamie@264 2234 virtual ~StartsWith();
jamie@264 2235
jamie@264 2236 virtual bool match( std::string const& expr ) const {
jamie@264 2237 return expr.find( m_substr ) == 0;
jamie@264 2238 }
jamie@264 2239 virtual std::string toString() const {
jamie@264 2240 return "starts with: \"" + m_substr + "\"";
jamie@264 2241 }
jamie@264 2242
jamie@264 2243 std::string m_substr;
jamie@264 2244 };
jamie@264 2245
jamie@264 2246 struct EndsWith : MatcherImpl<EndsWith, std::string> {
jamie@264 2247 EndsWith( std::string const& substr ) : m_substr( substr ){}
jamie@264 2248 EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){}
jamie@264 2249
jamie@264 2250 virtual ~EndsWith();
jamie@264 2251
jamie@264 2252 virtual bool match( std::string const& expr ) const {
jamie@264 2253 return expr.find( m_substr ) == expr.size() - m_substr.size();
jamie@264 2254 }
jamie@264 2255 virtual std::string toString() const {
jamie@264 2256 return "ends with: \"" + m_substr + "\"";
jamie@264 2257 }
jamie@264 2258
jamie@264 2259 std::string m_substr;
jamie@264 2260 };
jamie@264 2261 } // namespace StdString
jamie@264 2262 } // namespace Impl
jamie@264 2263
jamie@264 2264 // The following functions create the actual matcher objects.
jamie@264 2265 // This allows the types to be inferred
jamie@264 2266 template<typename ExpressionT>
jamie@264 2267 inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
jamie@264 2268 Impl::Matcher<ExpressionT> const& m2 ) {
jamie@264 2269 return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
jamie@264 2270 }
jamie@264 2271 template<typename ExpressionT>
jamie@264 2272 inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
jamie@264 2273 Impl::Matcher<ExpressionT> const& m2,
jamie@264 2274 Impl::Matcher<ExpressionT> const& m3 ) {
jamie@264 2275 return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
jamie@264 2276 }
jamie@264 2277 template<typename ExpressionT>
jamie@264 2278 inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
jamie@264 2279 Impl::Matcher<ExpressionT> const& m2 ) {
jamie@264 2280 return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
jamie@264 2281 }
jamie@264 2282 template<typename ExpressionT>
jamie@264 2283 inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
jamie@264 2284 Impl::Matcher<ExpressionT> const& m2,
jamie@264 2285 Impl::Matcher<ExpressionT> const& m3 ) {
jamie@264 2286 return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
jamie@264 2287 }
jamie@264 2288
jamie@264 2289 inline Impl::StdString::Equals Equals( std::string const& str ) {
jamie@264 2290 return Impl::StdString::Equals( str );
jamie@264 2291 }
jamie@264 2292 inline Impl::StdString::Equals Equals( const char* str ) {
jamie@264 2293 return Impl::StdString::Equals( Impl::StdString::makeString( str ) );
jamie@264 2294 }
jamie@264 2295 inline Impl::StdString::Contains Contains( std::string const& substr ) {
jamie@264 2296 return Impl::StdString::Contains( substr );
jamie@264 2297 }
jamie@264 2298 inline Impl::StdString::Contains Contains( const char* substr ) {
jamie@264 2299 return Impl::StdString::Contains( Impl::StdString::makeString( substr ) );
jamie@264 2300 }
jamie@264 2301 inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
jamie@264 2302 return Impl::StdString::StartsWith( substr );
jamie@264 2303 }
jamie@264 2304 inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
jamie@264 2305 return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
jamie@264 2306 }
jamie@264 2307 inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
jamie@264 2308 return Impl::StdString::EndsWith( substr );
jamie@264 2309 }
jamie@264 2310 inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
jamie@264 2311 return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
jamie@264 2312 }
jamie@264 2313
jamie@264 2314 } // namespace Matchers
jamie@264 2315
jamie@264 2316 using namespace Matchers;
jamie@264 2317
jamie@264 2318 } // namespace Catch
jamie@264 2319
jamie@264 2320 // #included from: internal/catch_interfaces_tag_alias_registry.h
jamie@264 2321 #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
jamie@264 2322
jamie@264 2323 // #included from: catch_tag_alias.h
jamie@264 2324 #define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
jamie@264 2325
jamie@264 2326 #include <string>
jamie@264 2327
jamie@264 2328 namespace Catch {
jamie@264 2329
jamie@264 2330 struct TagAlias {
jamie@264 2331 TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
jamie@264 2332
jamie@264 2333 std::string tag;
jamie@264 2334 SourceLineInfo lineInfo;
jamie@264 2335 };
jamie@264 2336
jamie@264 2337 struct RegistrarForTagAliases {
jamie@264 2338 RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
jamie@264 2339 };
jamie@264 2340
jamie@264 2341 } // end namespace Catch
jamie@264 2342
jamie@264 2343 #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
jamie@264 2344 // #included from: catch_option.hpp
jamie@264 2345 #define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
jamie@264 2346
jamie@264 2347 namespace Catch {
jamie@264 2348
jamie@264 2349 // An optional type
jamie@264 2350 template<typename T>
jamie@264 2351 class Option {
jamie@264 2352 public:
jamie@264 2353 Option() : nullableValue( NULL ) {}
jamie@264 2354 Option( T const& _value )
jamie@264 2355 : nullableValue( new( storage ) T( _value ) )
jamie@264 2356 {}
jamie@264 2357 Option( Option const& _other )
jamie@264 2358 : nullableValue( _other ? new( storage ) T( *_other ) : NULL )
jamie@264 2359 {}
jamie@264 2360
jamie@264 2361 ~Option() {
jamie@264 2362 reset();
jamie@264 2363 }
jamie@264 2364
jamie@264 2365 Option& operator= ( Option const& _other ) {
jamie@264 2366 if( &_other != this ) {
jamie@264 2367 reset();
jamie@264 2368 if( _other )
jamie@264 2369 nullableValue = new( storage ) T( *_other );
jamie@264 2370 }
jamie@264 2371 return *this;
jamie@264 2372 }
jamie@264 2373 Option& operator = ( T const& _value ) {
jamie@264 2374 reset();
jamie@264 2375 nullableValue = new( storage ) T( _value );
jamie@264 2376 return *this;
jamie@264 2377 }
jamie@264 2378
jamie@264 2379 void reset() {
jamie@264 2380 if( nullableValue )
jamie@264 2381 nullableValue->~T();
jamie@264 2382 nullableValue = NULL;
jamie@264 2383 }
jamie@264 2384
jamie@264 2385 T& operator*() { return *nullableValue; }
jamie@264 2386 T const& operator*() const { return *nullableValue; }
jamie@264 2387 T* operator->() { return nullableValue; }
jamie@264 2388 const T* operator->() const { return nullableValue; }
jamie@264 2389
jamie@264 2390 T valueOr( T const& defaultValue ) const {
jamie@264 2391 return nullableValue ? *nullableValue : defaultValue;
jamie@264 2392 }
jamie@264 2393
jamie@264 2394 bool some() const { return nullableValue != NULL; }
jamie@264 2395 bool none() const { return nullableValue == NULL; }
jamie@264 2396
jamie@264 2397 bool operator !() const { return nullableValue == NULL; }
jamie@264 2398 operator SafeBool::type() const {
jamie@264 2399 return SafeBool::makeSafe( some() );
jamie@264 2400 }
jamie@264 2401
jamie@264 2402 private:
jamie@264 2403 T* nullableValue;
jamie@264 2404 char storage[sizeof(T)];
jamie@264 2405 };
jamie@264 2406
jamie@264 2407 } // end namespace Catch
jamie@264 2408
jamie@264 2409 namespace Catch {
jamie@264 2410
jamie@264 2411 struct ITagAliasRegistry {
jamie@264 2412 virtual ~ITagAliasRegistry();
jamie@264 2413 virtual Option<TagAlias> find( std::string const& alias ) const = 0;
jamie@264 2414 virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
jamie@264 2415
jamie@264 2416 static ITagAliasRegistry const& get();
jamie@264 2417 };
jamie@264 2418
jamie@264 2419 } // end namespace Catch
jamie@264 2420
jamie@264 2421 // These files are included here so the single_include script doesn't put them
jamie@264 2422 // in the conditionally compiled sections
jamie@264 2423 // #included from: internal/catch_test_case_info.h
jamie@264 2424 #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
jamie@264 2425
jamie@264 2426 #include <string>
jamie@264 2427 #include <set>
jamie@264 2428
jamie@264 2429 #ifdef __clang__
jamie@264 2430 #pragma clang diagnostic push
jamie@264 2431 #pragma clang diagnostic ignored "-Wpadded"
jamie@264 2432 #endif
jamie@264 2433
jamie@264 2434 namespace Catch {
jamie@264 2435
jamie@264 2436 struct ITestCase;
jamie@264 2437
jamie@264 2438 struct TestCaseInfo {
jamie@264 2439 enum SpecialProperties{
jamie@264 2440 None = 0,
jamie@264 2441 IsHidden = 1 << 1,
jamie@264 2442 ShouldFail = 1 << 2,
jamie@264 2443 MayFail = 1 << 3,
jamie@264 2444 Throws = 1 << 4
jamie@264 2445 };
jamie@264 2446
jamie@264 2447 TestCaseInfo( std::string const& _name,
jamie@264 2448 std::string const& _className,
jamie@264 2449 std::string const& _description,
jamie@264 2450 std::set<std::string> const& _tags,
jamie@264 2451 SourceLineInfo const& _lineInfo );
jamie@264 2452
jamie@264 2453 TestCaseInfo( TestCaseInfo const& other );
jamie@264 2454
jamie@264 2455 bool isHidden() const;
jamie@264 2456 bool throws() const;
jamie@264 2457 bool okToFail() const;
jamie@264 2458 bool expectedToFail() const;
jamie@264 2459
jamie@264 2460 std::string name;
jamie@264 2461 std::string className;
jamie@264 2462 std::string description;
jamie@264 2463 std::set<std::string> tags;
jamie@264 2464 std::set<std::string> lcaseTags;
jamie@264 2465 std::string tagsAsString;
jamie@264 2466 SourceLineInfo lineInfo;
jamie@264 2467 SpecialProperties properties;
jamie@264 2468 };
jamie@264 2469
jamie@264 2470 class TestCase : public TestCaseInfo {
jamie@264 2471 public:
jamie@264 2472
jamie@264 2473 TestCase( ITestCase* testCase, TestCaseInfo const& info );
jamie@264 2474 TestCase( TestCase const& other );
jamie@264 2475
jamie@264 2476 TestCase withName( std::string const& _newName ) const;
jamie@264 2477
jamie@264 2478 void invoke() const;
jamie@264 2479
jamie@264 2480 TestCaseInfo const& getTestCaseInfo() const;
jamie@264 2481
jamie@264 2482 void swap( TestCase& other );
jamie@264 2483 bool operator == ( TestCase const& other ) const;
jamie@264 2484 bool operator < ( TestCase const& other ) const;
jamie@264 2485 TestCase& operator = ( TestCase const& other );
jamie@264 2486
jamie@264 2487 private:
jamie@264 2488 Ptr<ITestCase> test;
jamie@264 2489 };
jamie@264 2490
jamie@264 2491 TestCase makeTestCase( ITestCase* testCase,
jamie@264 2492 std::string const& className,
jamie@264 2493 std::string const& name,
jamie@264 2494 std::string const& description,
jamie@264 2495 SourceLineInfo const& lineInfo );
jamie@264 2496 }
jamie@264 2497
jamie@264 2498 #ifdef __clang__
jamie@264 2499 #pragma clang diagnostic pop
jamie@264 2500 #endif
jamie@264 2501
jamie@264 2502
jamie@264 2503 #ifdef __OBJC__
jamie@264 2504 // #included from: internal/catch_objc.hpp
jamie@264 2505 #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
jamie@264 2506
jamie@264 2507 #import <objc/runtime.h>
jamie@264 2508
jamie@264 2509 #include <string>
jamie@264 2510
jamie@264 2511 // NB. Any general catch headers included here must be included
jamie@264 2512 // in catch.hpp first to make sure they are included by the single
jamie@264 2513 // header for non obj-usage
jamie@264 2514
jamie@264 2515 ///////////////////////////////////////////////////////////////////////////////
jamie@264 2516 // This protocol is really only here for (self) documenting purposes, since
jamie@264 2517 // all its methods are optional.
jamie@264 2518 @protocol OcFixture
jamie@264 2519
jamie@264 2520 @optional
jamie@264 2521
jamie@264 2522 -(void) setUp;
jamie@264 2523 -(void) tearDown;
jamie@264 2524
jamie@264 2525 @end
jamie@264 2526
jamie@264 2527 namespace Catch {
jamie@264 2528
jamie@264 2529 class OcMethod : public SharedImpl<ITestCase> {
jamie@264 2530
jamie@264 2531 public:
jamie@264 2532 OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
jamie@264 2533
jamie@264 2534 virtual void invoke() const {
jamie@264 2535 id obj = [[m_cls alloc] init];
jamie@264 2536
jamie@264 2537 performOptionalSelector( obj, @selector(setUp) );
jamie@264 2538 performOptionalSelector( obj, m_sel );
jamie@264 2539 performOptionalSelector( obj, @selector(tearDown) );
jamie@264 2540
jamie@264 2541 arcSafeRelease( obj );
jamie@264 2542 }
jamie@264 2543 private:
jamie@264 2544 virtual ~OcMethod() {}
jamie@264 2545
jamie@264 2546 Class m_cls;
jamie@264 2547 SEL m_sel;
jamie@264 2548 };
jamie@264 2549
jamie@264 2550 namespace Detail{
jamie@264 2551
jamie@264 2552 inline std::string getAnnotation( Class cls,
jamie@264 2553 std::string const& annotationName,
jamie@264 2554 std::string const& testCaseName ) {
jamie@264 2555 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
jamie@264 2556 SEL sel = NSSelectorFromString( selStr );
jamie@264 2557 arcSafeRelease( selStr );
jamie@264 2558 id value = performOptionalSelector( cls, sel );
jamie@264 2559 if( value )
jamie@264 2560 return [(NSString*)value UTF8String];
jamie@264 2561 return "";
jamie@264 2562 }
jamie@264 2563 }
jamie@264 2564
jamie@264 2565 inline size_t registerTestMethods() {
jamie@264 2566 size_t noTestMethods = 0;
jamie@264 2567 int noClasses = objc_getClassList( NULL, 0 );
jamie@264 2568
jamie@264 2569 Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
jamie@264 2570 objc_getClassList( classes, noClasses );
jamie@264 2571
jamie@264 2572 for( int c = 0; c < noClasses; c++ ) {
jamie@264 2573 Class cls = classes[c];
jamie@264 2574 {
jamie@264 2575 u_int count;
jamie@264 2576 Method* methods = class_copyMethodList( cls, &count );
jamie@264 2577 for( u_int m = 0; m < count ; m++ ) {
jamie@264 2578 SEL selector = method_getName(methods[m]);
jamie@264 2579 std::string methodName = sel_getName(selector);
jamie@264 2580 if( startsWith( methodName, "Catch_TestCase_" ) ) {
jamie@264 2581 std::string testCaseName = methodName.substr( 15 );
jamie@264 2582 std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
jamie@264 2583 std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
jamie@264 2584 const char* className = class_getName( cls );
jamie@264 2585
jamie@264 2586 getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
jamie@264 2587 noTestMethods++;
jamie@264 2588 }
jamie@264 2589 }
jamie@264 2590 free(methods);
jamie@264 2591 }
jamie@264 2592 }
jamie@264 2593 return noTestMethods;
jamie@264 2594 }
jamie@264 2595
jamie@264 2596 namespace Matchers {
jamie@264 2597 namespace Impl {
jamie@264 2598 namespace NSStringMatchers {
jamie@264 2599
jamie@264 2600 template<typename MatcherT>
jamie@264 2601 struct StringHolder : MatcherImpl<MatcherT, NSString*>{
jamie@264 2602 StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
jamie@264 2603 StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
jamie@264 2604 StringHolder() {
jamie@264 2605 arcSafeRelease( m_substr );
jamie@264 2606 }
jamie@264 2607
jamie@264 2608 NSString* m_substr;
jamie@264 2609 };
jamie@264 2610
jamie@264 2611 struct Equals : StringHolder<Equals> {
jamie@264 2612 Equals( NSString* substr ) : StringHolder( substr ){}
jamie@264 2613
jamie@264 2614 virtual bool match( ExpressionType const& str ) const {
jamie@264 2615 return (str != nil || m_substr == nil ) &&
jamie@264 2616 [str isEqualToString:m_substr];
jamie@264 2617 }
jamie@264 2618
jamie@264 2619 virtual std::string toString() const {
jamie@264 2620 return "equals string: " + Catch::toString( m_substr );
jamie@264 2621 }
jamie@264 2622 };
jamie@264 2623
jamie@264 2624 struct Contains : StringHolder<Contains> {
jamie@264 2625 Contains( NSString* substr ) : StringHolder( substr ){}
jamie@264 2626
jamie@264 2627 virtual bool match( ExpressionType const& str ) const {
jamie@264 2628 return (str != nil || m_substr == nil ) &&
jamie@264 2629 [str rangeOfString:m_substr].location != NSNotFound;
jamie@264 2630 }
jamie@264 2631
jamie@264 2632 virtual std::string toString() const {
jamie@264 2633 return "contains string: " + Catch::toString( m_substr );
jamie@264 2634 }
jamie@264 2635 };
jamie@264 2636
jamie@264 2637 struct StartsWith : StringHolder<StartsWith> {
jamie@264 2638 StartsWith( NSString* substr ) : StringHolder( substr ){}
jamie@264 2639
jamie@264 2640 virtual bool match( ExpressionType const& str ) const {
jamie@264 2641 return (str != nil || m_substr == nil ) &&
jamie@264 2642 [str rangeOfString:m_substr].location == 0;
jamie@264 2643 }
jamie@264 2644
jamie@264 2645 virtual std::string toString() const {
jamie@264 2646 return "starts with: " + Catch::toString( m_substr );
jamie@264 2647 }
jamie@264 2648 };
jamie@264 2649 struct EndsWith : StringHolder<EndsWith> {
jamie@264 2650 EndsWith( NSString* substr ) : StringHolder( substr ){}
jamie@264 2651
jamie@264 2652 virtual bool match( ExpressionType const& str ) const {
jamie@264 2653 return (str != nil || m_substr == nil ) &&
jamie@264 2654 [str rangeOfString:m_substr].location == [str length] - [m_substr length];
jamie@264 2655 }
jamie@264 2656
jamie@264 2657 virtual std::string toString() const {
jamie@264 2658 return "ends with: " + Catch::toString( m_substr );
jamie@264 2659 }
jamie@264 2660 };
jamie@264 2661
jamie@264 2662 } // namespace NSStringMatchers
jamie@264 2663 } // namespace Impl
jamie@264 2664
jamie@264 2665 inline Impl::NSStringMatchers::Equals
jamie@264 2666 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
jamie@264 2667
jamie@264 2668 inline Impl::NSStringMatchers::Contains
jamie@264 2669 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
jamie@264 2670
jamie@264 2671 inline Impl::NSStringMatchers::StartsWith
jamie@264 2672 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
jamie@264 2673
jamie@264 2674 inline Impl::NSStringMatchers::EndsWith
jamie@264 2675 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
jamie@264 2676
jamie@264 2677 } // namespace Matchers
jamie@264 2678
jamie@264 2679 using namespace Matchers;
jamie@264 2680
jamie@264 2681 } // namespace Catch
jamie@264 2682
jamie@264 2683 ///////////////////////////////////////////////////////////////////////////////
jamie@264 2684 #define OC_TEST_CASE( name, desc )\
jamie@264 2685 +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
jamie@264 2686 {\
jamie@264 2687 return @ name; \
jamie@264 2688 }\
jamie@264 2689 +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
jamie@264 2690 { \
jamie@264 2691 return @ desc; \
jamie@264 2692 } \
jamie@264 2693 -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
jamie@264 2694
jamie@264 2695 #endif
jamie@264 2696
jamie@264 2697 #ifdef CATCH_CONFIG_RUNNER
jamie@264 2698 // #included from: internal/catch_impl.hpp
jamie@264 2699 #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
jamie@264 2700
jamie@264 2701 // Collect all the implementation files together here
jamie@264 2702 // These are the equivalent of what would usually be cpp files
jamie@264 2703
jamie@264 2704 #ifdef __clang__
jamie@264 2705 #pragma clang diagnostic push
jamie@264 2706 #pragma clang diagnostic ignored "-Wweak-vtables"
jamie@264 2707 #endif
jamie@264 2708
jamie@264 2709 // #included from: catch_runner.hpp
jamie@264 2710 #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
jamie@264 2711
jamie@264 2712 // #included from: internal/catch_commandline.hpp
jamie@264 2713 #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
jamie@264 2714
jamie@264 2715 // #included from: catch_config.hpp
jamie@264 2716 #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
jamie@264 2717
jamie@264 2718 // #included from: catch_test_spec_parser.hpp
jamie@264 2719 #define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
jamie@264 2720
jamie@264 2721 #ifdef __clang__
jamie@264 2722 #pragma clang diagnostic push
jamie@264 2723 #pragma clang diagnostic ignored "-Wpadded"
jamie@264 2724 #endif
jamie@264 2725
jamie@264 2726 // #included from: catch_test_spec.hpp
jamie@264 2727 #define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
jamie@264 2728
jamie@264 2729 #ifdef __clang__
jamie@264 2730 #pragma clang diagnostic push
jamie@264 2731 #pragma clang diagnostic ignored "-Wpadded"
jamie@264 2732 #endif
jamie@264 2733
jamie@264 2734 #include <string>
jamie@264 2735 #include <vector>
jamie@264 2736
jamie@264 2737 namespace Catch {
jamie@264 2738
jamie@264 2739 class TestSpec {
jamie@264 2740 struct Pattern : SharedImpl<> {
jamie@264 2741 virtual ~Pattern();
jamie@264 2742 virtual bool matches( TestCaseInfo const& testCase ) const = 0;
jamie@264 2743 };
jamie@264 2744 class NamePattern : public Pattern {
jamie@264 2745 enum WildcardPosition {
jamie@264 2746 NoWildcard = 0,
jamie@264 2747 WildcardAtStart = 1,
jamie@264 2748 WildcardAtEnd = 2,
jamie@264 2749 WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
jamie@264 2750 };
jamie@264 2751
jamie@264 2752 public:
jamie@264 2753 NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) {
jamie@264 2754 if( startsWith( m_name, "*" ) ) {
jamie@264 2755 m_name = m_name.substr( 1 );
jamie@264 2756 m_wildcard = WildcardAtStart;
jamie@264 2757 }
jamie@264 2758 if( endsWith( m_name, "*" ) ) {
jamie@264 2759 m_name = m_name.substr( 0, m_name.size()-1 );
jamie@264 2760 m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
jamie@264 2761 }
jamie@264 2762 }
jamie@264 2763 virtual ~NamePattern();
jamie@264 2764 virtual bool matches( TestCaseInfo const& testCase ) const {
jamie@264 2765 switch( m_wildcard ) {
jamie@264 2766 case NoWildcard:
jamie@264 2767 return m_name == toLower( testCase.name );
jamie@264 2768 case WildcardAtStart:
jamie@264 2769 return endsWith( toLower( testCase.name ), m_name );
jamie@264 2770 case WildcardAtEnd:
jamie@264 2771 return startsWith( toLower( testCase.name ), m_name );
jamie@264 2772 case WildcardAtBothEnds:
jamie@264 2773 return contains( toLower( testCase.name ), m_name );
jamie@264 2774 }
jamie@264 2775
jamie@264 2776 #ifdef __clang__
jamie@264 2777 #pragma clang diagnostic push
jamie@264 2778 #pragma clang diagnostic ignored "-Wunreachable-code"
jamie@264 2779 #endif
jamie@264 2780 throw std::logic_error( "Unknown enum" );
jamie@264 2781 #ifdef __clang__
jamie@264 2782 #pragma clang diagnostic pop
jamie@264 2783 #endif
jamie@264 2784 }
jamie@264 2785 private:
jamie@264 2786 std::string m_name;
jamie@264 2787 WildcardPosition m_wildcard;
jamie@264 2788 };
jamie@264 2789 class TagPattern : public Pattern {
jamie@264 2790 public:
jamie@264 2791 TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
jamie@264 2792 virtual ~TagPattern();
jamie@264 2793 virtual bool matches( TestCaseInfo const& testCase ) const {
jamie@264 2794 return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
jamie@264 2795 }
jamie@264 2796 private:
jamie@264 2797 std::string m_tag;
jamie@264 2798 };
jamie@264 2799 class ExcludedPattern : public Pattern {
jamie@264 2800 public:
jamie@264 2801 ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
jamie@264 2802 virtual ~ExcludedPattern();
jamie@264 2803 virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
jamie@264 2804 private:
jamie@264 2805 Ptr<Pattern> m_underlyingPattern;
jamie@264 2806 };
jamie@264 2807
jamie@264 2808 struct Filter {
jamie@264 2809 std::vector<Ptr<Pattern> > m_patterns;
jamie@264 2810
jamie@264 2811 bool matches( TestCaseInfo const& testCase ) const {
jamie@264 2812 // All patterns in a filter must match for the filter to be a match
jamie@264 2813 for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
jamie@264 2814 if( !(*it)->matches( testCase ) )
jamie@264 2815 return false;
jamie@264 2816 return true;
jamie@264 2817 }
jamie@264 2818 };
jamie@264 2819
jamie@264 2820 public:
jamie@264 2821 bool hasFilters() const {
jamie@264 2822 return !m_filters.empty();
jamie@264 2823 }
jamie@264 2824 bool matches( TestCaseInfo const& testCase ) const {
jamie@264 2825 // A TestSpec matches if any filter matches
jamie@264 2826 for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
jamie@264 2827 if( it->matches( testCase ) )
jamie@264 2828 return true;
jamie@264 2829 return false;
jamie@264 2830 }
jamie@264 2831
jamie@264 2832 private:
jamie@264 2833 std::vector<Filter> m_filters;
jamie@264 2834
jamie@264 2835 friend class TestSpecParser;
jamie@264 2836 };
jamie@264 2837 }
jamie@264 2838
jamie@264 2839 #ifdef __clang__
jamie@264 2840 #pragma clang diagnostic pop
jamie@264 2841 #endif
jamie@264 2842
jamie@264 2843 namespace Catch {
jamie@264 2844
jamie@264 2845 class TestSpecParser {
jamie@264 2846 enum Mode{ None, Name, QuotedName, Tag };
jamie@264 2847 Mode m_mode;
jamie@264 2848 bool m_exclusion;
jamie@264 2849 std::size_t m_start, m_pos;
jamie@264 2850 std::string m_arg;
jamie@264 2851 TestSpec::Filter m_currentFilter;
jamie@264 2852 TestSpec m_testSpec;
jamie@264 2853 ITagAliasRegistry const* m_tagAliases;
jamie@264 2854
jamie@264 2855 public:
jamie@264 2856 TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
jamie@264 2857
jamie@264 2858 TestSpecParser& parse( std::string const& arg ) {
jamie@264 2859 m_mode = None;
jamie@264 2860 m_exclusion = false;
jamie@264 2861 m_start = std::string::npos;
jamie@264 2862 m_arg = m_tagAliases->expandAliases( arg );
jamie@264 2863 for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
jamie@264 2864 visitChar( m_arg[m_pos] );
jamie@264 2865 if( m_mode == Name )
jamie@264 2866 addPattern<TestSpec::NamePattern>();
jamie@264 2867 return *this;
jamie@264 2868 }
jamie@264 2869 TestSpec testSpec() {
jamie@264 2870 addFilter();
jamie@264 2871 return m_testSpec;
jamie@264 2872 }
jamie@264 2873 private:
jamie@264 2874 void visitChar( char c ) {
jamie@264 2875 if( m_mode == None ) {
jamie@264 2876 switch( c ) {
jamie@264 2877 case ' ': return;
jamie@264 2878 case '~': m_exclusion = true; return;
jamie@264 2879 case '[': return startNewMode( Tag, ++m_pos );
jamie@264 2880 case '"': return startNewMode( QuotedName, ++m_pos );
jamie@264 2881 default: startNewMode( Name, m_pos ); break;
jamie@264 2882 }
jamie@264 2883 }
jamie@264 2884 if( m_mode == Name ) {
jamie@264 2885 if( c == ',' ) {
jamie@264 2886 addPattern<TestSpec::NamePattern>();
jamie@264 2887 addFilter();
jamie@264 2888 }
jamie@264 2889 else if( c == '[' ) {
jamie@264 2890 if( subString() == "exclude:" )
jamie@264 2891 m_exclusion = true;
jamie@264 2892 else
jamie@264 2893 addPattern<TestSpec::NamePattern>();
jamie@264 2894 startNewMode( Tag, ++m_pos );
jamie@264 2895 }
jamie@264 2896 }
jamie@264 2897 else if( m_mode == QuotedName && c == '"' )
jamie@264 2898 addPattern<TestSpec::NamePattern>();
jamie@264 2899 else if( m_mode == Tag && c == ']' )
jamie@264 2900 addPattern<TestSpec::TagPattern>();
jamie@264 2901 }
jamie@264 2902 void startNewMode( Mode mode, std::size_t start ) {
jamie@264 2903 m_mode = mode;
jamie@264 2904 m_start = start;
jamie@264 2905 }
jamie@264 2906 std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
jamie@264 2907 template<typename T>
jamie@264 2908 void addPattern() {
jamie@264 2909 std::string token = subString();
jamie@264 2910 if( startsWith( token, "exclude:" ) ) {
jamie@264 2911 m_exclusion = true;
jamie@264 2912 token = token.substr( 8 );
jamie@264 2913 }
jamie@264 2914 if( !token.empty() ) {
jamie@264 2915 Ptr<TestSpec::Pattern> pattern = new T( token );
jamie@264 2916 if( m_exclusion )
jamie@264 2917 pattern = new TestSpec::ExcludedPattern( pattern );
jamie@264 2918 m_currentFilter.m_patterns.push_back( pattern );
jamie@264 2919 }
jamie@264 2920 m_exclusion = false;
jamie@264 2921 m_mode = None;
jamie@264 2922 }
jamie@264 2923 void addFilter() {
jamie@264 2924 if( !m_currentFilter.m_patterns.empty() ) {
jamie@264 2925 m_testSpec.m_filters.push_back( m_currentFilter );
jamie@264 2926 m_currentFilter = TestSpec::Filter();
jamie@264 2927 }
jamie@264 2928 }
jamie@264 2929 };
jamie@264 2930 inline TestSpec parseTestSpec( std::string const& arg ) {
jamie@264 2931 return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
jamie@264 2932 }
jamie@264 2933
jamie@264 2934 } // namespace Catch
jamie@264 2935
jamie@264 2936 #ifdef __clang__
jamie@264 2937 #pragma clang diagnostic pop
jamie@264 2938 #endif
jamie@264 2939
jamie@264 2940 // #included from: catch_interfaces_config.h
jamie@264 2941 #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
jamie@264 2942
jamie@264 2943 #include <iostream>
jamie@264 2944 #include <string>
jamie@264 2945 #include <vector>
jamie@264 2946
jamie@264 2947 namespace Catch {
jamie@264 2948
jamie@264 2949 struct Verbosity { enum Level {
jamie@264 2950 NoOutput = 0,
jamie@264 2951 Quiet,
jamie@264 2952 Normal
jamie@264 2953 }; };
jamie@264 2954
jamie@264 2955 struct WarnAbout { enum What {
jamie@264 2956 Nothing = 0x00,
jamie@264 2957 NoAssertions = 0x01
jamie@264 2958 }; };
jamie@264 2959
jamie@264 2960 struct ShowDurations { enum OrNot {
jamie@264 2961 DefaultForReporter,
jamie@264 2962 Always,
jamie@264 2963 Never
jamie@264 2964 }; };
jamie@264 2965
jamie@264 2966 class TestSpec;
jamie@264 2967
jamie@264 2968 struct IConfig : IShared {
jamie@264 2969
jamie@264 2970 virtual ~IConfig();
jamie@264 2971
jamie@264 2972 virtual bool allowThrows() const = 0;
jamie@264 2973 virtual std::ostream& stream() const = 0;
jamie@264 2974 virtual std::string name() const = 0;
jamie@264 2975 virtual bool includeSuccessfulResults() const = 0;
jamie@264 2976 virtual bool shouldDebugBreak() const = 0;
jamie@264 2977 virtual bool warnAboutMissingAssertions() const = 0;
jamie@264 2978 virtual int abortAfter() const = 0;
jamie@264 2979 virtual bool showInvisibles() const = 0;
jamie@264 2980 virtual ShowDurations::OrNot showDurations() const = 0;
jamie@264 2981 virtual TestSpec const& testSpec() const = 0;
jamie@264 2982 };
jamie@264 2983 }
jamie@264 2984
jamie@264 2985 // #included from: catch_stream.h
jamie@264 2986 #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
jamie@264 2987
jamie@264 2988 #include <streambuf>
jamie@264 2989
jamie@264 2990 #ifdef __clang__
jamie@264 2991 #pragma clang diagnostic ignored "-Wpadded"
jamie@264 2992 #endif
jamie@264 2993
jamie@264 2994 namespace Catch {
jamie@264 2995
jamie@264 2996 class Stream {
jamie@264 2997 public:
jamie@264 2998 Stream();
jamie@264 2999 Stream( std::streambuf* _streamBuf, bool _isOwned );
jamie@264 3000 void release();
jamie@264 3001
jamie@264 3002 std::streambuf* streamBuf;
jamie@264 3003
jamie@264 3004 private:
jamie@264 3005 bool isOwned;
jamie@264 3006 };
jamie@264 3007 }
jamie@264 3008
jamie@264 3009 #include <memory>
jamie@264 3010 #include <vector>
jamie@264 3011 #include <string>
jamie@264 3012 #include <iostream>
jamie@264 3013
jamie@264 3014 #ifndef CATCH_CONFIG_CONSOLE_WIDTH
jamie@264 3015 #define CATCH_CONFIG_CONSOLE_WIDTH 80
jamie@264 3016 #endif
jamie@264 3017
jamie@264 3018 namespace Catch {
jamie@264 3019
jamie@264 3020 struct ConfigData {
jamie@264 3021
jamie@264 3022 ConfigData()
jamie@264 3023 : listTests( false ),
jamie@264 3024 listTags( false ),
jamie@264 3025 listReporters( false ),
jamie@264 3026 listTestNamesOnly( false ),
jamie@264 3027 showSuccessfulTests( false ),
jamie@264 3028 shouldDebugBreak( false ),
jamie@264 3029 noThrow( false ),
jamie@264 3030 showHelp( false ),
jamie@264 3031 showInvisibles( false ),
jamie@264 3032 abortAfter( -1 ),
jamie@264 3033 verbosity( Verbosity::Normal ),
jamie@264 3034 warnings( WarnAbout::Nothing ),
jamie@264 3035 showDurations( ShowDurations::DefaultForReporter )
jamie@264 3036 {}
jamie@264 3037
jamie@264 3038 bool listTests;
jamie@264 3039 bool listTags;
jamie@264 3040 bool listReporters;
jamie@264 3041 bool listTestNamesOnly;
jamie@264 3042
jamie@264 3043 bool showSuccessfulTests;
jamie@264 3044 bool shouldDebugBreak;
jamie@264 3045 bool noThrow;
jamie@264 3046 bool showHelp;
jamie@264 3047 bool showInvisibles;
jamie@264 3048
jamie@264 3049 int abortAfter;
jamie@264 3050
jamie@264 3051 Verbosity::Level verbosity;
jamie@264 3052 WarnAbout::What warnings;
jamie@264 3053 ShowDurations::OrNot showDurations;
jamie@264 3054
jamie@264 3055 std::string reporterName;
jamie@264 3056 std::string outputFilename;
jamie@264 3057 std::string name;
jamie@264 3058 std::string processName;
jamie@264 3059
jamie@264 3060 std::vector<std::string> testsOrTags;
jamie@264 3061 };
jamie@264 3062
jamie@264 3063 class Config : public SharedImpl<IConfig> {
jamie@264 3064 private:
jamie@264 3065 Config( Config const& other );
jamie@264 3066 Config& operator = ( Config const& other );
jamie@264 3067 virtual void dummy();
jamie@264 3068 public:
jamie@264 3069
jamie@264 3070 Config()
jamie@264 3071 : m_os( std::cout.rdbuf() )
jamie@264 3072 {}
jamie@264 3073
jamie@264 3074 Config( ConfigData const& data )
jamie@264 3075 : m_data( data ),
jamie@264 3076 m_os( std::cout.rdbuf() )
jamie@264 3077 {
jamie@264 3078 if( !data.testsOrTags.empty() ) {
jamie@264 3079 TestSpecParser parser( ITagAliasRegistry::get() );
jamie@264 3080 for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
jamie@264 3081 parser.parse( data.testsOrTags[i] );
jamie@264 3082 m_testSpec = parser.testSpec();
jamie@264 3083 }
jamie@264 3084 }
jamie@264 3085
jamie@264 3086 virtual ~Config() {
jamie@264 3087 m_os.rdbuf( std::cout.rdbuf() );
jamie@264 3088 m_stream.release();
jamie@264 3089 }
jamie@264 3090
jamie@264 3091 void setFilename( std::string const& filename ) {
jamie@264 3092 m_data.outputFilename = filename;
jamie@264 3093 }
jamie@264 3094
jamie@264 3095 std::string const& getFilename() const {
jamie@264 3096 return m_data.outputFilename ;
jamie@264 3097 }
jamie@264 3098
jamie@264 3099 bool listTests() const { return m_data.listTests; }
jamie@264 3100 bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
jamie@264 3101 bool listTags() const { return m_data.listTags; }
jamie@264 3102 bool listReporters() const { return m_data.listReporters; }
jamie@264 3103
jamie@264 3104 std::string getProcessName() const { return m_data.processName; }
jamie@264 3105
jamie@264 3106 bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
jamie@264 3107
jamie@264 3108 void setStreamBuf( std::streambuf* buf ) {
jamie@264 3109 m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
jamie@264 3110 }
jamie@264 3111
jamie@264 3112 void useStream( std::string const& streamName ) {
jamie@264 3113 Stream stream = createStream( streamName );
jamie@264 3114 setStreamBuf( stream.streamBuf );
jamie@264 3115 m_stream.release();
jamie@264 3116 m_stream = stream;
jamie@264 3117 }
jamie@264 3118
jamie@264 3119 std::string getReporterName() const { return m_data.reporterName; }
jamie@264 3120
jamie@264 3121 int abortAfter() const { return m_data.abortAfter; }
jamie@264 3122
jamie@264 3123 TestSpec const& testSpec() const { return m_testSpec; }
jamie@264 3124
jamie@264 3125 bool showHelp() const { return m_data.showHelp; }
jamie@264 3126 bool showInvisibles() const { return m_data.showInvisibles; }
jamie@264 3127
jamie@264 3128 // IConfig interface
jamie@264 3129 virtual bool allowThrows() const { return !m_data.noThrow; }
jamie@264 3130 virtual std::ostream& stream() const { return m_os; }
jamie@264 3131 virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
jamie@264 3132 virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
jamie@264 3133 virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
jamie@264 3134 virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
jamie@264 3135
jamie@264 3136 private:
jamie@264 3137 ConfigData m_data;
jamie@264 3138
jamie@264 3139 Stream m_stream;
jamie@264 3140 mutable std::ostream m_os;
jamie@264 3141 TestSpec m_testSpec;
jamie@264 3142 };
jamie@264 3143
jamie@264 3144 } // end namespace Catch
jamie@264 3145
jamie@264 3146 // #included from: catch_clara.h
jamie@264 3147 #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
jamie@264 3148
jamie@264 3149 // Use Catch's value for console width (store Clara's off to the side, if present)
jamie@264 3150 #ifdef CLARA_CONFIG_CONSOLE_WIDTH
jamie@264 3151 #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
jamie@264 3152 #undef CLARA_CONFIG_CONSOLE_WIDTH
jamie@264 3153 #endif
jamie@264 3154 #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
jamie@264 3155
jamie@264 3156 // Declare Clara inside the Catch namespace
jamie@264 3157 #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
jamie@264 3158 // #included from: ../external/clara.h
jamie@264 3159
jamie@264 3160 // Only use header guard if we are not using an outer namespace
jamie@264 3161 #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
jamie@264 3162
jamie@264 3163 #ifndef STITCH_CLARA_OPEN_NAMESPACE
jamie@264 3164 #define TWOBLUECUBES_CLARA_H_INCLUDED
jamie@264 3165 #define STITCH_CLARA_OPEN_NAMESPACE
jamie@264 3166 #define STITCH_CLARA_CLOSE_NAMESPACE
jamie@264 3167 #else
jamie@264 3168 #define STITCH_CLARA_CLOSE_NAMESPACE }
jamie@264 3169 #endif
jamie@264 3170
jamie@264 3171 #define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
jamie@264 3172
jamie@264 3173 // ----------- #included from tbc_text_format.h -----------
jamie@264 3174
jamie@264 3175 // Only use header guard if we are not using an outer namespace
jamie@264 3176 #if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
jamie@264 3177 #ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
jamie@264 3178 #define TBC_TEXT_FORMAT_H_INCLUDED
jamie@264 3179 #endif
jamie@264 3180
jamie@264 3181 #include <string>
jamie@264 3182 #include <vector>
jamie@264 3183 #include <sstream>
jamie@264 3184
jamie@264 3185 // Use optional outer namespace
jamie@264 3186 #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
jamie@264 3187 namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
jamie@264 3188 #endif
jamie@264 3189
jamie@264 3190 namespace Tbc {
jamie@264 3191
jamie@264 3192 #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
jamie@264 3193 const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
jamie@264 3194 #else
jamie@264 3195 const unsigned int consoleWidth = 80;
jamie@264 3196 #endif
jamie@264 3197
jamie@264 3198 struct TextAttributes {
jamie@264 3199 TextAttributes()
jamie@264 3200 : initialIndent( std::string::npos ),
jamie@264 3201 indent( 0 ),
jamie@264 3202 width( consoleWidth-1 ),
jamie@264 3203 tabChar( '\t' )
jamie@264 3204 {}
jamie@264 3205
jamie@264 3206 TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
jamie@264 3207 TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
jamie@264 3208 TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
jamie@264 3209 TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
jamie@264 3210
jamie@264 3211 std::size_t initialIndent; // indent of first line, or npos
jamie@264 3212 std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
jamie@264 3213 std::size_t width; // maximum width of text, including indent. Longer text will wrap
jamie@264 3214 char tabChar; // If this char is seen the indent is changed to current pos
jamie@264 3215 };
jamie@264 3216
jamie@264 3217 class Text {
jamie@264 3218 public:
jamie@264 3219 Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
jamie@264 3220 : attr( _attr )
jamie@264 3221 {
jamie@264 3222 std::string wrappableChars = " [({.,/|\\-";
jamie@264 3223 std::size_t indent = _attr.initialIndent != std::string::npos
jamie@264 3224 ? _attr.initialIndent
jamie@264 3225 : _attr.indent;
jamie@264 3226 std::string remainder = _str;
jamie@264 3227
jamie@264 3228 while( !remainder.empty() ) {
jamie@264 3229 if( lines.size() >= 1000 ) {
jamie@264 3230 lines.push_back( "... message truncated due to excessive size" );
jamie@264 3231 return;
jamie@264 3232 }
jamie@264 3233 std::size_t tabPos = std::string::npos;
jamie@264 3234 std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
jamie@264 3235 std::size_t pos = remainder.find_first_of( '\n' );
jamie@264 3236 if( pos <= width ) {
jamie@264 3237 width = pos;
jamie@264 3238 }
jamie@264 3239 pos = remainder.find_last_of( _attr.tabChar, width );
jamie@264 3240 if( pos != std::string::npos ) {
jamie@264 3241 tabPos = pos;
jamie@264 3242 if( remainder[width] == '\n' )
jamie@264 3243 width--;
jamie@264 3244 remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
jamie@264 3245 }
jamie@264 3246
jamie@264 3247 if( width == remainder.size() ) {
jamie@264 3248 spliceLine( indent, remainder, width );
jamie@264 3249 }
jamie@264 3250 else if( remainder[width] == '\n' ) {
jamie@264 3251 spliceLine( indent, remainder, width );
jamie@264 3252 if( width <= 1 || remainder.size() != 1 )
jamie@264 3253 remainder = remainder.substr( 1 );
jamie@264 3254 indent = _attr.indent;
jamie@264 3255 }
jamie@264 3256 else {
jamie@264 3257 pos = remainder.find_last_of( wrappableChars, width );
jamie@264 3258 if( pos != std::string::npos && pos > 0 ) {
jamie@264 3259 spliceLine( indent, remainder, pos );
jamie@264 3260 if( remainder[0] == ' ' )
jamie@264 3261 remainder = remainder.substr( 1 );
jamie@264 3262 }
jamie@264 3263 else {
jamie@264 3264 spliceLine( indent, remainder, width-1 );
jamie@264 3265 lines.back() += "-";
jamie@264 3266 }
jamie@264 3267 if( lines.size() == 1 )
jamie@264 3268 indent = _attr.indent;
jamie@264 3269 if( tabPos != std::string::npos )
jamie@264 3270 indent += tabPos;
jamie@264 3271 }
jamie@264 3272 }
jamie@264 3273 }
jamie@264 3274
jamie@264 3275 void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
jamie@264 3276 lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
jamie@264 3277 _remainder = _remainder.substr( _pos );
jamie@264 3278 }
jamie@264 3279
jamie@264 3280 typedef std::vector<std::string>::const_iterator const_iterator;
jamie@264 3281
jamie@264 3282 const_iterator begin() const { return lines.begin(); }
jamie@264 3283 const_iterator end() const { return lines.end(); }
jamie@264 3284 std::string const& last() const { return lines.back(); }
jamie@264 3285 std::size_t size() const { return lines.size(); }
jamie@264 3286 std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
jamie@264 3287 std::string toString() const {
jamie@264 3288 std::ostringstream oss;
jamie@264 3289 oss << *this;
jamie@264 3290 return oss.str();
jamie@264 3291 }
jamie@264 3292
jamie@264 3293 inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
jamie@264 3294 for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
jamie@264 3295 it != itEnd; ++it ) {
jamie@264 3296 if( it != _text.begin() )
jamie@264 3297 _stream << "\n";
jamie@264 3298 _stream << *it;
jamie@264 3299 }
jamie@264 3300 return _stream;
jamie@264 3301 }
jamie@264 3302
jamie@264 3303 private:
jamie@264 3304 std::string str;
jamie@264 3305 TextAttributes attr;
jamie@264 3306 std::vector<std::string> lines;
jamie@264 3307 };
jamie@264 3308
jamie@264 3309 } // end namespace Tbc
jamie@264 3310
jamie@264 3311 #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
jamie@264 3312 } // end outer namespace
jamie@264 3313 #endif
jamie@264 3314
jamie@264 3315 #endif // TBC_TEXT_FORMAT_H_INCLUDED
jamie@264 3316
jamie@264 3317 // ----------- end of #include from tbc_text_format.h -----------
jamie@264 3318 // ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
jamie@264 3319
jamie@264 3320 #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
jamie@264 3321
jamie@264 3322 #include <map>
jamie@264 3323 #include <algorithm>
jamie@264 3324 #include <stdexcept>
jamie@264 3325 #include <memory>
jamie@264 3326
jamie@264 3327 // Use optional outer namespace
jamie@264 3328 #ifdef STITCH_CLARA_OPEN_NAMESPACE
jamie@264 3329 STITCH_CLARA_OPEN_NAMESPACE
jamie@264 3330 #endif
jamie@264 3331
jamie@264 3332 namespace Clara {
jamie@264 3333
jamie@264 3334 struct UnpositionalTag {};
jamie@264 3335
jamie@264 3336 extern UnpositionalTag _;
jamie@264 3337
jamie@264 3338 #ifdef CLARA_CONFIG_MAIN
jamie@264 3339 UnpositionalTag _;
jamie@264 3340 #endif
jamie@264 3341
jamie@264 3342 namespace Detail {
jamie@264 3343
jamie@264 3344 #ifdef CLARA_CONSOLE_WIDTH
jamie@264 3345 const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
jamie@264 3346 #else
jamie@264 3347 const unsigned int consoleWidth = 80;
jamie@264 3348 #endif
jamie@264 3349
jamie@264 3350 using namespace Tbc;
jamie@264 3351
jamie@264 3352 inline bool startsWith( std::string const& str, std::string const& prefix ) {
jamie@264 3353 return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
jamie@264 3354 }
jamie@264 3355
jamie@264 3356 template<typename T> struct RemoveConstRef{ typedef T type; };
jamie@264 3357 template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
jamie@264 3358 template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
jamie@264 3359 template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
jamie@264 3360
jamie@264 3361 template<typename T> struct IsBool { static const bool value = false; };
jamie@264 3362 template<> struct IsBool<bool> { static const bool value = true; };
jamie@264 3363
jamie@264 3364 template<typename T>
jamie@264 3365 void convertInto( std::string const& _source, T& _dest ) {
jamie@264 3366 std::stringstream ss;
jamie@264 3367 ss << _source;
jamie@264 3368 ss >> _dest;
jamie@264 3369 if( ss.fail() )
jamie@264 3370 throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
jamie@264 3371 }
jamie@264 3372 inline void convertInto( std::string const& _source, std::string& _dest ) {
jamie@264 3373 _dest = _source;
jamie@264 3374 }
jamie@264 3375 inline void convertInto( std::string const& _source, bool& _dest ) {
jamie@264 3376 std::string sourceLC = _source;
jamie@264 3377 std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
jamie@264 3378 if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
jamie@264 3379 _dest = true;
jamie@264 3380 else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
jamie@264 3381 _dest = false;
jamie@264 3382 else
jamie@264 3383 throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
jamie@264 3384 }
jamie@264 3385 inline void convertInto( bool _source, bool& _dest ) {
jamie@264 3386 _dest = _source;
jamie@264 3387 }
jamie@264 3388 template<typename T>
jamie@264 3389 inline void convertInto( bool, T& ) {
jamie@264 3390 throw std::runtime_error( "Invalid conversion" );
jamie@264 3391 }
jamie@264 3392
jamie@264 3393 template<typename ConfigT>
jamie@264 3394 struct IArgFunction {
jamie@264 3395 virtual ~IArgFunction() {}
jamie@264 3396 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 3397 IArgFunction() = default;
jamie@264 3398 IArgFunction( IArgFunction const& ) = default;
jamie@264 3399 # endif
jamie@264 3400 virtual void set( ConfigT& config, std::string const& value ) const = 0;
jamie@264 3401 virtual void setFlag( ConfigT& config ) const = 0;
jamie@264 3402 virtual bool takesArg() const = 0;
jamie@264 3403 virtual IArgFunction* clone() const = 0;
jamie@264 3404 };
jamie@264 3405
jamie@264 3406 template<typename ConfigT>
jamie@264 3407 class BoundArgFunction {
jamie@264 3408 public:
jamie@264 3409 BoundArgFunction() : functionObj( NULL ) {}
jamie@264 3410 BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
jamie@264 3411 BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {}
jamie@264 3412 BoundArgFunction& operator = ( BoundArgFunction const& other ) {
jamie@264 3413 IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL;
jamie@264 3414 delete functionObj;
jamie@264 3415 functionObj = newFunctionObj;
jamie@264 3416 return *this;
jamie@264 3417 }
jamie@264 3418 ~BoundArgFunction() { delete functionObj; }
jamie@264 3419
jamie@264 3420 void set( ConfigT& config, std::string const& value ) const {
jamie@264 3421 functionObj->set( config, value );
jamie@264 3422 }
jamie@264 3423 void setFlag( ConfigT& config ) const {
jamie@264 3424 functionObj->setFlag( config );
jamie@264 3425 }
jamie@264 3426 bool takesArg() const { return functionObj->takesArg(); }
jamie@264 3427
jamie@264 3428 bool isSet() const {
jamie@264 3429 return functionObj != NULL;
jamie@264 3430 }
jamie@264 3431 private:
jamie@264 3432 IArgFunction<ConfigT>* functionObj;
jamie@264 3433 };
jamie@264 3434
jamie@264 3435 template<typename C>
jamie@264 3436 struct NullBinder : IArgFunction<C>{
jamie@264 3437 virtual void set( C&, std::string const& ) const {}
jamie@264 3438 virtual void setFlag( C& ) const {}
jamie@264 3439 virtual bool takesArg() const { return true; }
jamie@264 3440 virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
jamie@264 3441 };
jamie@264 3442
jamie@264 3443 template<typename C, typename M>
jamie@264 3444 struct BoundDataMember : IArgFunction<C>{
jamie@264 3445 BoundDataMember( M C::* _member ) : member( _member ) {}
jamie@264 3446 virtual void set( C& p, std::string const& stringValue ) const {
jamie@264 3447 convertInto( stringValue, p.*member );
jamie@264 3448 }
jamie@264 3449 virtual void setFlag( C& p ) const {
jamie@264 3450 convertInto( true, p.*member );
jamie@264 3451 }
jamie@264 3452 virtual bool takesArg() const { return !IsBool<M>::value; }
jamie@264 3453 virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
jamie@264 3454 M C::* member;
jamie@264 3455 };
jamie@264 3456 template<typename C, typename M>
jamie@264 3457 struct BoundUnaryMethod : IArgFunction<C>{
jamie@264 3458 BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
jamie@264 3459 virtual void set( C& p, std::string const& stringValue ) const {
jamie@264 3460 typename RemoveConstRef<M>::type value;
jamie@264 3461 convertInto( stringValue, value );
jamie@264 3462 (p.*member)( value );
jamie@264 3463 }
jamie@264 3464 virtual void setFlag( C& p ) const {
jamie@264 3465 typename RemoveConstRef<M>::type value;
jamie@264 3466 convertInto( true, value );
jamie@264 3467 (p.*member)( value );
jamie@264 3468 }
jamie@264 3469 virtual bool takesArg() const { return !IsBool<M>::value; }
jamie@264 3470 virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
jamie@264 3471 void (C::*member)( M );
jamie@264 3472 };
jamie@264 3473 template<typename C>
jamie@264 3474 struct BoundNullaryMethod : IArgFunction<C>{
jamie@264 3475 BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
jamie@264 3476 virtual void set( C& p, std::string const& stringValue ) const {
jamie@264 3477 bool value;
jamie@264 3478 convertInto( stringValue, value );
jamie@264 3479 if( value )
jamie@264 3480 (p.*member)();
jamie@264 3481 }
jamie@264 3482 virtual void setFlag( C& p ) const {
jamie@264 3483 (p.*member)();
jamie@264 3484 }
jamie@264 3485 virtual bool takesArg() const { return false; }
jamie@264 3486 virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
jamie@264 3487 void (C::*member)();
jamie@264 3488 };
jamie@264 3489
jamie@264 3490 template<typename C>
jamie@264 3491 struct BoundUnaryFunction : IArgFunction<C>{
jamie@264 3492 BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
jamie@264 3493 virtual void set( C& obj, std::string const& stringValue ) const {
jamie@264 3494 bool value;
jamie@264 3495 convertInto( stringValue, value );
jamie@264 3496 if( value )
jamie@264 3497 function( obj );
jamie@264 3498 }
jamie@264 3499 virtual void setFlag( C& p ) const {
jamie@264 3500 function( p );
jamie@264 3501 }
jamie@264 3502 virtual bool takesArg() const { return false; }
jamie@264 3503 virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
jamie@264 3504 void (*function)( C& );
jamie@264 3505 };
jamie@264 3506
jamie@264 3507 template<typename C, typename T>
jamie@264 3508 struct BoundBinaryFunction : IArgFunction<C>{
jamie@264 3509 BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
jamie@264 3510 virtual void set( C& obj, std::string const& stringValue ) const {
jamie@264 3511 typename RemoveConstRef<T>::type value;
jamie@264 3512 convertInto( stringValue, value );
jamie@264 3513 function( obj, value );
jamie@264 3514 }
jamie@264 3515 virtual void setFlag( C& obj ) const {
jamie@264 3516 typename RemoveConstRef<T>::type value;
jamie@264 3517 convertInto( true, value );
jamie@264 3518 function( obj, value );
jamie@264 3519 }
jamie@264 3520 virtual bool takesArg() const { return !IsBool<T>::value; }
jamie@264 3521 virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
jamie@264 3522 void (*function)( C&, T );
jamie@264 3523 };
jamie@264 3524
jamie@264 3525 } // namespace Detail
jamie@264 3526
jamie@264 3527 struct Parser {
jamie@264 3528 Parser() : separators( " \t=:" ) {}
jamie@264 3529
jamie@264 3530 struct Token {
jamie@264 3531 enum Type { Positional, ShortOpt, LongOpt };
jamie@264 3532 Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
jamie@264 3533 Type type;
jamie@264 3534 std::string data;
jamie@264 3535 };
jamie@264 3536
jamie@264 3537 void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
jamie@264 3538 const std::string doubleDash = "--";
jamie@264 3539 for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
jamie@264 3540 parseIntoTokens( argv[i] , tokens);
jamie@264 3541 }
jamie@264 3542 void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
jamie@264 3543 while( !arg.empty() ) {
jamie@264 3544 Parser::Token token( Parser::Token::Positional, arg );
jamie@264 3545 arg = "";
jamie@264 3546 if( token.data[0] == '-' ) {
jamie@264 3547 if( token.data.size() > 1 && token.data[1] == '-' ) {
jamie@264 3548 token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
jamie@264 3549 }
jamie@264 3550 else {
jamie@264 3551 token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
jamie@264 3552 if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
jamie@264 3553 arg = "-" + token.data.substr( 1 );
jamie@264 3554 token.data = token.data.substr( 0, 1 );
jamie@264 3555 }
jamie@264 3556 }
jamie@264 3557 }
jamie@264 3558 if( token.type != Parser::Token::Positional ) {
jamie@264 3559 std::size_t pos = token.data.find_first_of( separators );
jamie@264 3560 if( pos != std::string::npos ) {
jamie@264 3561 arg = token.data.substr( pos+1 );
jamie@264 3562 token.data = token.data.substr( 0, pos );
jamie@264 3563 }
jamie@264 3564 }
jamie@264 3565 tokens.push_back( token );
jamie@264 3566 }
jamie@264 3567 }
jamie@264 3568 std::string separators;
jamie@264 3569 };
jamie@264 3570
jamie@264 3571 template<typename ConfigT>
jamie@264 3572 struct CommonArgProperties {
jamie@264 3573 CommonArgProperties() {}
jamie@264 3574 CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
jamie@264 3575
jamie@264 3576 Detail::BoundArgFunction<ConfigT> boundField;
jamie@264 3577 std::string description;
jamie@264 3578 std::string detail;
jamie@264 3579 std::string placeholder; // Only value if boundField takes an arg
jamie@264 3580
jamie@264 3581 bool takesArg() const {
jamie@264 3582 return !placeholder.empty();
jamie@264 3583 }
jamie@264 3584 void validate() const {
jamie@264 3585 if( !boundField.isSet() )
jamie@264 3586 throw std::logic_error( "option not bound" );
jamie@264 3587 }
jamie@264 3588 };
jamie@264 3589 struct OptionArgProperties {
jamie@264 3590 std::vector<std::string> shortNames;
jamie@264 3591 std::string longName;
jamie@264 3592
jamie@264 3593 bool hasShortName( std::string const& shortName ) const {
jamie@264 3594 return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
jamie@264 3595 }
jamie@264 3596 bool hasLongName( std::string const& _longName ) const {
jamie@264 3597 return _longName == longName;
jamie@264 3598 }
jamie@264 3599 };
jamie@264 3600 struct PositionalArgProperties {
jamie@264 3601 PositionalArgProperties() : position( -1 ) {}
jamie@264 3602 int position; // -1 means non-positional (floating)
jamie@264 3603
jamie@264 3604 bool isFixedPositional() const {
jamie@264 3605 return position != -1;
jamie@264 3606 }
jamie@264 3607 };
jamie@264 3608
jamie@264 3609 template<typename ConfigT>
jamie@264 3610 class CommandLine {
jamie@264 3611
jamie@264 3612 struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
jamie@264 3613 Arg() {}
jamie@264 3614 Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
jamie@264 3615
jamie@264 3616 using CommonArgProperties<ConfigT>::placeholder; // !TBD
jamie@264 3617
jamie@264 3618 std::string dbgName() const {
jamie@264 3619 if( !longName.empty() )
jamie@264 3620 return "--" + longName;
jamie@264 3621 if( !shortNames.empty() )
jamie@264 3622 return "-" + shortNames[0];
jamie@264 3623 return "positional args";
jamie@264 3624 }
jamie@264 3625 std::string commands() const {
jamie@264 3626 std::ostringstream oss;
jamie@264 3627 bool first = true;
jamie@264 3628 std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
jamie@264 3629 for(; it != itEnd; ++it ) {
jamie@264 3630 if( first )
jamie@264 3631 first = false;
jamie@264 3632 else
jamie@264 3633 oss << ", ";
jamie@264 3634 oss << "-" << *it;
jamie@264 3635 }
jamie@264 3636 if( !longName.empty() ) {
jamie@264 3637 if( !first )
jamie@264 3638 oss << ", ";
jamie@264 3639 oss << "--" << longName;
jamie@264 3640 }
jamie@264 3641 if( !placeholder.empty() )
jamie@264 3642 oss << " <" << placeholder << ">";
jamie@264 3643 return oss.str();
jamie@264 3644 }
jamie@264 3645 };
jamie@264 3646
jamie@264 3647 // NOTE: std::auto_ptr is deprecated in c++11/c++0x
jamie@264 3648 #if defined(__cplusplus) && __cplusplus > 199711L
jamie@264 3649 typedef std::unique_ptr<Arg> ArgAutoPtr;
jamie@264 3650 #else
jamie@264 3651 typedef std::auto_ptr<Arg> ArgAutoPtr;
jamie@264 3652 #endif
jamie@264 3653
jamie@264 3654 friend void addOptName( Arg& arg, std::string const& optName )
jamie@264 3655 {
jamie@264 3656 if( optName.empty() )
jamie@264 3657 return;
jamie@264 3658 if( Detail::startsWith( optName, "--" ) ) {
jamie@264 3659 if( !arg.longName.empty() )
jamie@264 3660 throw std::logic_error( "Only one long opt may be specified. '"
jamie@264 3661 + arg.longName
jamie@264 3662 + "' already specified, now attempting to add '"
jamie@264 3663 + optName + "'" );
jamie@264 3664 arg.longName = optName.substr( 2 );
jamie@264 3665 }
jamie@264 3666 else if( Detail::startsWith( optName, "-" ) )
jamie@264 3667 arg.shortNames.push_back( optName.substr( 1 ) );
jamie@264 3668 else
jamie@264 3669 throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
jamie@264 3670 }
jamie@264 3671 friend void setPositionalArg( Arg& arg, int position )
jamie@264 3672 {
jamie@264 3673 arg.position = position;
jamie@264 3674 }
jamie@264 3675
jamie@264 3676 class ArgBuilder {
jamie@264 3677 public:
jamie@264 3678 ArgBuilder( Arg* arg ) : m_arg( arg ) {}
jamie@264 3679
jamie@264 3680 // Bind a non-boolean data member (requires placeholder string)
jamie@264 3681 template<typename C, typename M>
jamie@264 3682 void bind( M C::* field, std::string const& placeholder ) {
jamie@264 3683 m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
jamie@264 3684 m_arg->placeholder = placeholder;
jamie@264 3685 }
jamie@264 3686 // Bind a boolean data member (no placeholder required)
jamie@264 3687 template<typename C>
jamie@264 3688 void bind( bool C::* field ) {
jamie@264 3689 m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
jamie@264 3690 }
jamie@264 3691
jamie@264 3692 // Bind a method taking a single, non-boolean argument (requires a placeholder string)
jamie@264 3693 template<typename C, typename M>
jamie@264 3694 void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
jamie@264 3695 m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
jamie@264 3696 m_arg->placeholder = placeholder;
jamie@264 3697 }
jamie@264 3698
jamie@264 3699 // Bind a method taking a single, boolean argument (no placeholder string required)
jamie@264 3700 template<typename C>
jamie@264 3701 void bind( void (C::* unaryMethod)( bool ) ) {
jamie@264 3702 m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
jamie@264 3703 }
jamie@264 3704
jamie@264 3705 // Bind a method that takes no arguments (will be called if opt is present)
jamie@264 3706 template<typename C>
jamie@264 3707 void bind( void (C::* nullaryMethod)() ) {
jamie@264 3708 m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
jamie@264 3709 }
jamie@264 3710
jamie@264 3711 // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
jamie@264 3712 template<typename C>
jamie@264 3713 void bind( void (* unaryFunction)( C& ) ) {
jamie@264 3714 m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
jamie@264 3715 }
jamie@264 3716
jamie@264 3717 // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
jamie@264 3718 template<typename C, typename T>
jamie@264 3719 void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
jamie@264 3720 m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
jamie@264 3721 m_arg->placeholder = placeholder;
jamie@264 3722 }
jamie@264 3723
jamie@264 3724 ArgBuilder& describe( std::string const& description ) {
jamie@264 3725 m_arg->description = description;
jamie@264 3726 return *this;
jamie@264 3727 }
jamie@264 3728 ArgBuilder& detail( std::string const& detail ) {
jamie@264 3729 m_arg->detail = detail;
jamie@264 3730 return *this;
jamie@264 3731 }
jamie@264 3732
jamie@264 3733 protected:
jamie@264 3734 Arg* m_arg;
jamie@264 3735 };
jamie@264 3736
jamie@264 3737 class OptBuilder : public ArgBuilder {
jamie@264 3738 public:
jamie@264 3739 OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
jamie@264 3740 OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
jamie@264 3741
jamie@264 3742 OptBuilder& operator[]( std::string const& optName ) {
jamie@264 3743 addOptName( *ArgBuilder::m_arg, optName );
jamie@264 3744 return *this;
jamie@264 3745 }
jamie@264 3746 };
jamie@264 3747
jamie@264 3748 public:
jamie@264 3749
jamie@264 3750 CommandLine()
jamie@264 3751 : m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
jamie@264 3752 m_highestSpecifiedArgPosition( 0 ),
jamie@264 3753 m_throwOnUnrecognisedTokens( false )
jamie@264 3754 {}
jamie@264 3755 CommandLine( CommandLine const& other )
jamie@264 3756 : m_boundProcessName( other.m_boundProcessName ),
jamie@264 3757 m_options ( other.m_options ),
jamie@264 3758 m_positionalArgs( other.m_positionalArgs ),
jamie@264 3759 m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
jamie@264 3760 m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
jamie@264 3761 {
jamie@264 3762 if( other.m_floatingArg.get() )
jamie@264 3763 m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) );
jamie@264 3764 }
jamie@264 3765
jamie@264 3766 CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
jamie@264 3767 m_throwOnUnrecognisedTokens = shouldThrow;
jamie@264 3768 return *this;
jamie@264 3769 }
jamie@264 3770
jamie@264 3771 OptBuilder operator[]( std::string const& optName ) {
jamie@264 3772 m_options.push_back( Arg() );
jamie@264 3773 addOptName( m_options.back(), optName );
jamie@264 3774 OptBuilder builder( &m_options.back() );
jamie@264 3775 return builder;
jamie@264 3776 }
jamie@264 3777
jamie@264 3778 ArgBuilder operator[]( int position ) {
jamie@264 3779 m_positionalArgs.insert( std::make_pair( position, Arg() ) );
jamie@264 3780 if( position > m_highestSpecifiedArgPosition )
jamie@264 3781 m_highestSpecifiedArgPosition = position;
jamie@264 3782 setPositionalArg( m_positionalArgs[position], position );
jamie@264 3783 ArgBuilder builder( &m_positionalArgs[position] );
jamie@264 3784 return builder;
jamie@264 3785 }
jamie@264 3786
jamie@264 3787 // Invoke this with the _ instance
jamie@264 3788 ArgBuilder operator[]( UnpositionalTag ) {
jamie@264 3789 if( m_floatingArg.get() )
jamie@264 3790 throw std::logic_error( "Only one unpositional argument can be added" );
jamie@264 3791 m_floatingArg = ArgAutoPtr( new Arg() );
jamie@264 3792 ArgBuilder builder( m_floatingArg.get() );
jamie@264 3793 return builder;
jamie@264 3794 }
jamie@264 3795
jamie@264 3796 template<typename C, typename M>
jamie@264 3797 void bindProcessName( M C::* field ) {
jamie@264 3798 m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
jamie@264 3799 }
jamie@264 3800 template<typename C, typename M>
jamie@264 3801 void bindProcessName( void (C::*_unaryMethod)( M ) ) {
jamie@264 3802 m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
jamie@264 3803 }
jamie@264 3804
jamie@264 3805 void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
jamie@264 3806 typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
jamie@264 3807 std::size_t maxWidth = 0;
jamie@264 3808 for( it = itBegin; it != itEnd; ++it )
jamie@264 3809 maxWidth = (std::max)( maxWidth, it->commands().size() );
jamie@264 3810
jamie@264 3811 for( it = itBegin; it != itEnd; ++it ) {
jamie@264 3812 Detail::Text usage( it->commands(), Detail::TextAttributes()
jamie@264 3813 .setWidth( maxWidth+indent )
jamie@264 3814 .setIndent( indent ) );
jamie@264 3815 Detail::Text desc( it->description, Detail::TextAttributes()
jamie@264 3816 .setWidth( width - maxWidth - 3 ) );
jamie@264 3817
jamie@264 3818 for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
jamie@264 3819 std::string usageCol = i < usage.size() ? usage[i] : "";
jamie@264 3820 os << usageCol;
jamie@264 3821
jamie@264 3822 if( i < desc.size() && !desc[i].empty() )
jamie@264 3823 os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
jamie@264 3824 << desc[i];
jamie@264 3825 os << "\n";
jamie@264 3826 }
jamie@264 3827 }
jamie@264 3828 }
jamie@264 3829 std::string optUsage() const {
jamie@264 3830 std::ostringstream oss;
jamie@264 3831 optUsage( oss );
jamie@264 3832 return oss.str();
jamie@264 3833 }
jamie@264 3834
jamie@264 3835 void argSynopsis( std::ostream& os ) const {
jamie@264 3836 for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
jamie@264 3837 if( i > 1 )
jamie@264 3838 os << " ";
jamie@264 3839 typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
jamie@264 3840 if( it != m_positionalArgs.end() )
jamie@264 3841 os << "<" << it->second.placeholder << ">";
jamie@264 3842 else if( m_floatingArg.get() )
jamie@264 3843 os << "<" << m_floatingArg->placeholder << ">";
jamie@264 3844 else
jamie@264 3845 throw std::logic_error( "non consecutive positional arguments with no floating args" );
jamie@264 3846 }
jamie@264 3847 // !TBD No indication of mandatory args
jamie@264 3848 if( m_floatingArg.get() ) {
jamie@264 3849 if( m_highestSpecifiedArgPosition > 1 )
jamie@264 3850 os << " ";
jamie@264 3851 os << "[<" << m_floatingArg->placeholder << "> ...]";
jamie@264 3852 }
jamie@264 3853 }
jamie@264 3854 std::string argSynopsis() const {
jamie@264 3855 std::ostringstream oss;
jamie@264 3856 argSynopsis( oss );
jamie@264 3857 return oss.str();
jamie@264 3858 }
jamie@264 3859
jamie@264 3860 void usage( std::ostream& os, std::string const& procName ) const {
jamie@264 3861 validate();
jamie@264 3862 os << "usage:\n " << procName << " ";
jamie@264 3863 argSynopsis( os );
jamie@264 3864 if( !m_options.empty() ) {
jamie@264 3865 os << " [options]\n\nwhere options are: \n";
jamie@264 3866 optUsage( os, 2 );
jamie@264 3867 }
jamie@264 3868 os << "\n";
jamie@264 3869 }
jamie@264 3870 std::string usage( std::string const& procName ) const {
jamie@264 3871 std::ostringstream oss;
jamie@264 3872 usage( oss, procName );
jamie@264 3873 return oss.str();
jamie@264 3874 }
jamie@264 3875
jamie@264 3876 ConfigT parse( int argc, char const * const * argv ) const {
jamie@264 3877 ConfigT config;
jamie@264 3878 parseInto( argc, argv, config );
jamie@264 3879 return config;
jamie@264 3880 }
jamie@264 3881
jamie@264 3882 std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
jamie@264 3883 std::string processName = argv[0];
jamie@264 3884 std::size_t lastSlash = processName.find_last_of( "/\\" );
jamie@264 3885 if( lastSlash != std::string::npos )
jamie@264 3886 processName = processName.substr( lastSlash+1 );
jamie@264 3887 m_boundProcessName.set( config, processName );
jamie@264 3888 std::vector<Parser::Token> tokens;
jamie@264 3889 Parser parser;
jamie@264 3890 parser.parseIntoTokens( argc, argv, tokens );
jamie@264 3891 return populate( tokens, config );
jamie@264 3892 }
jamie@264 3893
jamie@264 3894 std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
jamie@264 3895 validate();
jamie@264 3896 std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
jamie@264 3897 unusedTokens = populateFixedArgs( unusedTokens, config );
jamie@264 3898 unusedTokens = populateFloatingArgs( unusedTokens, config );
jamie@264 3899 return unusedTokens;
jamie@264 3900 }
jamie@264 3901
jamie@264 3902 std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
jamie@264 3903 std::vector<Parser::Token> unusedTokens;
jamie@264 3904 std::vector<std::string> errors;
jamie@264 3905 for( std::size_t i = 0; i < tokens.size(); ++i ) {
jamie@264 3906 Parser::Token const& token = tokens[i];
jamie@264 3907 typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
jamie@264 3908 for(; it != itEnd; ++it ) {
jamie@264 3909 Arg const& arg = *it;
jamie@264 3910
jamie@264 3911 try {
jamie@264 3912 if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
jamie@264 3913 ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
jamie@264 3914 if( arg.takesArg() ) {
jamie@264 3915 if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
jamie@264 3916 errors.push_back( "Expected argument to option: " + token.data );
jamie@264 3917 else
jamie@264 3918 arg.boundField.set( config, tokens[++i].data );
jamie@264 3919 }
jamie@264 3920 else {
jamie@264 3921 arg.boundField.setFlag( config );
jamie@264 3922 }
jamie@264 3923 break;
jamie@264 3924 }
jamie@264 3925 }
jamie@264 3926 catch( std::exception& ex ) {
jamie@264 3927 errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
jamie@264 3928 }
jamie@264 3929 }
jamie@264 3930 if( it == itEnd ) {
jamie@264 3931 if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
jamie@264 3932 unusedTokens.push_back( token );
jamie@264 3933 else if( m_throwOnUnrecognisedTokens )
jamie@264 3934 errors.push_back( "unrecognised option: " + token.data );
jamie@264 3935 }
jamie@264 3936 }
jamie@264 3937 if( !errors.empty() ) {
jamie@264 3938 std::ostringstream oss;
jamie@264 3939 for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
jamie@264 3940 it != itEnd;
jamie@264 3941 ++it ) {
jamie@264 3942 if( it != errors.begin() )
jamie@264 3943 oss << "\n";
jamie@264 3944 oss << *it;
jamie@264 3945 }
jamie@264 3946 throw std::runtime_error( oss.str() );
jamie@264 3947 }
jamie@264 3948 return unusedTokens;
jamie@264 3949 }
jamie@264 3950 std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
jamie@264 3951 std::vector<Parser::Token> unusedTokens;
jamie@264 3952 int position = 1;
jamie@264 3953 for( std::size_t i = 0; i < tokens.size(); ++i ) {
jamie@264 3954 Parser::Token const& token = tokens[i];
jamie@264 3955 typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
jamie@264 3956 if( it != m_positionalArgs.end() )
jamie@264 3957 it->second.boundField.set( config, token.data );
jamie@264 3958 else
jamie@264 3959 unusedTokens.push_back( token );
jamie@264 3960 if( token.type == Parser::Token::Positional )
jamie@264 3961 position++;
jamie@264 3962 }
jamie@264 3963 return unusedTokens;
jamie@264 3964 }
jamie@264 3965 std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
jamie@264 3966 if( !m_floatingArg.get() )
jamie@264 3967 return tokens;
jamie@264 3968 std::vector<Parser::Token> unusedTokens;
jamie@264 3969 for( std::size_t i = 0; i < tokens.size(); ++i ) {
jamie@264 3970 Parser::Token const& token = tokens[i];
jamie@264 3971 if( token.type == Parser::Token::Positional )
jamie@264 3972 m_floatingArg->boundField.set( config, token.data );
jamie@264 3973 else
jamie@264 3974 unusedTokens.push_back( token );
jamie@264 3975 }
jamie@264 3976 return unusedTokens;
jamie@264 3977 }
jamie@264 3978
jamie@264 3979 void validate() const
jamie@264 3980 {
jamie@264 3981 if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
jamie@264 3982 throw std::logic_error( "No options or arguments specified" );
jamie@264 3983
jamie@264 3984 for( typename std::vector<Arg>::const_iterator it = m_options.begin(),
jamie@264 3985 itEnd = m_options.end();
jamie@264 3986 it != itEnd; ++it )
jamie@264 3987 it->validate();
jamie@264 3988 }
jamie@264 3989
jamie@264 3990 private:
jamie@264 3991 Detail::BoundArgFunction<ConfigT> m_boundProcessName;
jamie@264 3992 std::vector<Arg> m_options;
jamie@264 3993 std::map<int, Arg> m_positionalArgs;
jamie@264 3994 ArgAutoPtr m_floatingArg;
jamie@264 3995 int m_highestSpecifiedArgPosition;
jamie@264 3996 bool m_throwOnUnrecognisedTokens;
jamie@264 3997 };
jamie@264 3998
jamie@264 3999 } // end namespace Clara
jamie@264 4000
jamie@264 4001 STITCH_CLARA_CLOSE_NAMESPACE
jamie@264 4002 #undef STITCH_CLARA_OPEN_NAMESPACE
jamie@264 4003 #undef STITCH_CLARA_CLOSE_NAMESPACE
jamie@264 4004
jamie@264 4005 #endif // TWOBLUECUBES_CLARA_H_INCLUDED
jamie@264 4006 #undef STITCH_CLARA_OPEN_NAMESPACE
jamie@264 4007
jamie@264 4008 // Restore Clara's value for console width, if present
jamie@264 4009 #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
jamie@264 4010 #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
jamie@264 4011 #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
jamie@264 4012 #endif
jamie@264 4013
jamie@264 4014 #include <fstream>
jamie@264 4015
jamie@264 4016 namespace Catch {
jamie@264 4017
jamie@264 4018 inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
jamie@264 4019 inline void abortAfterX( ConfigData& config, int x ) {
jamie@264 4020 if( x < 1 )
jamie@264 4021 throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
jamie@264 4022 config.abortAfter = x;
jamie@264 4023 }
jamie@264 4024 inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
jamie@264 4025
jamie@264 4026 inline void addWarning( ConfigData& config, std::string const& _warning ) {
jamie@264 4027 if( _warning == "NoAssertions" )
jamie@264 4028 config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
jamie@264 4029 else
jamie@264 4030 throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
jamie@264 4031
jamie@264 4032 }
jamie@264 4033 inline void setVerbosity( ConfigData& config, int level ) {
jamie@264 4034 // !TBD: accept strings?
jamie@264 4035 config.verbosity = static_cast<Verbosity::Level>( level );
jamie@264 4036 }
jamie@264 4037 inline void setShowDurations( ConfigData& config, bool _showDurations ) {
jamie@264 4038 config.showDurations = _showDurations
jamie@264 4039 ? ShowDurations::Always
jamie@264 4040 : ShowDurations::Never;
jamie@264 4041 }
jamie@264 4042 inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
jamie@264 4043 std::ifstream f( _filename.c_str() );
jamie@264 4044 if( !f.is_open() )
jamie@264 4045 throw std::domain_error( "Unable to load input file: " + _filename );
jamie@264 4046
jamie@264 4047 std::string line;
jamie@264 4048 while( std::getline( f, line ) ) {
jamie@264 4049 line = trim(line);
jamie@264 4050 if( !line.empty() && !startsWith( line, "#" ) )
jamie@264 4051 addTestOrTags( config, "\"" + line + "\"," );
jamie@264 4052 }
jamie@264 4053 }
jamie@264 4054
jamie@264 4055 inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
jamie@264 4056
jamie@264 4057 using namespace Clara;
jamie@264 4058 CommandLine<ConfigData> cli;
jamie@264 4059
jamie@264 4060 cli.bindProcessName( &ConfigData::processName );
jamie@264 4061
jamie@264 4062 cli["-?"]["-h"]["--help"]
jamie@264 4063 .describe( "display usage information" )
jamie@264 4064 .bind( &ConfigData::showHelp );
jamie@264 4065
jamie@264 4066 cli["-l"]["--list-tests"]
jamie@264 4067 .describe( "list all/matching test cases" )
jamie@264 4068 .bind( &ConfigData::listTests );
jamie@264 4069
jamie@264 4070 cli["-t"]["--list-tags"]
jamie@264 4071 .describe( "list all/matching tags" )
jamie@264 4072 .bind( &ConfigData::listTags );
jamie@264 4073
jamie@264 4074 cli["-s"]["--success"]
jamie@264 4075 .describe( "include successful tests in output" )
jamie@264 4076 .bind( &ConfigData::showSuccessfulTests );
jamie@264 4077
jamie@264 4078 cli["-b"]["--break"]
jamie@264 4079 .describe( "break into debugger on failure" )
jamie@264 4080 .bind( &ConfigData::shouldDebugBreak );
jamie@264 4081
jamie@264 4082 cli["-e"]["--nothrow"]
jamie@264 4083 .describe( "skip exception tests" )
jamie@264 4084 .bind( &ConfigData::noThrow );
jamie@264 4085
jamie@264 4086 cli["-i"]["--invisibles"]
jamie@264 4087 .describe( "show invisibles (tabs, newlines)" )
jamie@264 4088 .bind( &ConfigData::showInvisibles );
jamie@264 4089
jamie@264 4090 cli["-o"]["--out"]
jamie@264 4091 .describe( "output filename" )
jamie@264 4092 .bind( &ConfigData::outputFilename, "filename" );
jamie@264 4093
jamie@264 4094 cli["-r"]["--reporter"]
jamie@264 4095 // .placeholder( "name[:filename]" )
jamie@264 4096 .describe( "reporter to use (defaults to console)" )
jamie@264 4097 .bind( &ConfigData::reporterName, "name" );
jamie@264 4098
jamie@264 4099 cli["-n"]["--name"]
jamie@264 4100 .describe( "suite name" )
jamie@264 4101 .bind( &ConfigData::name, "name" );
jamie@264 4102
jamie@264 4103 cli["-a"]["--abort"]
jamie@264 4104 .describe( "abort at first failure" )
jamie@264 4105 .bind( &abortAfterFirst );
jamie@264 4106
jamie@264 4107 cli["-x"]["--abortx"]
jamie@264 4108 .describe( "abort after x failures" )
jamie@264 4109 .bind( &abortAfterX, "no. failures" );
jamie@264 4110
jamie@264 4111 cli["-w"]["--warn"]
jamie@264 4112 .describe( "enable warnings" )
jamie@264 4113 .bind( &addWarning, "warning name" );
jamie@264 4114
jamie@264 4115 // - needs updating if reinstated
jamie@264 4116 // cli.into( &setVerbosity )
jamie@264 4117 // .describe( "level of verbosity (0=no output)" )
jamie@264 4118 // .shortOpt( "v")
jamie@264 4119 // .longOpt( "verbosity" )
jamie@264 4120 // .placeholder( "level" );
jamie@264 4121
jamie@264 4122 cli[_]
jamie@264 4123 .describe( "which test or tests to use" )
jamie@264 4124 .bind( &addTestOrTags, "test name, pattern or tags" );
jamie@264 4125
jamie@264 4126 cli["-d"]["--durations"]
jamie@264 4127 .describe( "show test durations" )
jamie@264 4128 .bind( &setShowDurations, "yes/no" );
jamie@264 4129
jamie@264 4130 cli["-f"]["--input-file"]
jamie@264 4131 .describe( "load test names to run from a file" )
jamie@264 4132 .bind( &loadTestNamesFromFile, "filename" );
jamie@264 4133
jamie@264 4134 // Less common commands which don't have a short form
jamie@264 4135 cli["--list-test-names-only"]
jamie@264 4136 .describe( "list all/matching test cases names only" )
jamie@264 4137 .bind( &ConfigData::listTestNamesOnly );
jamie@264 4138
jamie@264 4139 cli["--list-reporters"]
jamie@264 4140 .describe( "list all reporters" )
jamie@264 4141 .bind( &ConfigData::listReporters );
jamie@264 4142
jamie@264 4143 return cli;
jamie@264 4144 }
jamie@264 4145
jamie@264 4146 } // end namespace Catch
jamie@264 4147
jamie@264 4148 // #included from: internal/catch_list.hpp
jamie@264 4149 #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
jamie@264 4150
jamie@264 4151 // #included from: catch_text.h
jamie@264 4152 #define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
jamie@264 4153
jamie@264 4154 #define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
jamie@264 4155
jamie@264 4156 #define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
jamie@264 4157 // #included from: ../external/tbc_text_format.h
jamie@264 4158 // Only use header guard if we are not using an outer namespace
jamie@264 4159 #ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
jamie@264 4160 # ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
jamie@264 4161 # ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
jamie@264 4162 # define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
jamie@264 4163 # endif
jamie@264 4164 # else
jamie@264 4165 # define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
jamie@264 4166 # endif
jamie@264 4167 #endif
jamie@264 4168 #ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
jamie@264 4169 #include <string>
jamie@264 4170 #include <vector>
jamie@264 4171 #include <sstream>
jamie@264 4172
jamie@264 4173 // Use optional outer namespace
jamie@264 4174 #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
jamie@264 4175 namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
jamie@264 4176 #endif
jamie@264 4177
jamie@264 4178 namespace Tbc {
jamie@264 4179
jamie@264 4180 #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
jamie@264 4181 const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
jamie@264 4182 #else
jamie@264 4183 const unsigned int consoleWidth = 80;
jamie@264 4184 #endif
jamie@264 4185
jamie@264 4186 struct TextAttributes {
jamie@264 4187 TextAttributes()
jamie@264 4188 : initialIndent( std::string::npos ),
jamie@264 4189 indent( 0 ),
jamie@264 4190 width( consoleWidth-1 ),
jamie@264 4191 tabChar( '\t' )
jamie@264 4192 {}
jamie@264 4193
jamie@264 4194 TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
jamie@264 4195 TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
jamie@264 4196 TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
jamie@264 4197 TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
jamie@264 4198
jamie@264 4199 std::size_t initialIndent; // indent of first line, or npos
jamie@264 4200 std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
jamie@264 4201 std::size_t width; // maximum width of text, including indent. Longer text will wrap
jamie@264 4202 char tabChar; // If this char is seen the indent is changed to current pos
jamie@264 4203 };
jamie@264 4204
jamie@264 4205 class Text {
jamie@264 4206 public:
jamie@264 4207 Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
jamie@264 4208 : attr( _attr )
jamie@264 4209 {
jamie@264 4210 std::string wrappableChars = " [({.,/|\\-";
jamie@264 4211 std::size_t indent = _attr.initialIndent != std::string::npos
jamie@264 4212 ? _attr.initialIndent
jamie@264 4213 : _attr.indent;
jamie@264 4214 std::string remainder = _str;
jamie@264 4215
jamie@264 4216 while( !remainder.empty() ) {
jamie@264 4217 if( lines.size() >= 1000 ) {
jamie@264 4218 lines.push_back( "... message truncated due to excessive size" );
jamie@264 4219 return;
jamie@264 4220 }
jamie@264 4221 std::size_t tabPos = std::string::npos;
jamie@264 4222 std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
jamie@264 4223 std::size_t pos = remainder.find_first_of( '\n' );
jamie@264 4224 if( pos <= width ) {
jamie@264 4225 width = pos;
jamie@264 4226 }
jamie@264 4227 pos = remainder.find_last_of( _attr.tabChar, width );
jamie@264 4228 if( pos != std::string::npos ) {
jamie@264 4229 tabPos = pos;
jamie@264 4230 if( remainder[width] == '\n' )
jamie@264 4231 width--;
jamie@264 4232 remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
jamie@264 4233 }
jamie@264 4234
jamie@264 4235 if( width == remainder.size() ) {
jamie@264 4236 spliceLine( indent, remainder, width );
jamie@264 4237 }
jamie@264 4238 else if( remainder[width] == '\n' ) {
jamie@264 4239 spliceLine( indent, remainder, width );
jamie@264 4240 if( width <= 1 || remainder.size() != 1 )
jamie@264 4241 remainder = remainder.substr( 1 );
jamie@264 4242 indent = _attr.indent;
jamie@264 4243 }
jamie@264 4244 else {
jamie@264 4245 pos = remainder.find_last_of( wrappableChars, width );
jamie@264 4246 if( pos != std::string::npos && pos > 0 ) {
jamie@264 4247 spliceLine( indent, remainder, pos );
jamie@264 4248 if( remainder[0] == ' ' )
jamie@264 4249 remainder = remainder.substr( 1 );
jamie@264 4250 }
jamie@264 4251 else {
jamie@264 4252 spliceLine( indent, remainder, width-1 );
jamie@264 4253 lines.back() += "-";
jamie@264 4254 }
jamie@264 4255 if( lines.size() == 1 )
jamie@264 4256 indent = _attr.indent;
jamie@264 4257 if( tabPos != std::string::npos )
jamie@264 4258 indent += tabPos;
jamie@264 4259 }
jamie@264 4260 }
jamie@264 4261 }
jamie@264 4262
jamie@264 4263 void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
jamie@264 4264 lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
jamie@264 4265 _remainder = _remainder.substr( _pos );
jamie@264 4266 }
jamie@264 4267
jamie@264 4268 typedef std::vector<std::string>::const_iterator const_iterator;
jamie@264 4269
jamie@264 4270 const_iterator begin() const { return lines.begin(); }
jamie@264 4271 const_iterator end() const { return lines.end(); }
jamie@264 4272 std::string const& last() const { return lines.back(); }
jamie@264 4273 std::size_t size() const { return lines.size(); }
jamie@264 4274 std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
jamie@264 4275 std::string toString() const {
jamie@264 4276 std::ostringstream oss;
jamie@264 4277 oss << *this;
jamie@264 4278 return oss.str();
jamie@264 4279 }
jamie@264 4280
jamie@264 4281 inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
jamie@264 4282 for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
jamie@264 4283 it != itEnd; ++it ) {
jamie@264 4284 if( it != _text.begin() )
jamie@264 4285 _stream << "\n";
jamie@264 4286 _stream << *it;
jamie@264 4287 }
jamie@264 4288 return _stream;
jamie@264 4289 }
jamie@264 4290
jamie@264 4291 private:
jamie@264 4292 std::string str;
jamie@264 4293 TextAttributes attr;
jamie@264 4294 std::vector<std::string> lines;
jamie@264 4295 };
jamie@264 4296
jamie@264 4297 } // end namespace Tbc
jamie@264 4298
jamie@264 4299 #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
jamie@264 4300 } // end outer namespace
jamie@264 4301 #endif
jamie@264 4302
jamie@264 4303 #endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
jamie@264 4304 #undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
jamie@264 4305
jamie@264 4306 namespace Catch {
jamie@264 4307 using Tbc::Text;
jamie@264 4308 using Tbc::TextAttributes;
jamie@264 4309 }
jamie@264 4310
jamie@264 4311 // #included from: catch_console_colour.hpp
jamie@264 4312 #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
jamie@264 4313
jamie@264 4314 namespace Catch {
jamie@264 4315
jamie@264 4316 namespace Detail {
jamie@264 4317 struct IColourImpl;
jamie@264 4318 }
jamie@264 4319
jamie@264 4320 struct Colour {
jamie@264 4321 enum Code {
jamie@264 4322 None = 0,
jamie@264 4323
jamie@264 4324 White,
jamie@264 4325 Red,
jamie@264 4326 Green,
jamie@264 4327 Blue,
jamie@264 4328 Cyan,
jamie@264 4329 Yellow,
jamie@264 4330 Grey,
jamie@264 4331
jamie@264 4332 Bright = 0x10,
jamie@264 4333
jamie@264 4334 BrightRed = Bright | Red,
jamie@264 4335 BrightGreen = Bright | Green,
jamie@264 4336 LightGrey = Bright | Grey,
jamie@264 4337 BrightWhite = Bright | White,
jamie@264 4338
jamie@264 4339 // By intention
jamie@264 4340 FileName = LightGrey,
jamie@264 4341 Warning = Yellow,
jamie@264 4342 ResultError = BrightRed,
jamie@264 4343 ResultSuccess = BrightGreen,
jamie@264 4344 ResultExpectedFailure = Warning,
jamie@264 4345
jamie@264 4346 Error = BrightRed,
jamie@264 4347 Success = Green,
jamie@264 4348
jamie@264 4349 OriginalExpression = Cyan,
jamie@264 4350 ReconstructedExpression = Yellow,
jamie@264 4351
jamie@264 4352 SecondaryText = LightGrey,
jamie@264 4353 Headers = White
jamie@264 4354 };
jamie@264 4355
jamie@264 4356 // Use constructed object for RAII guard
jamie@264 4357 Colour( Code _colourCode );
jamie@264 4358 Colour( Colour const& other );
jamie@264 4359 ~Colour();
jamie@264 4360
jamie@264 4361 // Use static method for one-shot changes
jamie@264 4362 static void use( Code _colourCode );
jamie@264 4363
jamie@264 4364 private:
jamie@264 4365 static Detail::IColourImpl* impl();
jamie@264 4366 bool m_moved;
jamie@264 4367 };
jamie@264 4368
jamie@264 4369 inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
jamie@264 4370
jamie@264 4371 } // end namespace Catch
jamie@264 4372
jamie@264 4373 // #included from: catch_interfaces_reporter.h
jamie@264 4374 #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
jamie@264 4375
jamie@264 4376 #include <string>
jamie@264 4377 #include <ostream>
jamie@264 4378 #include <map>
jamie@264 4379 #include <assert.h>
jamie@264 4380
jamie@264 4381 namespace Catch
jamie@264 4382 {
jamie@264 4383 struct ReporterConfig {
jamie@264 4384 explicit ReporterConfig( Ptr<IConfig> const& _fullConfig )
jamie@264 4385 : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
jamie@264 4386
jamie@264 4387 ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream )
jamie@264 4388 : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
jamie@264 4389
jamie@264 4390 std::ostream& stream() const { return *m_stream; }
jamie@264 4391 Ptr<IConfig> fullConfig() const { return m_fullConfig; }
jamie@264 4392
jamie@264 4393 private:
jamie@264 4394 std::ostream* m_stream;
jamie@264 4395 Ptr<IConfig> m_fullConfig;
jamie@264 4396 };
jamie@264 4397
jamie@264 4398 struct ReporterPreferences {
jamie@264 4399 ReporterPreferences()
jamie@264 4400 : shouldRedirectStdOut( false )
jamie@264 4401 {}
jamie@264 4402
jamie@264 4403 bool shouldRedirectStdOut;
jamie@264 4404 };
jamie@264 4405
jamie@264 4406 template<typename T>
jamie@264 4407 struct LazyStat : Option<T> {
jamie@264 4408 LazyStat() : used( false ) {}
jamie@264 4409 LazyStat& operator=( T const& _value ) {
jamie@264 4410 Option<T>::operator=( _value );
jamie@264 4411 used = false;
jamie@264 4412 return *this;
jamie@264 4413 }
jamie@264 4414 void reset() {
jamie@264 4415 Option<T>::reset();
jamie@264 4416 used = false;
jamie@264 4417 }
jamie@264 4418 bool used;
jamie@264 4419 };
jamie@264 4420
jamie@264 4421 struct TestRunInfo {
jamie@264 4422 TestRunInfo( std::string const& _name ) : name( _name ) {}
jamie@264 4423 std::string name;
jamie@264 4424 };
jamie@264 4425 struct GroupInfo {
jamie@264 4426 GroupInfo( std::string const& _name,
jamie@264 4427 std::size_t _groupIndex,
jamie@264 4428 std::size_t _groupsCount )
jamie@264 4429 : name( _name ),
jamie@264 4430 groupIndex( _groupIndex ),
jamie@264 4431 groupsCounts( _groupsCount )
jamie@264 4432 {}
jamie@264 4433
jamie@264 4434 std::string name;
jamie@264 4435 std::size_t groupIndex;
jamie@264 4436 std::size_t groupsCounts;
jamie@264 4437 };
jamie@264 4438
jamie@264 4439 struct AssertionStats {
jamie@264 4440 AssertionStats( AssertionResult const& _assertionResult,
jamie@264 4441 std::vector<MessageInfo> const& _infoMessages,
jamie@264 4442 Totals const& _totals )
jamie@264 4443 : assertionResult( _assertionResult ),
jamie@264 4444 infoMessages( _infoMessages ),
jamie@264 4445 totals( _totals )
jamie@264 4446 {
jamie@264 4447 if( assertionResult.hasMessage() ) {
jamie@264 4448 // Copy message into messages list.
jamie@264 4449 // !TBD This should have been done earlier, somewhere
jamie@264 4450 MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
jamie@264 4451 builder << assertionResult.getMessage();
jamie@264 4452 builder.m_info.message = builder.m_stream.str();
jamie@264 4453
jamie@264 4454 infoMessages.push_back( builder.m_info );
jamie@264 4455 }
jamie@264 4456 }
jamie@264 4457 virtual ~AssertionStats();
jamie@264 4458
jamie@264 4459 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 4460 AssertionStats( AssertionStats const& ) = default;
jamie@264 4461 AssertionStats( AssertionStats && ) = default;
jamie@264 4462 AssertionStats& operator = ( AssertionStats const& ) = default;
jamie@264 4463 AssertionStats& operator = ( AssertionStats && ) = default;
jamie@264 4464 # endif
jamie@264 4465
jamie@264 4466 AssertionResult assertionResult;
jamie@264 4467 std::vector<MessageInfo> infoMessages;
jamie@264 4468 Totals totals;
jamie@264 4469 };
jamie@264 4470
jamie@264 4471 struct SectionStats {
jamie@264 4472 SectionStats( SectionInfo const& _sectionInfo,
jamie@264 4473 Counts const& _assertions,
jamie@264 4474 double _durationInSeconds,
jamie@264 4475 bool _missingAssertions )
jamie@264 4476 : sectionInfo( _sectionInfo ),
jamie@264 4477 assertions( _assertions ),
jamie@264 4478 durationInSeconds( _durationInSeconds ),
jamie@264 4479 missingAssertions( _missingAssertions )
jamie@264 4480 {}
jamie@264 4481 virtual ~SectionStats();
jamie@264 4482 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 4483 SectionStats( SectionStats const& ) = default;
jamie@264 4484 SectionStats( SectionStats && ) = default;
jamie@264 4485 SectionStats& operator = ( SectionStats const& ) = default;
jamie@264 4486 SectionStats& operator = ( SectionStats && ) = default;
jamie@264 4487 # endif
jamie@264 4488
jamie@264 4489 SectionInfo sectionInfo;
jamie@264 4490 Counts assertions;
jamie@264 4491 double durationInSeconds;
jamie@264 4492 bool missingAssertions;
jamie@264 4493 };
jamie@264 4494
jamie@264 4495 struct TestCaseStats {
jamie@264 4496 TestCaseStats( TestCaseInfo const& _testInfo,
jamie@264 4497 Totals const& _totals,
jamie@264 4498 std::string const& _stdOut,
jamie@264 4499 std::string const& _stdErr,
jamie@264 4500 bool _aborting )
jamie@264 4501 : testInfo( _testInfo ),
jamie@264 4502 totals( _totals ),
jamie@264 4503 stdOut( _stdOut ),
jamie@264 4504 stdErr( _stdErr ),
jamie@264 4505 aborting( _aborting )
jamie@264 4506 {}
jamie@264 4507 virtual ~TestCaseStats();
jamie@264 4508
jamie@264 4509 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 4510 TestCaseStats( TestCaseStats const& ) = default;
jamie@264 4511 TestCaseStats( TestCaseStats && ) = default;
jamie@264 4512 TestCaseStats& operator = ( TestCaseStats const& ) = default;
jamie@264 4513 TestCaseStats& operator = ( TestCaseStats && ) = default;
jamie@264 4514 # endif
jamie@264 4515
jamie@264 4516 TestCaseInfo testInfo;
jamie@264 4517 Totals totals;
jamie@264 4518 std::string stdOut;
jamie@264 4519 std::string stdErr;
jamie@264 4520 bool aborting;
jamie@264 4521 };
jamie@264 4522
jamie@264 4523 struct TestGroupStats {
jamie@264 4524 TestGroupStats( GroupInfo const& _groupInfo,
jamie@264 4525 Totals const& _totals,
jamie@264 4526 bool _aborting )
jamie@264 4527 : groupInfo( _groupInfo ),
jamie@264 4528 totals( _totals ),
jamie@264 4529 aborting( _aborting )
jamie@264 4530 {}
jamie@264 4531 TestGroupStats( GroupInfo const& _groupInfo )
jamie@264 4532 : groupInfo( _groupInfo ),
jamie@264 4533 aborting( false )
jamie@264 4534 {}
jamie@264 4535 virtual ~TestGroupStats();
jamie@264 4536
jamie@264 4537 # ifdef CATCH_CPP11_OR_GREATER
jamie@264 4538 TestGroupStats( TestGroupStats const& ) = default;
jamie@264 4539 TestGroupStats( TestGroupStats && ) = default;
jamie@264 4540 TestGroupStats& operator = ( TestGroupStats const& ) = default;
jamie@264 4541 TestGroupStats& operator = ( TestGroupStats && ) = default;
jamie@264 4542 # endif
jamie@264 4543
jamie@264 4544 GroupInfo groupInfo;
jamie@264 4545 Totals totals;
jamie@264 4546 bool aborting;
jamie@264 4547 };
jamie@264 4548
jamie@264 4549 struct TestRunStats {
jamie@264 4550 TestRunStats( TestRunInfo const& _runInfo,
jamie@264 4551 Totals const& _totals,
jamie@264 4552 bool _aborting )
jamie@264 4553 : runInfo( _runInfo ),
jamie@264 4554 totals( _totals ),
jamie@264 4555 aborting( _aborting )
jamie@264 4556 {}
jamie@264 4557 virtual ~TestRunStats();
jamie@264 4558
jamie@264 4559 # ifndef CATCH_CPP11_OR_GREATER
jamie@264 4560 TestRunStats( TestRunStats const& _other )
jamie@264 4561 : runInfo( _other.runInfo ),
jamie@264 4562 totals( _other.totals ),
jamie@264 4563 aborting( _other.aborting )
jamie@264 4564 {}
jamie@264 4565 # else
jamie@264 4566 TestRunStats( TestRunStats const& ) = default;
jamie@264 4567 TestRunStats( TestRunStats && ) = default;
jamie@264 4568 TestRunStats& operator = ( TestRunStats const& ) = default;
jamie@264 4569 TestRunStats& operator = ( TestRunStats && ) = default;
jamie@264 4570 # endif
jamie@264 4571
jamie@264 4572 TestRunInfo runInfo;
jamie@264 4573 Totals totals;
jamie@264 4574 bool aborting;
jamie@264 4575 };
jamie@264 4576
jamie@264 4577 struct IStreamingReporter : IShared {
jamie@264 4578 virtual ~IStreamingReporter();
jamie@264 4579
jamie@264 4580 // Implementing class must also provide the following static method:
jamie@264 4581 // static std::string getDescription();
jamie@264 4582
jamie@264 4583 virtual ReporterPreferences getPreferences() const = 0;
jamie@264 4584
jamie@264 4585 virtual void noMatchingTestCases( std::string const& spec ) = 0;
jamie@264 4586
jamie@264 4587 virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
jamie@264 4588 virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
jamie@264 4589
jamie@264 4590 virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
jamie@264 4591 virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
jamie@264 4592
jamie@264 4593 virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
jamie@264 4594
jamie@264 4595 virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
jamie@264 4596 virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
jamie@264 4597 virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
jamie@264 4598 virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
jamie@264 4599 virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
jamie@264 4600 };
jamie@264 4601
jamie@264 4602 struct IReporterFactory {
jamie@264 4603 virtual ~IReporterFactory();
jamie@264 4604 virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
jamie@264 4605 virtual std::string getDescription() const = 0;
jamie@264 4606 };
jamie@264 4607
jamie@264 4608 struct IReporterRegistry {
jamie@264 4609 typedef std::map<std::string, IReporterFactory*> FactoryMap;
jamie@264 4610
jamie@264 4611 virtual ~IReporterRegistry();
jamie@264 4612 virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0;
jamie@264 4613 virtual FactoryMap const& getFactories() const = 0;
jamie@264 4614 };
jamie@264 4615
jamie@264 4616 }
jamie@264 4617
jamie@264 4618 #include <limits>
jamie@264 4619 #include <algorithm>
jamie@264 4620
jamie@264 4621 namespace Catch {
jamie@264 4622
jamie@264 4623 inline std::size_t listTests( Config const& config ) {
jamie@264 4624
jamie@264 4625 TestSpec testSpec = config.testSpec();
jamie@264 4626 if( config.testSpec().hasFilters() )
jamie@264 4627 std::cout << "Matching test cases:\n";
jamie@264 4628 else {
jamie@264 4629 std::cout << "All available test cases:\n";
jamie@264 4630 testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
jamie@264 4631 }
jamie@264 4632
jamie@264 4633 std::size_t matchedTests = 0;
jamie@264 4634 TextAttributes nameAttr, tagsAttr;
jamie@264 4635 nameAttr.setInitialIndent( 2 ).setIndent( 4 );
jamie@264 4636 tagsAttr.setIndent( 6 );
jamie@264 4637
jamie@264 4638 std::vector<TestCase> matchedTestCases;
jamie@264 4639 getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
jamie@264 4640 for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
jamie@264 4641 it != itEnd;
jamie@264 4642 ++it ) {
jamie@264 4643 matchedTests++;
jamie@264 4644 TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
jamie@264 4645 Colour::Code colour = testCaseInfo.isHidden()
jamie@264 4646 ? Colour::SecondaryText
jamie@264 4647 : Colour::None;
jamie@264 4648 Colour colourGuard( colour );
jamie@264 4649
jamie@264 4650 std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl;
jamie@264 4651 if( !testCaseInfo.tags.empty() )
jamie@264 4652 std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
jamie@264 4653 }
jamie@264 4654
jamie@264 4655 if( !config.testSpec().hasFilters() )
jamie@264 4656 std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
jamie@264 4657 else
jamie@264 4658 std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
jamie@264 4659 return matchedTests;
jamie@264 4660 }
jamie@264 4661
jamie@264 4662 inline std::size_t listTestsNamesOnly( Config const& config ) {
jamie@264 4663 TestSpec testSpec = config.testSpec();
jamie@264 4664 if( !config.testSpec().hasFilters() )
jamie@264 4665 testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
jamie@264 4666 std::size_t matchedTests = 0;
jamie@264 4667 std::vector<TestCase> matchedTestCases;
jamie@264 4668 getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
jamie@264 4669 for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
jamie@264 4670 it != itEnd;
jamie@264 4671 ++it ) {
jamie@264 4672 matchedTests++;
jamie@264 4673 TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
jamie@264 4674 std::cout << testCaseInfo.name << std::endl;
jamie@264 4675 }
jamie@264 4676 return matchedTests;
jamie@264 4677 }
jamie@264 4678
jamie@264 4679 struct TagInfo {
jamie@264 4680 TagInfo() : count ( 0 ) {}
jamie@264 4681 void add( std::string const& spelling ) {
jamie@264 4682 ++count;
jamie@264 4683 spellings.insert( spelling );
jamie@264 4684 }
jamie@264 4685 std::string all() const {
jamie@264 4686 std::string out;
jamie@264 4687 for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
jamie@264 4688 it != itEnd;
jamie@264 4689 ++it )
jamie@264 4690 out += "[" + *it + "]";
jamie@264 4691 return out;
jamie@264 4692 }
jamie@264 4693 std::set<std::string> spellings;
jamie@264 4694 std::size_t count;
jamie@264 4695 };
jamie@264 4696
jamie@264 4697 inline std::size_t listTags( Config const& config ) {
jamie@264 4698 TestSpec testSpec = config.testSpec();
jamie@264 4699 if( config.testSpec().hasFilters() )
jamie@264 4700 std::cout << "Tags for matching test cases:\n";
jamie@264 4701 else {
jamie@264 4702 std::cout << "All available tags:\n";
jamie@264 4703 testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
jamie@264 4704 }
jamie@264 4705
jamie@264 4706 std::map<std::string, TagInfo> tagCounts;
jamie@264 4707
jamie@264 4708 std::vector<TestCase> matchedTestCases;
jamie@264 4709 getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
jamie@264 4710 for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
jamie@264 4711 it != itEnd;
jamie@264 4712 ++it ) {
jamie@264 4713 for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
jamie@264 4714 tagItEnd = it->getTestCaseInfo().tags.end();
jamie@264 4715 tagIt != tagItEnd;
jamie@264 4716 ++tagIt ) {
jamie@264 4717 std::string tagName = *tagIt;
jamie@264 4718 std::string lcaseTagName = toLower( tagName );
jamie@264 4719 std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
jamie@264 4720 if( countIt == tagCounts.end() )
jamie@264 4721 countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
jamie@264 4722 countIt->second.add( tagName );
jamie@264 4723 }
jamie@264 4724 }
jamie@264 4725
jamie@264 4726 for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
jamie@264 4727 countItEnd = tagCounts.end();
jamie@264 4728 countIt != countItEnd;
jamie@264 4729 ++countIt ) {
jamie@264 4730 std::ostringstream oss;
jamie@264 4731 oss << " " << std::setw(2) << countIt->second.count << " ";
jamie@264 4732 Text wrapper( countIt->second.all(), TextAttributes()
jamie@264 4733 .setInitialIndent( 0 )
jamie@264 4734 .setIndent( oss.str().size() )
jamie@264 4735 .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
jamie@264 4736 std::cout << oss.str() << wrapper << "\n";
jamie@264 4737 }
jamie@264 4738 std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
jamie@264 4739 return tagCounts.size();
jamie@264 4740 }
jamie@264 4741
jamie@264 4742 inline std::size_t listReporters( Config const& /*config*/ ) {
jamie@264 4743 std::cout << "Available reports:\n";
jamie@264 4744 IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
jamie@264 4745 IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
jamie@264 4746 std::size_t maxNameLen = 0;
jamie@264 4747 for(it = itBegin; it != itEnd; ++it )
jamie@264 4748 maxNameLen = (std::max)( maxNameLen, it->first.size() );
jamie@264 4749
jamie@264 4750 for(it = itBegin; it != itEnd; ++it ) {
jamie@264 4751 Text wrapper( it->second->getDescription(), TextAttributes()
jamie@264 4752 .setInitialIndent( 0 )
jamie@264 4753 .setIndent( 7+maxNameLen )
jamie@264 4754 .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
jamie@264 4755 std::cout << " "
jamie@264 4756 << it->first
jamie@264 4757 << ":"
jamie@264 4758 << std::string( maxNameLen - it->first.size() + 2, ' ' )
jamie@264 4759 << wrapper << "\n";
jamie@264 4760 }
jamie@264 4761 std::cout << std::endl;
jamie@264 4762 return factories.size();
jamie@264 4763 }
jamie@264 4764
jamie@264 4765 inline Option<std::size_t> list( Config const& config ) {
jamie@264 4766 Option<std::size_t> listedCount;
jamie@264 4767 if( config.listTests() )
jamie@264 4768 listedCount = listedCount.valueOr(0) + listTests( config );
jamie@264 4769 if( config.listTestNamesOnly() )
jamie@264 4770 listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
jamie@264 4771 if( config.listTags() )
jamie@264 4772 listedCount = listedCount.valueOr(0) + listTags( config );
jamie@264 4773 if( config.listReporters() )
jamie@264 4774 listedCount = listedCount.valueOr(0) + listReporters( config );
jamie@264 4775 return listedCount;
jamie@264 4776 }
jamie@264 4777
jamie@264 4778 } // end namespace Catch
jamie@264 4779
jamie@264 4780 // #included from: internal/catch_runner_impl.hpp
jamie@264 4781 #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
jamie@264 4782
jamie@264 4783 // #included from: catch_test_case_tracker.hpp
jamie@264 4784 #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
jamie@264 4785
jamie@264 4786 #include <map>
jamie@264 4787 #include <string>
jamie@264 4788 #include <assert.h>
jamie@264 4789
jamie@264 4790 namespace Catch {
jamie@264 4791 namespace SectionTracking {
jamie@264 4792
jamie@264 4793 class TrackedSection {
jamie@264 4794
jamie@264 4795 typedef std::map<std::string, TrackedSection> TrackedSections;
jamie@264 4796
jamie@264 4797 public:
jamie@264 4798 enum RunState {
jamie@264 4799 NotStarted,
jamie@264 4800 Executing,
jamie@264 4801 ExecutingChildren,
jamie@264 4802 Completed
jamie@264 4803 };
jamie@264 4804
jamie@264 4805 TrackedSection( std::string const& name, TrackedSection* parent )
jamie@264 4806 : m_name( name ), m_runState( NotStarted ), m_parent( parent )
jamie@264 4807 {}
jamie@264 4808
jamie@264 4809 RunState runState() const { return m_runState; }
jamie@264 4810
jamie@264 4811 TrackedSection* findChild( std::string const& childName ) {
jamie@264 4812 TrackedSections::iterator it = m_children.find( childName );
jamie@264 4813 return it != m_children.end()
jamie@264 4814 ? &it->second
jamie@264 4815 : NULL;
jamie@264 4816 }
jamie@264 4817 TrackedSection* acquireChild( std::string const& childName ) {
jamie@264 4818 if( TrackedSection* child = findChild( childName ) )
jamie@264 4819 return child;
jamie@264 4820 m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) );
jamie@264 4821 return findChild( childName );
jamie@264 4822 }
jamie@264 4823 void enter() {
jamie@264 4824 if( m_runState == NotStarted )
jamie@264 4825 m_runState = Executing;
jamie@264 4826 }
jamie@264 4827 void leave() {
jamie@264 4828 for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end();
jamie@264 4829 it != itEnd;
jamie@264 4830 ++it )
jamie@264 4831 if( it->second.runState() != Completed ) {
jamie@264 4832 m_runState = ExecutingChildren;
jamie@264 4833 return;
jamie@264 4834 }
jamie@264 4835 m_runState = Completed;
jamie@264 4836 }
jamie@264 4837 TrackedSection* getParent() {
jamie@264 4838 return m_parent;
jamie@264 4839 }
jamie@264 4840 bool hasChildren() const {
jamie@264 4841 return !m_children.empty();
jamie@264 4842 }
jamie@264 4843
jamie@264 4844 private:
jamie@264 4845 std::string m_name;
jamie@264 4846 RunState m_runState;
jamie@264 4847 TrackedSections m_children;
jamie@264 4848 TrackedSection* m_parent;
jamie@264 4849
jamie@264 4850 };
jamie@264 4851
jamie@264 4852 class TestCaseTracker {
jamie@264 4853 public:
jamie@264 4854 TestCaseTracker( std::string const& testCaseName )
jamie@264 4855 : m_testCase( testCaseName, NULL ),
jamie@264 4856 m_currentSection( &m_testCase ),
jamie@264 4857 m_completedASectionThisRun( false )
jamie@264 4858 {}
jamie@264 4859
jamie@264 4860 bool enterSection( std::string const& name ) {
jamie@264 4861 TrackedSection* child = m_currentSection->acquireChild( name );
jamie@264 4862 if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed )
jamie@264 4863 return false;
jamie@264 4864
jamie@264 4865 m_currentSection = child;
jamie@264 4866 m_currentSection->enter();
jamie@264 4867 return true;
jamie@264 4868 }
jamie@264 4869 void leaveSection() {
jamie@264 4870 m_currentSection->leave();
jamie@264 4871 m_currentSection = m_currentSection->getParent();
jamie@264 4872 assert( m_currentSection != NULL );
jamie@264 4873 m_completedASectionThisRun = true;
jamie@264 4874 }
jamie@264 4875
jamie@264 4876 bool currentSectionHasChildren() const {
jamie@264 4877 return m_currentSection->hasChildren();
jamie@264 4878 }
jamie@264 4879 bool isCompleted() const {
jamie@264 4880 return m_testCase.runState() == TrackedSection::Completed;
jamie@264 4881 }
jamie@264 4882
jamie@264 4883 class Guard {
jamie@264 4884 public:
jamie@264 4885 Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) {
jamie@264 4886 m_tracker.enterTestCase();
jamie@264 4887 }
jamie@264 4888 ~Guard() {
jamie@264 4889 m_tracker.leaveTestCase();
jamie@264 4890 }
jamie@264 4891 private:
jamie@264 4892 Guard( Guard const& );
jamie@264 4893 void operator = ( Guard const& );
jamie@264 4894 TestCaseTracker& m_tracker;
jamie@264 4895 };
jamie@264 4896
jamie@264 4897 private:
jamie@264 4898 void enterTestCase() {
jamie@264 4899 m_currentSection = &m_testCase;
jamie@264 4900 m_completedASectionThisRun = false;
jamie@264 4901 m_testCase.enter();
jamie@264 4902 }
jamie@264 4903 void leaveTestCase() {
jamie@264 4904 m_testCase.leave();
jamie@264 4905 }
jamie@264 4906
jamie@264 4907 TrackedSection m_testCase;
jamie@264 4908 TrackedSection* m_currentSection;
jamie@264 4909 bool m_completedASectionThisRun;
jamie@264 4910 };
jamie@264 4911
jamie@264 4912 } // namespace SectionTracking
jamie@264 4913
jamie@264 4914 using SectionTracking::TestCaseTracker;
jamie@264 4915
jamie@264 4916 } // namespace Catch
jamie@264 4917
jamie@264 4918 #include <set>
jamie@264 4919 #include <string>
jamie@264 4920
jamie@264 4921 namespace Catch {
jamie@264 4922
jamie@264 4923 class StreamRedirect {
jamie@264 4924
jamie@264 4925 public:
jamie@264 4926 StreamRedirect( std::ostream& stream, std::string& targetString )
jamie@264 4927 : m_stream( stream ),
jamie@264 4928 m_prevBuf( stream.rdbuf() ),
jamie@264 4929 m_targetString( targetString )
jamie@264 4930 {
jamie@264 4931 stream.rdbuf( m_oss.rdbuf() );
jamie@264 4932 }
jamie@264 4933
jamie@264 4934 ~StreamRedirect() {
jamie@264 4935 m_targetString += m_oss.str();
jamie@264 4936 m_stream.rdbuf( m_prevBuf );
jamie@264 4937 }
jamie@264 4938
jamie@264 4939 private:
jamie@264 4940 std::ostream& m_stream;
jamie@264 4941 std::streambuf* m_prevBuf;
jamie@264 4942 std::ostringstream m_oss;
jamie@264 4943 std::string& m_targetString;
jamie@264 4944 };
jamie@264 4945
jamie@264 4946 ///////////////////////////////////////////////////////////////////////////
jamie@264 4947
jamie@264 4948 class RunContext : public IResultCapture, public IRunner {
jamie@264 4949
jamie@264 4950 RunContext( RunContext const& );
jamie@264 4951 void operator =( RunContext const& );
jamie@264 4952
jamie@264 4953 public:
jamie@264 4954
jamie@264 4955 explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter )
jamie@264 4956 : m_runInfo( config->name() ),
jamie@264 4957 m_context( getCurrentMutableContext() ),
jamie@264 4958 m_activeTestCase( NULL ),
jamie@264 4959 m_config( config ),
jamie@264 4960 m_reporter( reporter ),
jamie@264 4961 m_prevRunner( m_context.getRunner() ),
jamie@264 4962 m_prevResultCapture( m_context.getResultCapture() ),
jamie@264 4963 m_prevConfig( m_context.getConfig() )
jamie@264 4964 {
jamie@264 4965 m_context.setRunner( this );
jamie@264 4966 m_context.setConfig( m_config );
jamie@264 4967 m_context.setResultCapture( this );
jamie@264 4968 m_reporter->testRunStarting( m_runInfo );
jamie@264 4969 }
jamie@264 4970
jamie@264 4971 virtual ~RunContext() {
jamie@264 4972 m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
jamie@264 4973 m_context.setRunner( m_prevRunner );
jamie@264 4974 m_context.setConfig( NULL );
jamie@264 4975 m_context.setResultCapture( m_prevResultCapture );
jamie@264 4976 m_context.setConfig( m_prevConfig );
jamie@264 4977 }
jamie@264 4978
jamie@264 4979 void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
jamie@264 4980 m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
jamie@264 4981 }
jamie@264 4982 void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
jamie@264 4983 m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
jamie@264 4984 }
jamie@264 4985
jamie@264 4986 Totals runTest( TestCase const& testCase ) {
jamie@264 4987 Totals prevTotals = m_totals;
jamie@264 4988
jamie@264 4989 std::string redirectedCout;
jamie@264 4990 std::string redirectedCerr;
jamie@264 4991
jamie@264 4992 TestCaseInfo testInfo = testCase.getTestCaseInfo();
jamie@264 4993
jamie@264 4994 m_reporter->testCaseStarting( testInfo );
jamie@264 4995
jamie@264 4996 m_activeTestCase = &testCase;
jamie@264 4997 m_testCaseTracker = TestCaseTracker( testInfo.name );
jamie@264 4998
jamie@264 4999 do {
jamie@264 5000 do {
jamie@264 5001 runCurrentTest( redirectedCout, redirectedCerr );
jamie@264 5002 }
jamie@264 5003 while( !m_testCaseTracker->isCompleted() && !aborting() );
jamie@264 5004 }
jamie@264 5005 while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
jamie@264 5006
jamie@264 5007 Totals deltaTotals = m_totals.delta( prevTotals );
jamie@264 5008 m_totals.testCases += deltaTotals.testCases;
jamie@264 5009 m_reporter->testCaseEnded( TestCaseStats( testInfo,
jamie@264 5010 deltaTotals,
jamie@264 5011 redirectedCout,
jamie@264 5012 redirectedCerr,
jamie@264 5013 aborting() ) );
jamie@264 5014
jamie@264 5015 m_activeTestCase = NULL;
jamie@264 5016 m_testCaseTracker.reset();
jamie@264 5017
jamie@264 5018 return deltaTotals;
jamie@264 5019 }
jamie@264 5020
jamie@264 5021 Ptr<IConfig const> config() const {
jamie@264 5022 return m_config;
jamie@264 5023 }
jamie@264 5024
jamie@264 5025 private: // IResultCapture
jamie@264 5026
jamie@264 5027 virtual void assertionEnded( AssertionResult const& result ) {
jamie@264 5028 if( result.getResultType() == ResultWas::Ok ) {
jamie@264 5029 m_totals.assertions.passed++;
jamie@264 5030 }
jamie@264 5031 else if( !result.isOk() ) {
jamie@264 5032 m_totals.assertions.failed++;
jamie@264 5033 }
jamie@264 5034
jamie@264 5035 if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
jamie@264 5036 m_messages.clear();
jamie@264 5037
jamie@264 5038 // Reset working state
jamie@264 5039 m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
jamie@264 5040 m_lastResult = result;
jamie@264 5041 }
jamie@264 5042
jamie@264 5043 virtual bool sectionStarted (
jamie@264 5044 SectionInfo const& sectionInfo,
jamie@264 5045 Counts& assertions
jamie@264 5046 )
jamie@264 5047 {
jamie@264 5048 std::ostringstream oss;
jamie@264 5049 oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
jamie@264 5050
jamie@264 5051 if( !m_testCaseTracker->enterSection( oss.str() ) )
jamie@264 5052 return false;
jamie@264 5053
jamie@264 5054 m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
jamie@264 5055
jamie@264 5056 m_reporter->sectionStarting( sectionInfo );
jamie@264 5057
jamie@264 5058 assertions = m_totals.assertions;
jamie@264 5059
jamie@264 5060 return true;
jamie@264 5061 }
jamie@264 5062 bool testForMissingAssertions( Counts& assertions ) {
jamie@264 5063 if( assertions.total() != 0 ||
jamie@264 5064 !m_config->warnAboutMissingAssertions() ||
jamie@264 5065 m_testCaseTracker->currentSectionHasChildren() )
jamie@264 5066 return false;
jamie@264 5067 m_totals.assertions.failed++;
jamie@264 5068 assertions.failed++;
jamie@264 5069 return true;
jamie@264 5070 }
jamie@264 5071
jamie@264 5072 virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
jamie@264 5073 if( std::uncaught_exception() ) {
jamie@264 5074 m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
jamie@264 5075 return;
jamie@264 5076 }
jamie@264 5077
jamie@264 5078 Counts assertions = m_totals.assertions - prevAssertions;
jamie@264 5079 bool missingAssertions = testForMissingAssertions( assertions );
jamie@264 5080
jamie@264 5081 m_testCaseTracker->leaveSection();
jamie@264 5082
jamie@264 5083 m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
jamie@264 5084 m_messages.clear();
jamie@264 5085 }
jamie@264 5086
jamie@264 5087 virtual void pushScopedMessage( MessageInfo const& message ) {
jamie@264 5088 m_messages.push_back( message );
jamie@264 5089 }
jamie@264 5090
jamie@264 5091 virtual void popScopedMessage( MessageInfo const& message ) {
jamie@264 5092 m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
jamie@264 5093 }
jamie@264 5094
jamie@264 5095 virtual std::string getCurrentTestName() const {
jamie@264 5096 return m_activeTestCase
jamie@264 5097 ? m_activeTestCase->getTestCaseInfo().name
jamie@264 5098 : "";
jamie@264 5099 }
jamie@264 5100
jamie@264 5101 virtual const AssertionResult* getLastResult() const {
jamie@264 5102 return &m_lastResult;
jamie@264 5103 }
jamie@264 5104
jamie@264 5105 public:
jamie@264 5106 // !TBD We need to do this another way!
jamie@264 5107 bool aborting() const {
jamie@264 5108 return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
jamie@264 5109 }
jamie@264 5110
jamie@264 5111 private:
jamie@264 5112
jamie@264 5113 void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
jamie@264 5114 TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
jamie@264 5115 SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
jamie@264 5116 m_reporter->sectionStarting( testCaseSection );
jamie@264 5117 Counts prevAssertions = m_totals.assertions;
jamie@264 5118 double duration = 0;
jamie@264 5119 try {
jamie@264 5120 m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
jamie@264 5121 TestCaseTracker::Guard guard( *m_testCaseTracker );
jamie@264 5122
jamie@264 5123 Timer timer;
jamie@264 5124 timer.start();
jamie@264 5125 if( m_reporter->getPreferences().shouldRedirectStdOut ) {
jamie@264 5126 StreamRedirect coutRedir( std::cout, redirectedCout );
jamie@264 5127 StreamRedirect cerrRedir( std::cerr, redirectedCerr );
jamie@264 5128 m_activeTestCase->invoke();
jamie@264 5129 }
jamie@264 5130 else {
jamie@264 5131 m_activeTestCase->invoke();
jamie@264 5132 }
jamie@264 5133 duration = timer.getElapsedSeconds();
jamie@264 5134 }
jamie@264 5135 catch( TestFailureException& ) {
jamie@264 5136 // This just means the test was aborted due to failure
jamie@264 5137 }
jamie@264 5138 catch(...) {
jamie@264 5139 ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(),
jamie@264 5140 m_lastAssertionInfo.lineInfo,
jamie@264 5141 m_lastAssertionInfo.capturedExpression.c_str(),
jamie@264 5142 m_lastAssertionInfo.resultDisposition );
jamie@264 5143 exResult.useActiveException();
jamie@264 5144 }
jamie@264 5145 // If sections ended prematurely due to an exception we stored their
jamie@264 5146 // infos here so we can tear them down outside the unwind process.
jamie@264 5147 for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
jamie@264 5148 itEnd = m_unfinishedSections.rend();
jamie@264 5149 it != itEnd;
jamie@264 5150 ++it )
jamie@264 5151 sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
jamie@264 5152 m_unfinishedSections.clear();
jamie@264 5153 m_messages.clear();
jamie@264 5154
jamie@264 5155 Counts assertions = m_totals.assertions - prevAssertions;
jamie@264 5156 bool missingAssertions = testForMissingAssertions( assertions );
jamie@264 5157
jamie@264 5158 if( testCaseInfo.okToFail() ) {
jamie@264 5159 std::swap( assertions.failedButOk, assertions.failed );
jamie@264 5160 m_totals.assertions.failed -= assertions.failedButOk;
jamie@264 5161 m_totals.assertions.failedButOk += assertions.failedButOk;
jamie@264 5162 }
jamie@264 5163
jamie@264 5164 SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
jamie@264 5165 m_reporter->sectionEnded( testCaseSectionStats );
jamie@264 5166 }
jamie@264 5167
jamie@264 5168 private:
jamie@264 5169 struct UnfinishedSections {
jamie@264 5170 UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
jamie@264 5171 : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
jamie@264 5172 {}
jamie@264 5173
jamie@264 5174 SectionInfo info;
jamie@264 5175 Counts prevAssertions;
jamie@264 5176 double durationInSeconds;
jamie@264 5177 };
jamie@264 5178
jamie@264 5179 TestRunInfo m_runInfo;
jamie@264 5180 IMutableContext& m_context;
jamie@264 5181 TestCase const* m_activeTestCase;
jamie@264 5182 Option<TestCaseTracker> m_testCaseTracker;
jamie@264 5183 AssertionResult m_lastResult;
jamie@264 5184
jamie@264 5185 Ptr<IConfig const> m_config;
jamie@264 5186 Totals m_totals;
jamie@264 5187 Ptr<IStreamingReporter> m_reporter;
jamie@264 5188 std::vector<MessageInfo> m_messages;
jamie@264 5189 IRunner* m_prevRunner;
jamie@264 5190 IResultCapture* m_prevResultCapture;
jamie@264 5191 Ptr<IConfig const> m_prevConfig;
jamie@264 5192 AssertionInfo m_lastAssertionInfo;
jamie@264 5193 std::vector<UnfinishedSections> m_unfinishedSections;
jamie@264 5194 };
jamie@264 5195
jamie@264 5196 IResultCapture& getResultCapture() {
jamie@264 5197 if( IResultCapture* capture = getCurrentContext().getResultCapture() )
jamie@264 5198 return *capture;
jamie@264 5199 else
jamie@264 5200 throw std::logic_error( "No result capture instance" );
jamie@264 5201 }
jamie@264 5202
jamie@264 5203 } // end namespace Catch
jamie@264 5204
jamie@264 5205 // #included from: internal/catch_version.h
jamie@264 5206 #define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
jamie@264 5207
jamie@264 5208 namespace Catch {
jamie@264 5209
jamie@264 5210 // Versioning information
jamie@264 5211 struct Version {
jamie@264 5212 Version( unsigned int _majorVersion,
jamie@264 5213 unsigned int _minorVersion,
jamie@264 5214 unsigned int _buildNumber,
jamie@264 5215 char const* const _branchName )
jamie@264 5216 : majorVersion( _majorVersion ),
jamie@264 5217 minorVersion( _minorVersion ),
jamie@264 5218 buildNumber( _buildNumber ),
jamie@264 5219 branchName( _branchName )
jamie@264 5220 {}
jamie@264 5221
jamie@264 5222 unsigned int const majorVersion;
jamie@264 5223 unsigned int const minorVersion;
jamie@264 5224 unsigned int const buildNumber;
jamie@264 5225 char const* const branchName;
jamie@264 5226
jamie@264 5227 private:
jamie@264 5228 void operator=( Version const& );
jamie@264 5229 };
jamie@264 5230
jamie@264 5231 extern Version libraryVersion;
jamie@264 5232 }
jamie@264 5233
jamie@264 5234 #include <fstream>
jamie@264 5235 #include <stdlib.h>
jamie@264 5236 #include <limits>
jamie@264 5237
jamie@264 5238 namespace Catch {
jamie@264 5239
jamie@264 5240 class Runner {
jamie@264 5241
jamie@264 5242 public:
jamie@264 5243 Runner( Ptr<Config> const& config )
jamie@264 5244 : m_config( config )
jamie@264 5245 {
jamie@264 5246 openStream();
jamie@264 5247 makeReporter();
jamie@264 5248 }
jamie@264 5249
jamie@264 5250 Totals runTests() {
jamie@264 5251
jamie@264 5252 RunContext context( m_config.get(), m_reporter );
jamie@264 5253
jamie@264 5254 Totals totals;
jamie@264 5255
jamie@264 5256 context.testGroupStarting( "", 1, 1 ); // deprecated?
jamie@264 5257
jamie@264 5258 TestSpec testSpec = m_config->testSpec();
jamie@264 5259 if( !testSpec.hasFilters() )
jamie@264 5260 testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
jamie@264 5261
jamie@264 5262 std::vector<TestCase> testCases;
jamie@264 5263 getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
jamie@264 5264
jamie@264 5265 int testsRunForGroup = 0;
jamie@264 5266 for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
jamie@264 5267 it != itEnd;
jamie@264 5268 ++it ) {
jamie@264 5269 testsRunForGroup++;
jamie@264 5270 if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
jamie@264 5271
jamie@264 5272 if( context.aborting() )
jamie@264 5273 break;
jamie@264 5274
jamie@264 5275 totals += context.runTest( *it );
jamie@264 5276 m_testsAlreadyRun.insert( *it );
jamie@264 5277 }
jamie@264 5278 }
jamie@264 5279 context.testGroupEnded( "", totals, 1, 1 );
jamie@264 5280 return totals;
jamie@264 5281 }
jamie@264 5282
jamie@264 5283 private:
jamie@264 5284 void openStream() {
jamie@264 5285 // Open output file, if specified
jamie@264 5286 if( !m_config->getFilename().empty() ) {
jamie@264 5287 m_ofs.open( m_config->getFilename().c_str() );
jamie@264 5288 if( m_ofs.fail() ) {
jamie@264 5289 std::ostringstream oss;
jamie@264 5290 oss << "Unable to open file: '" << m_config->getFilename() << "'";
jamie@264 5291 throw std::domain_error( oss.str() );
jamie@264 5292 }
jamie@264 5293 m_config->setStreamBuf( m_ofs.rdbuf() );
jamie@264 5294 }
jamie@264 5295 }
jamie@264 5296 void makeReporter() {
jamie@264 5297 std::string reporterName = m_config->getReporterName().empty()
jamie@264 5298 ? "console"
jamie@264 5299 : m_config->getReporterName();
jamie@264 5300
jamie@264 5301 m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
jamie@264 5302 if( !m_reporter ) {
jamie@264 5303 std::ostringstream oss;
jamie@264 5304 oss << "No reporter registered with name: '" << reporterName << "'";
jamie@264 5305 throw std::domain_error( oss.str() );
jamie@264 5306 }
jamie@264 5307 }
jamie@264 5308
jamie@264 5309 private:
jamie@264 5310 Ptr<Config> m_config;
jamie@264 5311 std::ofstream m_ofs;
jamie@264 5312 Ptr<IStreamingReporter> m_reporter;
jamie@264 5313 std::set<TestCase> m_testsAlreadyRun;
jamie@264 5314 };
jamie@264 5315
jamie@264 5316 class Session {
jamie@264 5317 static bool alreadyInstantiated;
jamie@264 5318
jamie@264 5319 public:
jamie@264 5320
jamie@264 5321 struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
jamie@264 5322
jamie@264 5323 Session()
jamie@264 5324 : m_cli( makeCommandLineParser() ) {
jamie@264 5325 if( alreadyInstantiated ) {
jamie@264 5326 std::string msg = "Only one instance of Catch::Session can ever be used";
jamie@264 5327 std::cerr << msg << std::endl;
jamie@264 5328 throw std::logic_error( msg );
jamie@264 5329 }
jamie@264 5330 alreadyInstantiated = true;
jamie@264 5331 }
jamie@264 5332 ~Session() {
jamie@264 5333 Catch::cleanUp();
jamie@264 5334 }
jamie@264 5335
jamie@264 5336 void showHelp( std::string const& processName ) {
jamie@264 5337 std::cout << "\nCatch v" << libraryVersion.majorVersion << "."
jamie@264 5338 << libraryVersion.minorVersion << " build "
jamie@264 5339 << libraryVersion.buildNumber;
jamie@264 5340 if( libraryVersion.branchName != std::string( "master" ) )
jamie@264 5341 std::cout << " (" << libraryVersion.branchName << " branch)";
jamie@264 5342 std::cout << "\n";
jamie@264 5343
jamie@264 5344 m_cli.usage( std::cout, processName );
jamie@264 5345 std::cout << "For more detail usage please see the project docs\n" << std::endl;
jamie@264 5346 }
jamie@264 5347
jamie@264 5348 int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
jamie@264 5349 try {
jamie@264 5350 m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
jamie@264 5351 m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
jamie@264 5352 if( m_configData.showHelp )
jamie@264 5353 showHelp( m_configData.processName );
jamie@264 5354 m_config.reset();
jamie@264 5355 }
jamie@264 5356 catch( std::exception& ex ) {
jamie@264 5357 {
jamie@264 5358 Colour colourGuard( Colour::Red );
jamie@264 5359 std::cerr << "\nError(s) in input:\n"
jamie@264 5360 << Text( ex.what(), TextAttributes().setIndent(2) )
jamie@264 5361 << "\n\n";
jamie@264 5362 }
jamie@264 5363 m_cli.usage( std::cout, m_configData.processName );
jamie@264 5364 return (std::numeric_limits<int>::max)();
jamie@264 5365 }
jamie@264 5366 return 0;
jamie@264 5367 }
jamie@264 5368
jamie@264 5369 void useConfigData( ConfigData const& _configData ) {
jamie@264 5370 m_configData = _configData;
jamie@264 5371 m_config.reset();
jamie@264 5372 }
jamie@264 5373
jamie@264 5374 int run( int argc, char* const argv[] ) {
jamie@264 5375
jamie@264 5376 int returnCode = applyCommandLine( argc, argv );
jamie@264 5377 if( returnCode == 0 )
jamie@264 5378 returnCode = run();
jamie@264 5379 return returnCode;
jamie@264 5380 }
jamie@264 5381
jamie@264 5382 int run() {
jamie@264 5383 if( m_configData.showHelp )
jamie@264 5384 return 0;
jamie@264 5385
jamie@264 5386 try
jamie@264 5387 {
jamie@264 5388 config(); // Force config to be constructed
jamie@264 5389 Runner runner( m_config );
jamie@264 5390
jamie@264 5391 // Handle list request
jamie@264 5392 if( Option<std::size_t> listed = list( config() ) )
jamie@264 5393 return static_cast<int>( *listed );
jamie@264 5394
jamie@264 5395 return static_cast<int>( runner.runTests().assertions.failed );
jamie@264 5396 }
jamie@264 5397 catch( std::exception& ex ) {
jamie@264 5398 std::cerr << ex.what() << std::endl;
jamie@264 5399 return (std::numeric_limits<int>::max)();
jamie@264 5400 }
jamie@264 5401 }
jamie@264 5402
jamie@264 5403 Clara::CommandLine<ConfigData> const& cli() const {
jamie@264 5404 return m_cli;
jamie@264 5405 }
jamie@264 5406 std::vector<Clara::Parser::Token> const& unusedTokens() const {
jamie@264 5407 return m_unusedTokens;
jamie@264 5408 }
jamie@264 5409 ConfigData& configData() {
jamie@264 5410 return m_configData;
jamie@264 5411 }
jamie@264 5412 Config& config() {
jamie@264 5413 if( !m_config )
jamie@264 5414 m_config = new Config( m_configData );
jamie@264 5415 return *m_config;
jamie@264 5416 }
jamie@264 5417
jamie@264 5418 private:
jamie@264 5419 Clara::CommandLine<ConfigData> m_cli;
jamie@264 5420 std::vector<Clara::Parser::Token> m_unusedTokens;
jamie@264 5421 ConfigData m_configData;
jamie@264 5422 Ptr<Config> m_config;
jamie@264 5423 };
jamie@264 5424
jamie@264 5425 bool Session::alreadyInstantiated = false;
jamie@264 5426
jamie@264 5427 } // end namespace Catch
jamie@264 5428
jamie@264 5429 // #included from: catch_registry_hub.hpp
jamie@264 5430 #define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
jamie@264 5431
jamie@264 5432 // #included from: catch_test_case_registry_impl.hpp
jamie@264 5433 #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
jamie@264 5434
jamie@264 5435 #include <vector>
jamie@264 5436 #include <set>
jamie@264 5437 #include <sstream>
jamie@264 5438 #include <iostream>
jamie@264 5439
jamie@264 5440 namespace Catch {
jamie@264 5441
jamie@264 5442 class TestRegistry : public ITestCaseRegistry {
jamie@264 5443 public:
jamie@264 5444 TestRegistry() : m_unnamedCount( 0 ) {}
jamie@264 5445 virtual ~TestRegistry();
jamie@264 5446
jamie@264 5447 virtual void registerTest( TestCase const& testCase ) {
jamie@264 5448 std::string name = testCase.getTestCaseInfo().name;
jamie@264 5449 if( name == "" ) {
jamie@264 5450 std::ostringstream oss;
jamie@264 5451 oss << "Anonymous test case " << ++m_unnamedCount;
jamie@264 5452 return registerTest( testCase.withName( oss.str() ) );
jamie@264 5453 }
jamie@264 5454
jamie@264 5455 if( m_functions.find( testCase ) == m_functions.end() ) {
jamie@264 5456 m_functions.insert( testCase );
jamie@264 5457 m_functionsInOrder.push_back( testCase );
jamie@264 5458 if( !testCase.isHidden() )
jamie@264 5459 m_nonHiddenFunctions.push_back( testCase );
jamie@264 5460 }
jamie@264 5461 else {
jamie@264 5462 TestCase const& prev = *m_functions.find( testCase );
jamie@264 5463 {
jamie@264 5464 Colour colourGuard( Colour::Red );
jamie@264 5465 std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
jamie@264 5466 << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
jamie@264 5467 << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
jamie@264 5468 }
jamie@264 5469 exit(1);
jamie@264 5470 }
jamie@264 5471 }
jamie@264 5472
jamie@264 5473 virtual std::vector<TestCase> const& getAllTests() const {
jamie@264 5474 return m_functionsInOrder;
jamie@264 5475 }
jamie@264 5476
jamie@264 5477 virtual std::vector<TestCase> const& getAllNonHiddenTests() const {
jamie@264 5478 return m_nonHiddenFunctions;
jamie@264 5479 }
jamie@264 5480
jamie@264 5481 virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const {
jamie@264 5482 for( std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(),
jamie@264 5483 itEnd = m_functionsInOrder.end();
jamie@264 5484 it != itEnd;
jamie@264 5485 ++it ) {
jamie@264 5486 if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) )
jamie@264 5487 matchingTestCases.push_back( *it );
jamie@264 5488 }
jamie@264 5489 }
jamie@264 5490
jamie@264 5491 private:
jamie@264 5492
jamie@264 5493 std::set<TestCase> m_functions;
jamie@264 5494 std::vector<TestCase> m_functionsInOrder;
jamie@264 5495 std::vector<TestCase> m_nonHiddenFunctions;
jamie@264 5496 size_t m_unnamedCount;
jamie@264 5497 };
jamie@264 5498
jamie@264 5499 ///////////////////////////////////////////////////////////////////////////
jamie@264 5500
jamie@264 5501 class FreeFunctionTestCase : public SharedImpl<ITestCase> {
jamie@264 5502 public:
jamie@264 5503
jamie@264 5504 FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
jamie@264 5505
jamie@264 5506 virtual void invoke() const {
jamie@264 5507 m_fun();
jamie@264 5508 }
jamie@264 5509
jamie@264 5510 private:
jamie@264 5511 virtual ~FreeFunctionTestCase();
jamie@264 5512
jamie@264 5513 TestFunction m_fun;
jamie@264 5514 };
jamie@264 5515
jamie@264 5516 inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
jamie@264 5517 std::string className = classOrQualifiedMethodName;
jamie@264 5518 if( startsWith( className, "&" ) )
jamie@264 5519 {
jamie@264 5520 std::size_t lastColons = className.rfind( "::" );
jamie@264 5521 std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
jamie@264 5522 if( penultimateColons == std::string::npos )
jamie@264 5523 penultimateColons = 1;
jamie@264 5524 className = className.substr( penultimateColons, lastColons-penultimateColons );
jamie@264 5525 }
jamie@264 5526 return className;
jamie@264 5527 }
jamie@264 5528
jamie@264 5529 ///////////////////////////////////////////////////////////////////////////
jamie@264 5530
jamie@264 5531 AutoReg::AutoReg( TestFunction function,
jamie@264 5532 SourceLineInfo const& lineInfo,
jamie@264 5533 NameAndDesc const& nameAndDesc ) {
jamie@264 5534 registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
jamie@264 5535 }
jamie@264 5536
jamie@264 5537 AutoReg::~AutoReg() {}
jamie@264 5538
jamie@264 5539 void AutoReg::registerTestCase( ITestCase* testCase,
jamie@264 5540 char const* classOrQualifiedMethodName,
jamie@264 5541 NameAndDesc const& nameAndDesc,
jamie@264 5542 SourceLineInfo const& lineInfo ) {
jamie@264 5543
jamie@264 5544 getMutableRegistryHub().registerTest
jamie@264 5545 ( makeTestCase( testCase,
jamie@264 5546 extractClassName( classOrQualifiedMethodName ),
jamie@264 5547 nameAndDesc.name,
jamie@264 5548 nameAndDesc.description,
jamie@264 5549 lineInfo ) );
jamie@264 5550 }
jamie@264 5551
jamie@264 5552 } // end namespace Catch
jamie@264 5553
jamie@264 5554 // #included from: catch_reporter_registry.hpp
jamie@264 5555 #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
jamie@264 5556
jamie@264 5557 #include <map>
jamie@264 5558
jamie@264 5559 namespace Catch {
jamie@264 5560
jamie@264 5561 class ReporterRegistry : public IReporterRegistry {
jamie@264 5562
jamie@264 5563 public:
jamie@264 5564
jamie@264 5565 virtual ~ReporterRegistry() {
jamie@264 5566 deleteAllValues( m_factories );
jamie@264 5567 }
jamie@264 5568
jamie@264 5569 virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const {
jamie@264 5570 FactoryMap::const_iterator it = m_factories.find( name );
jamie@264 5571 if( it == m_factories.end() )
jamie@264 5572 return NULL;
jamie@264 5573 return it->second->create( ReporterConfig( config ) );
jamie@264 5574 }
jamie@264 5575
jamie@264 5576 void registerReporter( std::string const& name, IReporterFactory* factory ) {
jamie@264 5577 m_factories.insert( std::make_pair( name, factory ) );
jamie@264 5578 }
jamie@264 5579
jamie@264 5580 FactoryMap const& getFactories() const {
jamie@264 5581 return m_factories;
jamie@264 5582 }
jamie@264 5583
jamie@264 5584 private:
jamie@264 5585 FactoryMap m_factories;
jamie@264 5586 };
jamie@264 5587 }
jamie@264 5588
jamie@264 5589 // #included from: catch_exception_translator_registry.hpp
jamie@264 5590 #define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
jamie@264 5591
jamie@264 5592 #ifdef __OBJC__
jamie@264 5593 #import "Foundation/Foundation.h"
jamie@264 5594 #endif
jamie@264 5595
jamie@264 5596 namespace Catch {
jamie@264 5597
jamie@264 5598 class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
jamie@264 5599 public:
jamie@264 5600 ~ExceptionTranslatorRegistry() {
jamie@264 5601 deleteAll( m_translators );
jamie@264 5602 }
jamie@264 5603
jamie@264 5604 virtual void registerTranslator( const IExceptionTranslator* translator ) {
jamie@264 5605 m_translators.push_back( translator );
jamie@264 5606 }
jamie@264 5607
jamie@264 5608 virtual std::string translateActiveException() const {
jamie@264 5609 try {
jamie@264 5610 #ifdef __OBJC__
jamie@264 5611 // In Objective-C try objective-c exceptions first
jamie@264 5612 @try {
jamie@264 5613 throw;
jamie@264 5614 }
jamie@264 5615 @catch (NSException *exception) {
jamie@264 5616 return toString( [exception description] );
jamie@264 5617 }
jamie@264 5618 #else
jamie@264 5619 throw;
jamie@264 5620 #endif
jamie@264 5621 }
jamie@264 5622 catch( TestFailureException& ) {
jamie@264 5623 throw;
jamie@264 5624 }
jamie@264 5625 catch( std::exception& ex ) {
jamie@264 5626 return ex.what();
jamie@264 5627 }
jamie@264 5628 catch( std::string& msg ) {
jamie@264 5629 return msg;
jamie@264 5630 }
jamie@264 5631 catch( const char* msg ) {
jamie@264 5632 return msg;
jamie@264 5633 }
jamie@264 5634 catch(...) {
jamie@264 5635 return tryTranslators( m_translators.begin() );
jamie@264 5636 }
jamie@264 5637 }
jamie@264 5638
jamie@264 5639 std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
jamie@264 5640 if( it == m_translators.end() )
jamie@264 5641 return "Unknown exception";
jamie@264 5642
jamie@264 5643 try {
jamie@264 5644 return (*it)->translate();
jamie@264 5645 }
jamie@264 5646 catch(...) {
jamie@264 5647 return tryTranslators( it+1 );
jamie@264 5648 }
jamie@264 5649 }
jamie@264 5650
jamie@264 5651 private:
jamie@264 5652 std::vector<const IExceptionTranslator*> m_translators;
jamie@264 5653 };
jamie@264 5654 }
jamie@264 5655
jamie@264 5656 namespace Catch {
jamie@264 5657
jamie@264 5658 namespace {
jamie@264 5659
jamie@264 5660 class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
jamie@264 5661
jamie@264 5662 RegistryHub( RegistryHub const& );
jamie@264 5663 void operator=( RegistryHub const& );
jamie@264 5664
jamie@264 5665 public: // IRegistryHub
jamie@264 5666 RegistryHub() {
jamie@264 5667 }
jamie@264 5668 virtual IReporterRegistry const& getReporterRegistry() const {
jamie@264 5669 return m_reporterRegistry;
jamie@264 5670 }
jamie@264 5671 virtual ITestCaseRegistry const& getTestCaseRegistry() const {
jamie@264 5672 return m_testCaseRegistry;
jamie@264 5673 }
jamie@264 5674 virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
jamie@264 5675 return m_exceptionTranslatorRegistry;
jamie@264 5676 }
jamie@264 5677
jamie@264 5678 public: // IMutableRegistryHub
jamie@264 5679 virtual void registerReporter( std::string const& name, IReporterFactory* factory ) {
jamie@264 5680 m_reporterRegistry.registerReporter( name, factory );
jamie@264 5681 }
jamie@264 5682 virtual void registerTest( TestCase const& testInfo ) {
jamie@264 5683 m_testCaseRegistry.registerTest( testInfo );
jamie@264 5684 }
jamie@264 5685 virtual void registerTranslator( const IExceptionTranslator* translator ) {
jamie@264 5686 m_exceptionTranslatorRegistry.registerTranslator( translator );
jamie@264 5687 }
jamie@264 5688
jamie@264 5689 private:
jamie@264 5690 TestRegistry m_testCaseRegistry;
jamie@264 5691 ReporterRegistry m_reporterRegistry;
jamie@264 5692 ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
jamie@264 5693 };
jamie@264 5694
jamie@264 5695 // Single, global, instance
jamie@264 5696 inline RegistryHub*& getTheRegistryHub() {
jamie@264 5697 static RegistryHub* theRegistryHub = NULL;
jamie@264 5698 if( !theRegistryHub )
jamie@264 5699 theRegistryHub = new RegistryHub();
jamie@264 5700 return theRegistryHub;
jamie@264 5701 }
jamie@264 5702 }
jamie@264 5703
jamie@264 5704 IRegistryHub& getRegistryHub() {
jamie@264 5705 return *getTheRegistryHub();
jamie@264 5706 }
jamie@264 5707 IMutableRegistryHub& getMutableRegistryHub() {
jamie@264 5708 return *getTheRegistryHub();
jamie@264 5709 }
jamie@264 5710 void cleanUp() {
jamie@264 5711 delete getTheRegistryHub();
jamie@264 5712 getTheRegistryHub() = NULL;
jamie@264 5713 cleanUpContext();
jamie@264 5714 }
jamie@264 5715 std::string translateActiveException() {
jamie@264 5716 return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
jamie@264 5717 }
jamie@264 5718
jamie@264 5719 } // end namespace Catch
jamie@264 5720
jamie@264 5721 // #included from: catch_notimplemented_exception.hpp
jamie@264 5722 #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
jamie@264 5723
jamie@264 5724 #include <ostream>
jamie@264 5725
jamie@264 5726 namespace Catch {
jamie@264 5727
jamie@264 5728 NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
jamie@264 5729 : m_lineInfo( lineInfo ) {
jamie@264 5730 std::ostringstream oss;
jamie@264 5731 oss << lineInfo << ": function ";
jamie@264 5732 oss << "not implemented";
jamie@264 5733 m_what = oss.str();
jamie@264 5734 }
jamie@264 5735
jamie@264 5736 const char* NotImplementedException::what() const CATCH_NOEXCEPT {
jamie@264 5737 return m_what.c_str();
jamie@264 5738 }
jamie@264 5739
jamie@264 5740 } // end namespace Catch
jamie@264 5741
jamie@264 5742 // #included from: catch_context_impl.hpp
jamie@264 5743 #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
jamie@264 5744
jamie@264 5745 // #included from: catch_stream.hpp
jamie@264 5746 #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
jamie@264 5747
jamie@264 5748 // #included from: catch_streambuf.h
jamie@264 5749 #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
jamie@264 5750
jamie@264 5751 #include <streambuf>
jamie@264 5752
jamie@264 5753 namespace Catch {
jamie@264 5754
jamie@264 5755 class StreamBufBase : public std::streambuf {
jamie@264 5756 public:
jamie@264 5757 virtual ~StreamBufBase() CATCH_NOEXCEPT;
jamie@264 5758 };
jamie@264 5759 }
jamie@264 5760
jamie@264 5761 #include <stdexcept>
jamie@264 5762 #include <cstdio>
jamie@264 5763
jamie@264 5764 namespace Catch {
jamie@264 5765
jamie@264 5766 template<typename WriterF, size_t bufferSize=256>
jamie@264 5767 class StreamBufImpl : public StreamBufBase {
jamie@264 5768 char data[bufferSize];
jamie@264 5769 WriterF m_writer;
jamie@264 5770
jamie@264 5771 public:
jamie@264 5772 StreamBufImpl() {
jamie@264 5773 setp( data, data + sizeof(data) );
jamie@264 5774 }
jamie@264 5775
jamie@264 5776 ~StreamBufImpl() CATCH_NOEXCEPT {
jamie@264 5777 sync();
jamie@264 5778 }
jamie@264 5779
jamie@264 5780 private:
jamie@264 5781 int overflow( int c ) {
jamie@264 5782 sync();
jamie@264 5783
jamie@264 5784 if( c != EOF ) {
jamie@264 5785 if( pbase() == epptr() )
jamie@264 5786 m_writer( std::string( 1, static_cast<char>( c ) ) );
jamie@264 5787 else
jamie@264 5788 sputc( static_cast<char>( c ) );
jamie@264 5789 }
jamie@264 5790 return 0;
jamie@264 5791 }
jamie@264 5792
jamie@264 5793 int sync() {
jamie@264 5794 if( pbase() != pptr() ) {
jamie@264 5795 m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
jamie@264 5796 setp( pbase(), epptr() );
jamie@264 5797 }
jamie@264 5798 return 0;
jamie@264 5799 }
jamie@264 5800 };
jamie@264 5801
jamie@264 5802 ///////////////////////////////////////////////////////////////////////////
jamie@264 5803
jamie@264 5804 struct OutputDebugWriter {
jamie@264 5805
jamie@264 5806 void operator()( std::string const&str ) {
jamie@264 5807 writeToDebugConsole( str );
jamie@264 5808 }
jamie@264 5809 };
jamie@264 5810
jamie@264 5811 Stream::Stream()
jamie@264 5812 : streamBuf( NULL ), isOwned( false )
jamie@264 5813 {}
jamie@264 5814
jamie@264 5815 Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
jamie@264 5816 : streamBuf( _streamBuf ), isOwned( _isOwned )
jamie@264 5817 {}
jamie@264 5818
jamie@264 5819 void Stream::release() {
jamie@264 5820 if( isOwned ) {
jamie@264 5821 delete streamBuf;
jamie@264 5822 streamBuf = NULL;
jamie@264 5823 isOwned = false;
jamie@264 5824 }
jamie@264 5825 }
jamie@264 5826 }
jamie@264 5827
jamie@264 5828 namespace Catch {
jamie@264 5829
jamie@264 5830 class Context : public IMutableContext {
jamie@264 5831
jamie@264 5832 Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {}
jamie@264 5833 Context( Context const& );
jamie@264 5834 void operator=( Context const& );
jamie@264 5835
jamie@264 5836 public: // IContext
jamie@264 5837 virtual IResultCapture* getResultCapture() {
jamie@264 5838 return m_resultCapture;
jamie@264 5839 }
jamie@264 5840 virtual IRunner* getRunner() {
jamie@264 5841 return m_runner;
jamie@264 5842 }
jamie@264 5843 virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
jamie@264 5844 return getGeneratorsForCurrentTest()
jamie@264 5845 .getGeneratorInfo( fileInfo, totalSize )
jamie@264 5846 .getCurrentIndex();
jamie@264 5847 }
jamie@264 5848 virtual bool advanceGeneratorsForCurrentTest() {
jamie@264 5849 IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
jamie@264 5850 return generators && generators->moveNext();
jamie@264 5851 }
jamie@264 5852
jamie@264 5853 virtual Ptr<IConfig const> getConfig() const {
jamie@264 5854 return m_config;
jamie@264 5855 }
jamie@264 5856
jamie@264 5857 public: // IMutableContext
jamie@264 5858 virtual void setResultCapture( IResultCapture* resultCapture ) {
jamie@264 5859 m_resultCapture = resultCapture;
jamie@264 5860 }
jamie@264 5861 virtual void setRunner( IRunner* runner ) {
jamie@264 5862 m_runner = runner;
jamie@264 5863 }
jamie@264 5864 virtual void setConfig( Ptr<IConfig const> const& config ) {
jamie@264 5865 m_config = config;
jamie@264 5866 }
jamie@264 5867
jamie@264 5868 friend IMutableContext& getCurrentMutableContext();
jamie@264 5869
jamie@264 5870 private:
jamie@264 5871 IGeneratorsForTest* findGeneratorsForCurrentTest() {
jamie@264 5872 std::string testName = getResultCapture()->getCurrentTestName();
jamie@264 5873
jamie@264 5874 std::map<std::string, IGeneratorsForTest*>::const_iterator it =
jamie@264 5875 m_generatorsByTestName.find( testName );
jamie@264 5876 return it != m_generatorsByTestName.end()
jamie@264 5877 ? it->second
jamie@264 5878 : NULL;
jamie@264 5879 }
jamie@264 5880
jamie@264 5881 IGeneratorsForTest& getGeneratorsForCurrentTest() {
jamie@264 5882 IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
jamie@264 5883 if( !generators ) {
jamie@264 5884 std::string testName = getResultCapture()->getCurrentTestName();
jamie@264 5885 generators = createGeneratorsForTest();
jamie@264 5886 m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
jamie@264 5887 }
jamie@264 5888 return *generators;
jamie@264 5889 }
jamie@264 5890
jamie@264 5891 private:
jamie@264 5892 Ptr<IConfig const> m_config;
jamie@264 5893 IRunner* m_runner;
jamie@264 5894 IResultCapture* m_resultCapture;
jamie@264 5895 std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
jamie@264 5896 };
jamie@264 5897
jamie@264 5898 namespace {
jamie@264 5899 Context* currentContext = NULL;
jamie@264 5900 }
jamie@264 5901 IMutableContext& getCurrentMutableContext() {
jamie@264 5902 if( !currentContext )
jamie@264 5903 currentContext = new Context();
jamie@264 5904 return *currentContext;
jamie@264 5905 }
jamie@264 5906 IContext& getCurrentContext() {
jamie@264 5907 return getCurrentMutableContext();
jamie@264 5908 }
jamie@264 5909
jamie@264 5910 Stream createStream( std::string const& streamName ) {
jamie@264 5911 if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false );
jamie@264 5912 if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false );
jamie@264 5913 if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
jamie@264 5914
jamie@264 5915 throw std::domain_error( "Unknown stream: " + streamName );
jamie@264 5916 }
jamie@264 5917
jamie@264 5918 void cleanUpContext() {
jamie@264 5919 delete currentContext;
jamie@264 5920 currentContext = NULL;
jamie@264 5921 }
jamie@264 5922 }
jamie@264 5923
jamie@264 5924 // #included from: catch_console_colour_impl.hpp
jamie@264 5925 #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
jamie@264 5926
jamie@264 5927 namespace Catch { namespace Detail {
jamie@264 5928 struct IColourImpl {
jamie@264 5929 virtual ~IColourImpl() {}
jamie@264 5930 virtual void use( Colour::Code _colourCode ) = 0;
jamie@264 5931 };
jamie@264 5932 }}
jamie@264 5933
jamie@264 5934 #if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
jamie@264 5935
jamie@264 5936 #ifndef NOMINMAX
jamie@264 5937 #define NOMINMAX
jamie@264 5938 #endif
jamie@264 5939
jamie@264 5940 #ifdef __AFXDLL
jamie@264 5941 #include <AfxWin.h>
jamie@264 5942 #else
jamie@264 5943 #include <windows.h>
jamie@264 5944 #endif
jamie@264 5945
jamie@264 5946 namespace Catch {
jamie@264 5947 namespace {
jamie@264 5948
jamie@264 5949 class Win32ColourImpl : public Detail::IColourImpl {
jamie@264 5950 public:
jamie@264 5951 Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
jamie@264 5952 {
jamie@264 5953 CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
jamie@264 5954 GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
jamie@264 5955 originalAttributes = csbiInfo.wAttributes;
jamie@264 5956 }
jamie@264 5957
jamie@264 5958 virtual void use( Colour::Code _colourCode ) {
jamie@264 5959 switch( _colourCode ) {
jamie@264 5960 case Colour::None: return setTextAttribute( originalAttributes );
jamie@264 5961 case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
jamie@264 5962 case Colour::Red: return setTextAttribute( FOREGROUND_RED );
jamie@264 5963 case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
jamie@264 5964 case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
jamie@264 5965 case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
jamie@264 5966 case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
jamie@264 5967 case Colour::Grey: return setTextAttribute( 0 );
jamie@264 5968
jamie@264 5969 case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
jamie@264 5970 case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
jamie@264 5971 case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
jamie@264 5972 case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
jamie@264 5973
jamie@264 5974 case Colour::Bright: throw std::logic_error( "not a colour" );
jamie@264 5975 }
jamie@264 5976 }
jamie@264 5977
jamie@264 5978 private:
jamie@264 5979 void setTextAttribute( WORD _textAttribute ) {
jamie@264 5980 SetConsoleTextAttribute( stdoutHandle, _textAttribute );
jamie@264 5981 }
jamie@264 5982 HANDLE stdoutHandle;
jamie@264 5983 WORD originalAttributes;
jamie@264 5984 };
jamie@264 5985
jamie@264 5986 inline bool shouldUseColourForPlatform() {
jamie@264 5987 return true;
jamie@264 5988 }
jamie@264 5989
jamie@264 5990 static Detail::IColourImpl* platformColourInstance() {
jamie@264 5991 static Win32ColourImpl s_instance;
jamie@264 5992 return &s_instance;
jamie@264 5993 }
jamie@264 5994
jamie@264 5995 } // end anon namespace
jamie@264 5996 } // end namespace Catch
jamie@264 5997
jamie@264 5998 #else // Not Windows - assumed to be POSIX compatible //////////////////////////
jamie@264 5999
jamie@264 6000 #include <unistd.h>
jamie@264 6001
jamie@264 6002 namespace Catch {
jamie@264 6003 namespace {
jamie@264 6004
jamie@264 6005 // use POSIX/ ANSI console terminal codes
jamie@264 6006 // Thanks to Adam Strzelecki for original contribution
jamie@264 6007 // (http://github.com/nanoant)
jamie@264 6008 // https://github.com/philsquared/Catch/pull/131
jamie@264 6009 class PosixColourImpl : public Detail::IColourImpl {
jamie@264 6010 public:
jamie@264 6011 virtual void use( Colour::Code _colourCode ) {
jamie@264 6012 switch( _colourCode ) {
jamie@264 6013 case Colour::None:
jamie@264 6014 case Colour::White: return setColour( "[0m" );
jamie@264 6015 case Colour::Red: return setColour( "[0;31m" );
jamie@264 6016 case Colour::Green: return setColour( "[0;32m" );
jamie@264 6017 case Colour::Blue: return setColour( "[0:34m" );
jamie@264 6018 case Colour::Cyan: return setColour( "[0;36m" );
jamie@264 6019 case Colour::Yellow: return setColour( "[0;33m" );
jamie@264 6020 case Colour::Grey: return setColour( "[1;30m" );
jamie@264 6021
jamie@264 6022 case Colour::LightGrey: return setColour( "[0;37m" );
jamie@264 6023 case Colour::BrightRed: return setColour( "[1;31m" );
jamie@264 6024 case Colour::BrightGreen: return setColour( "[1;32m" );
jamie@264 6025 case Colour::BrightWhite: return setColour( "[1;37m" );
jamie@264 6026
jamie@264 6027 case Colour::Bright: throw std::logic_error( "not a colour" );
jamie@264 6028 }
jamie@264 6029 }
jamie@264 6030 private:
jamie@264 6031 void setColour( const char* _escapeCode ) {
jamie@264 6032 std::cout << '\033' << _escapeCode;
jamie@264 6033 }
jamie@264 6034 };
jamie@264 6035
jamie@264 6036 inline bool shouldUseColourForPlatform() {
jamie@264 6037 return isatty(STDOUT_FILENO);
jamie@264 6038 }
jamie@264 6039
jamie@264 6040 static Detail::IColourImpl* platformColourInstance() {
jamie@264 6041 static PosixColourImpl s_instance;
jamie@264 6042 return &s_instance;
jamie@264 6043 }
jamie@264 6044
jamie@264 6045 } // end anon namespace
jamie@264 6046 } // end namespace Catch
jamie@264 6047
jamie@264 6048 #endif // not Windows
jamie@264 6049
jamie@264 6050 namespace Catch {
jamie@264 6051
jamie@264 6052 namespace {
jamie@264 6053 struct NoColourImpl : Detail::IColourImpl {
jamie@264 6054 void use( Colour::Code ) {}
jamie@264 6055
jamie@264 6056 static IColourImpl* instance() {
jamie@264 6057 static NoColourImpl s_instance;
jamie@264 6058 return &s_instance;
jamie@264 6059 }
jamie@264 6060 };
jamie@264 6061 static bool shouldUseColour() {
jamie@264 6062 return shouldUseColourForPlatform() && !isDebuggerActive();
jamie@264 6063 }
jamie@264 6064 }
jamie@264 6065
jamie@264 6066 Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
jamie@264 6067 Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
jamie@264 6068 Colour::~Colour(){ if( !m_moved ) use( None ); }
jamie@264 6069 void Colour::use( Code _colourCode ) {
jamie@264 6070 impl()->use( _colourCode );
jamie@264 6071 }
jamie@264 6072
jamie@264 6073 Detail::IColourImpl* Colour::impl() {
jamie@264 6074 return shouldUseColour()
jamie@264 6075 ? platformColourInstance()
jamie@264 6076 : NoColourImpl::instance();
jamie@264 6077 }
jamie@264 6078
jamie@264 6079 } // end namespace Catch
jamie@264 6080
jamie@264 6081 // #included from: catch_generators_impl.hpp
jamie@264 6082 #define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
jamie@264 6083
jamie@264 6084 #include <vector>
jamie@264 6085 #include <string>
jamie@264 6086 #include <map>
jamie@264 6087
jamie@264 6088 namespace Catch {
jamie@264 6089
jamie@264 6090 struct GeneratorInfo : IGeneratorInfo {
jamie@264 6091
jamie@264 6092 GeneratorInfo( std::size_t size )
jamie@264 6093 : m_size( size ),
jamie@264 6094 m_currentIndex( 0 )
jamie@264 6095 {}
jamie@264 6096
jamie@264 6097 bool moveNext() {
jamie@264 6098 if( ++m_currentIndex == m_size ) {
jamie@264 6099 m_currentIndex = 0;
jamie@264 6100 return false;
jamie@264 6101 }
jamie@264 6102 return true;
jamie@264 6103 }
jamie@264 6104
jamie@264 6105 std::size_t getCurrentIndex() const {
jamie@264 6106 return m_currentIndex;
jamie@264 6107 }
jamie@264 6108
jamie@264 6109 std::size_t m_size;
jamie@264 6110 std::size_t m_currentIndex;
jamie@264 6111 };
jamie@264 6112
jamie@264 6113 ///////////////////////////////////////////////////////////////////////////
jamie@264 6114
jamie@264 6115 class GeneratorsForTest : public IGeneratorsForTest {
jamie@264 6116
jamie@264 6117 public:
jamie@264 6118 ~GeneratorsForTest() {
jamie@264 6119 deleteAll( m_generatorsInOrder );
jamie@264 6120 }
jamie@264 6121
jamie@264 6122 IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
jamie@264 6123 std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
jamie@264 6124 if( it == m_generatorsByName.end() ) {
jamie@264 6125 IGeneratorInfo* info = new GeneratorInfo( size );
jamie@264 6126 m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
jamie@264 6127 m_generatorsInOrder.push_back( info );
jamie@264 6128 return *info;
jamie@264 6129 }
jamie@264 6130 return *it->second;
jamie@264 6131 }
jamie@264 6132
jamie@264 6133 bool moveNext() {
jamie@264 6134 std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
jamie@264 6135 std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
jamie@264 6136 for(; it != itEnd; ++it ) {
jamie@264 6137 if( (*it)->moveNext() )
jamie@264 6138 return true;
jamie@264 6139 }
jamie@264 6140 return false;
jamie@264 6141 }
jamie@264 6142
jamie@264 6143 private:
jamie@264 6144 std::map<std::string, IGeneratorInfo*> m_generatorsByName;
jamie@264 6145 std::vector<IGeneratorInfo*> m_generatorsInOrder;
jamie@264 6146 };
jamie@264 6147
jamie@264 6148 IGeneratorsForTest* createGeneratorsForTest()
jamie@264 6149 {
jamie@264 6150 return new GeneratorsForTest();
jamie@264 6151 }
jamie@264 6152
jamie@264 6153 } // end namespace Catch
jamie@264 6154
jamie@264 6155 // #included from: catch_assertionresult.hpp
jamie@264 6156 #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
jamie@264 6157
jamie@264 6158 namespace Catch {
jamie@264 6159
jamie@264 6160 AssertionInfo::AssertionInfo( std::string const& _macroName,
jamie@264 6161 SourceLineInfo const& _lineInfo,
jamie@264 6162 std::string const& _capturedExpression,
jamie@264 6163 ResultDisposition::Flags _resultDisposition )
jamie@264 6164 : macroName( _macroName ),
jamie@264 6165 lineInfo( _lineInfo ),
jamie@264 6166 capturedExpression( _capturedExpression ),
jamie@264 6167 resultDisposition( _resultDisposition )
jamie@264 6168 {}
jamie@264 6169
jamie@264 6170 AssertionResult::AssertionResult() {}
jamie@264 6171
jamie@264 6172 AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
jamie@264 6173 : m_info( info ),
jamie@264 6174 m_resultData( data )
jamie@264 6175 {}
jamie@264 6176
jamie@264 6177 AssertionResult::~AssertionResult() {}
jamie@264 6178
jamie@264 6179 // Result was a success
jamie@264 6180 bool AssertionResult::succeeded() const {
jamie@264 6181 return Catch::isOk( m_resultData.resultType );
jamie@264 6182 }
jamie@264 6183
jamie@264 6184 // Result was a success, or failure is suppressed
jamie@264 6185 bool AssertionResult::isOk() const {
jamie@264 6186 return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
jamie@264 6187 }
jamie@264 6188
jamie@264 6189 ResultWas::OfType AssertionResult::getResultType() const {
jamie@264 6190 return m_resultData.resultType;
jamie@264 6191 }
jamie@264 6192
jamie@264 6193 bool AssertionResult::hasExpression() const {
jamie@264 6194 return !m_info.capturedExpression.empty();
jamie@264 6195 }
jamie@264 6196
jamie@264 6197 bool AssertionResult::hasMessage() const {
jamie@264 6198 return !m_resultData.message.empty();
jamie@264 6199 }
jamie@264 6200
jamie@264 6201 std::string AssertionResult::getExpression() const {
jamie@264 6202 if( isFalseTest( m_info.resultDisposition ) )
jamie@264 6203 return "!" + m_info.capturedExpression;
jamie@264 6204 else
jamie@264 6205 return m_info.capturedExpression;
jamie@264 6206 }
jamie@264 6207 std::string AssertionResult::getExpressionInMacro() const {
jamie@264 6208 if( m_info.macroName.empty() )
jamie@264 6209 return m_info.capturedExpression;
jamie@264 6210 else
jamie@264 6211 return m_info.macroName + "( " + m_info.capturedExpression + " )";
jamie@264 6212 }
jamie@264 6213
jamie@264 6214 bool AssertionResult::hasExpandedExpression() const {
jamie@264 6215 return hasExpression() && getExpandedExpression() != getExpression();
jamie@264 6216 }
jamie@264 6217
jamie@264 6218 std::string AssertionResult::getExpandedExpression() const {
jamie@264 6219 return m_resultData.reconstructedExpression;
jamie@264 6220 }
jamie@264 6221
jamie@264 6222 std::string AssertionResult::getMessage() const {
jamie@264 6223 return m_resultData.message;
jamie@264 6224 }
jamie@264 6225 SourceLineInfo AssertionResult::getSourceInfo() const {
jamie@264 6226 return m_info.lineInfo;
jamie@264 6227 }
jamie@264 6228
jamie@264 6229 std::string AssertionResult::getTestMacroName() const {
jamie@264 6230 return m_info.macroName;
jamie@264 6231 }
jamie@264 6232
jamie@264 6233 } // end namespace Catch
jamie@264 6234
jamie@264 6235 // #included from: catch_test_case_info.hpp
jamie@264 6236 #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
jamie@264 6237
jamie@264 6238 namespace Catch {
jamie@264 6239
jamie@264 6240 inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
jamie@264 6241 if( tag == "." ||
jamie@264 6242 tag == "hide" ||
jamie@264 6243 tag == "!hide" )
jamie@264 6244 return TestCaseInfo::IsHidden;
jamie@264 6245 else if( tag == "!throws" )
jamie@264 6246 return TestCaseInfo::Throws;
jamie@264 6247 else if( tag == "!shouldfail" )
jamie@264 6248 return TestCaseInfo::ShouldFail;
jamie@264 6249 else if( tag == "!mayfail" )
jamie@264 6250 return TestCaseInfo::MayFail;
jamie@264 6251 else
jamie@264 6252 return TestCaseInfo::None;
jamie@264 6253 }
jamie@264 6254 inline bool isReservedTag( std::string const& tag ) {
jamie@264 6255 return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] );
jamie@264 6256 }
jamie@264 6257 inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
jamie@264 6258 if( isReservedTag( tag ) ) {
jamie@264 6259 {
jamie@264 6260 Colour colourGuard( Colour::Red );
jamie@264 6261 std::cerr
jamie@264 6262 << "Tag name [" << tag << "] not allowed.\n"
jamie@264 6263 << "Tag names starting with non alpha-numeric characters are reserved\n";
jamie@264 6264 }
jamie@264 6265 {
jamie@264 6266 Colour colourGuard( Colour::FileName );
jamie@264 6267 std::cerr << _lineInfo << std::endl;
jamie@264 6268 }
jamie@264 6269 exit(1);
jamie@264 6270 }
jamie@264 6271 }
jamie@264 6272
jamie@264 6273 TestCase makeTestCase( ITestCase* _testCase,
jamie@264 6274 std::string const& _className,
jamie@264 6275 std::string const& _name,
jamie@264 6276 std::string const& _descOrTags,
jamie@264 6277 SourceLineInfo const& _lineInfo )
jamie@264 6278 {
jamie@264 6279 bool isHidden( startsWith( _name, "./" ) ); // Legacy support
jamie@264 6280
jamie@264 6281 // Parse out tags
jamie@264 6282 std::set<std::string> tags;
jamie@264 6283 std::string desc, tag;
jamie@264 6284 bool inTag = false;
jamie@264 6285 for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
jamie@264 6286 char c = _descOrTags[i];
jamie@264 6287 if( !inTag ) {
jamie@264 6288 if( c == '[' )
jamie@264 6289 inTag = true;
jamie@264 6290 else
jamie@264 6291 desc += c;
jamie@264 6292 }
jamie@264 6293 else {
jamie@264 6294 if( c == ']' ) {
jamie@264 6295 enforceNotReservedTag( tag, _lineInfo );
jamie@264 6296
jamie@264 6297 inTag = false;
jamie@264 6298 if( tag == "hide" || tag == "." )
jamie@264 6299 isHidden = true;
jamie@264 6300 else
jamie@264 6301 tags.insert( tag );
jamie@264 6302 tag.clear();
jamie@264 6303 }
jamie@264 6304 else
jamie@264 6305 tag += c;
jamie@264 6306 }
jamie@264 6307 }
jamie@264 6308 if( isHidden ) {
jamie@264 6309 tags.insert( "hide" );
jamie@264 6310 tags.insert( "." );
jamie@264 6311 }
jamie@264 6312
jamie@264 6313 TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
jamie@264 6314 return TestCase( _testCase, info );
jamie@264 6315 }
jamie@264 6316
jamie@264 6317 TestCaseInfo::TestCaseInfo( std::string const& _name,
jamie@264 6318 std::string const& _className,
jamie@264 6319 std::string const& _description,
jamie@264 6320 std::set<std::string> const& _tags,
jamie@264 6321 SourceLineInfo const& _lineInfo )
jamie@264 6322 : name( _name ),
jamie@264 6323 className( _className ),
jamie@264 6324 description( _description ),
jamie@264 6325 tags( _tags ),
jamie@264 6326 lineInfo( _lineInfo ),
jamie@264 6327 properties( None )
jamie@264 6328 {
jamie@264 6329 std::ostringstream oss;
jamie@264 6330 for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) {
jamie@264 6331 oss << "[" << *it << "]";
jamie@264 6332 std::string lcaseTag = toLower( *it );
jamie@264 6333 properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) );
jamie@264 6334 lcaseTags.insert( lcaseTag );
jamie@264 6335 }
jamie@264 6336 tagsAsString = oss.str();
jamie@264 6337 }
jamie@264 6338
jamie@264 6339 TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
jamie@264 6340 : name( other.name ),
jamie@264 6341 className( other.className ),
jamie@264 6342 description( other.description ),
jamie@264 6343 tags( other.tags ),
jamie@264 6344 lcaseTags( other.lcaseTags ),
jamie@264 6345 tagsAsString( other.tagsAsString ),
jamie@264 6346 lineInfo( other.lineInfo ),
jamie@264 6347 properties( other.properties )
jamie@264 6348 {}
jamie@264 6349
jamie@264 6350 bool TestCaseInfo::isHidden() const {
jamie@264 6351 return ( properties & IsHidden ) != 0;
jamie@264 6352 }
jamie@264 6353 bool TestCaseInfo::throws() const {
jamie@264 6354 return ( properties & Throws ) != 0;
jamie@264 6355 }
jamie@264 6356 bool TestCaseInfo::okToFail() const {
jamie@264 6357 return ( properties & (ShouldFail | MayFail ) ) != 0;
jamie@264 6358 }
jamie@264 6359 bool TestCaseInfo::expectedToFail() const {
jamie@264 6360 return ( properties & (ShouldFail ) ) != 0;
jamie@264 6361 }
jamie@264 6362
jamie@264 6363 TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
jamie@264 6364
jamie@264 6365 TestCase::TestCase( TestCase const& other )
jamie@264 6366 : TestCaseInfo( other ),
jamie@264 6367 test( other.test )
jamie@264 6368 {}
jamie@264 6369
jamie@264 6370 TestCase TestCase::withName( std::string const& _newName ) const {
jamie@264 6371 TestCase other( *this );
jamie@264 6372 other.name = _newName;
jamie@264 6373 return other;
jamie@264 6374 }
jamie@264 6375
jamie@264 6376 void TestCase::swap( TestCase& other ) {
jamie@264 6377 test.swap( other.test );
jamie@264 6378 name.swap( other.name );
jamie@264 6379 className.swap( other.className );
jamie@264 6380 description.swap( other.description );
jamie@264 6381 tags.swap( other.tags );
jamie@264 6382 lcaseTags.swap( other.lcaseTags );
jamie@264 6383 tagsAsString.swap( other.tagsAsString );
jamie@264 6384 std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
jamie@264 6385 std::swap( lineInfo, other.lineInfo );
jamie@264 6386 }
jamie@264 6387
jamie@264 6388 void TestCase::invoke() const {
jamie@264 6389 test->invoke();
jamie@264 6390 }
jamie@264 6391
jamie@264 6392 bool TestCase::operator == ( TestCase const& other ) const {
jamie@264 6393 return test.get() == other.test.get() &&
jamie@264 6394 name == other.name &&
jamie@264 6395 className == other.className;
jamie@264 6396 }
jamie@264 6397
jamie@264 6398 bool TestCase::operator < ( TestCase const& other ) const {
jamie@264 6399 return name < other.name;
jamie@264 6400 }
jamie@264 6401 TestCase& TestCase::operator = ( TestCase const& other ) {
jamie@264 6402 TestCase temp( other );
jamie@264 6403 swap( temp );
jamie@264 6404 return *this;
jamie@264 6405 }
jamie@264 6406
jamie@264 6407 TestCaseInfo const& TestCase::getTestCaseInfo() const
jamie@264 6408 {
jamie@264 6409 return *this;
jamie@264 6410 }
jamie@264 6411
jamie@264 6412 } // end namespace Catch
jamie@264 6413
jamie@264 6414 // #included from: catch_version.hpp
jamie@264 6415 #define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
jamie@264 6416
jamie@264 6417 namespace Catch {
jamie@264 6418
jamie@264 6419 // These numbers are maintained by a script
jamie@264 6420 Version libraryVersion( 1, 0, 53, "master" );
jamie@264 6421 }
jamie@264 6422
jamie@264 6423 // #included from: catch_message.hpp
jamie@264 6424 #define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
jamie@264 6425
jamie@264 6426 namespace Catch {
jamie@264 6427
jamie@264 6428 MessageInfo::MessageInfo( std::string const& _macroName,
jamie@264 6429 SourceLineInfo const& _lineInfo,
jamie@264 6430 ResultWas::OfType _type )
jamie@264 6431 : macroName( _macroName ),
jamie@264 6432 lineInfo( _lineInfo ),
jamie@264 6433 type( _type ),
jamie@264 6434 sequence( ++globalCount )
jamie@264 6435 {}
jamie@264 6436
jamie@264 6437 // This may need protecting if threading support is added
jamie@264 6438 unsigned int MessageInfo::globalCount = 0;
jamie@264 6439
jamie@264 6440 ////////////////////////////////////////////////////////////////////////////
jamie@264 6441
jamie@264 6442 ScopedMessage::ScopedMessage( MessageBuilder const& builder )
jamie@264 6443 : m_info( builder.m_info )
jamie@264 6444 {
jamie@264 6445 m_info.message = builder.m_stream.str();
jamie@264 6446 getResultCapture().pushScopedMessage( m_info );
jamie@264 6447 }
jamie@264 6448 ScopedMessage::ScopedMessage( ScopedMessage const& other )
jamie@264 6449 : m_info( other.m_info )
jamie@264 6450 {}
jamie@264 6451
jamie@264 6452 ScopedMessage::~ScopedMessage() {
jamie@264 6453 getResultCapture().popScopedMessage( m_info );
jamie@264 6454 }
jamie@264 6455
jamie@264 6456 } // end namespace Catch
jamie@264 6457
jamie@264 6458 // #included from: catch_legacy_reporter_adapter.hpp
jamie@264 6459 #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
jamie@264 6460
jamie@264 6461 // #included from: catch_legacy_reporter_adapter.h
jamie@264 6462 #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
jamie@264 6463
jamie@264 6464 namespace Catch
jamie@264 6465 {
jamie@264 6466 // Deprecated
jamie@264 6467 struct IReporter : IShared {
jamie@264 6468 virtual ~IReporter();
jamie@264 6469
jamie@264 6470 virtual bool shouldRedirectStdout() const = 0;
jamie@264 6471
jamie@264 6472 virtual void StartTesting() = 0;
jamie@264 6473 virtual void EndTesting( Totals const& totals ) = 0;
jamie@264 6474 virtual void StartGroup( std::string const& groupName ) = 0;
jamie@264 6475 virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
jamie@264 6476 virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
jamie@264 6477 virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
jamie@264 6478 virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
jamie@264 6479 virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
jamie@264 6480 virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
jamie@264 6481 virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
jamie@264 6482 virtual void Aborted() = 0;
jamie@264 6483 virtual void Result( AssertionResult const& result ) = 0;
jamie@264 6484 };
jamie@264 6485
jamie@264 6486 class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
jamie@264 6487 {
jamie@264 6488 public:
jamie@264 6489 LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
jamie@264 6490 virtual ~LegacyReporterAdapter();
jamie@264 6491
jamie@264 6492 virtual ReporterPreferences getPreferences() const;
jamie@264 6493 virtual void noMatchingTestCases( std::string const& );
jamie@264 6494 virtual void testRunStarting( TestRunInfo const& );
jamie@264 6495 virtual void testGroupStarting( GroupInfo const& groupInfo );
jamie@264 6496 virtual void testCaseStarting( TestCaseInfo const& testInfo );
jamie@264 6497 virtual void sectionStarting( SectionInfo const& sectionInfo );
jamie@264 6498 virtual void assertionStarting( AssertionInfo const& );
jamie@264 6499 virtual bool assertionEnded( AssertionStats const& assertionStats );
jamie@264 6500 virtual void sectionEnded( SectionStats const& sectionStats );
jamie@264 6501 virtual void testCaseEnded( TestCaseStats const& testCaseStats );
jamie@264 6502 virtual void testGroupEnded( TestGroupStats const& testGroupStats );
jamie@264 6503 virtual void testRunEnded( TestRunStats const& testRunStats );
jamie@264 6504
jamie@264 6505 private:
jamie@264 6506 Ptr<IReporter> m_legacyReporter;
jamie@264 6507 };
jamie@264 6508 }
jamie@264 6509
jamie@264 6510 namespace Catch
jamie@264 6511 {
jamie@264 6512 LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
jamie@264 6513 : m_legacyReporter( legacyReporter )
jamie@264 6514 {}
jamie@264 6515 LegacyReporterAdapter::~LegacyReporterAdapter() {}
jamie@264 6516
jamie@264 6517 ReporterPreferences LegacyReporterAdapter::getPreferences() const {
jamie@264 6518 ReporterPreferences prefs;
jamie@264 6519 prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
jamie@264 6520 return prefs;
jamie@264 6521 }
jamie@264 6522
jamie@264 6523 void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
jamie@264 6524 void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
jamie@264 6525 m_legacyReporter->StartTesting();
jamie@264 6526 }
jamie@264 6527 void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
jamie@264 6528 m_legacyReporter->StartGroup( groupInfo.name );
jamie@264 6529 }
jamie@264 6530 void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
jamie@264 6531 m_legacyReporter->StartTestCase( testInfo );
jamie@264 6532 }
jamie@264 6533 void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
jamie@264 6534 m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
jamie@264 6535 }
jamie@264 6536 void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
jamie@264 6537 // Not on legacy interface
jamie@264 6538 }
jamie@264 6539
jamie@264 6540 bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
jamie@264 6541 if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
jamie@264 6542 for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
jamie@264 6543 it != itEnd;
jamie@264 6544 ++it ) {
jamie@264 6545 if( it->type == ResultWas::Info ) {
jamie@264 6546 ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
jamie@264 6547 rb << it->message;
jamie@264 6548 rb.setResultType( ResultWas::Info );
jamie@264 6549 AssertionResult result = rb.build();
jamie@264 6550 m_legacyReporter->Result( result );
jamie@264 6551 }
jamie@264 6552 }
jamie@264 6553 }
jamie@264 6554 m_legacyReporter->Result( assertionStats.assertionResult );
jamie@264 6555 return true;
jamie@264 6556 }
jamie@264 6557 void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
jamie@264 6558 if( sectionStats.missingAssertions )
jamie@264 6559 m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
jamie@264 6560 m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
jamie@264 6561 }
jamie@264 6562 void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
jamie@264 6563 m_legacyReporter->EndTestCase
jamie@264 6564 ( testCaseStats.testInfo,
jamie@264 6565 testCaseStats.totals,
jamie@264 6566 testCaseStats.stdOut,
jamie@264 6567 testCaseStats.stdErr );
jamie@264 6568 }
jamie@264 6569 void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
jamie@264 6570 if( testGroupStats.aborting )
jamie@264 6571 m_legacyReporter->Aborted();
jamie@264 6572 m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
jamie@264 6573 }
jamie@264 6574 void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
jamie@264 6575 m_legacyReporter->EndTesting( testRunStats.totals );
jamie@264 6576 }
jamie@264 6577 }
jamie@264 6578
jamie@264 6579 // #included from: catch_timer.hpp
jamie@264 6580
jamie@264 6581 #ifdef __clang__
jamie@264 6582 #pragma clang diagnostic push
jamie@264 6583 #pragma clang diagnostic ignored "-Wc++11-long-long"
jamie@264 6584 #endif
jamie@264 6585
jamie@264 6586 #ifdef CATCH_PLATFORM_WINDOWS
jamie@264 6587 #include <windows.h>
jamie@264 6588 #else
jamie@264 6589 #include <sys/time.h>
jamie@264 6590 #endif
jamie@264 6591
jamie@264 6592 namespace Catch {
jamie@264 6593
jamie@264 6594 namespace {
jamie@264 6595 #ifdef CATCH_PLATFORM_WINDOWS
jamie@264 6596 uint64_t getCurrentTicks() {
jamie@264 6597 static uint64_t hz=0, hzo=0;
jamie@264 6598 if (!hz) {
jamie@264 6599 QueryPerformanceFrequency((LARGE_INTEGER*)&hz);
jamie@264 6600 QueryPerformanceCounter((LARGE_INTEGER*)&hzo);
jamie@264 6601 }
jamie@264 6602 uint64_t t;
jamie@264 6603 QueryPerformanceCounter((LARGE_INTEGER*)&t);
jamie@264 6604 return ((t-hzo)*1000000)/hz;
jamie@264 6605 }
jamie@264 6606 #else
jamie@264 6607 uint64_t getCurrentTicks() {
jamie@264 6608 timeval t;
jamie@264 6609 gettimeofday(&t,NULL);
jamie@264 6610 return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
jamie@264 6611 }
jamie@264 6612 #endif
jamie@264 6613 }
jamie@264 6614
jamie@264 6615 void Timer::start() {
jamie@264 6616 m_ticks = getCurrentTicks();
jamie@264 6617 }
jamie@264 6618 unsigned int Timer::getElapsedNanoseconds() const {
jamie@264 6619 return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
jamie@264 6620 }
jamie@264 6621 unsigned int Timer::getElapsedMilliseconds() const {
jamie@264 6622 return static_cast<unsigned int>((getCurrentTicks() - m_ticks)/1000);
jamie@264 6623 }
jamie@264 6624 double Timer::getElapsedSeconds() const {
jamie@264 6625 return (getCurrentTicks() - m_ticks)/1000000.0;
jamie@264 6626 }
jamie@264 6627
jamie@264 6628 } // namespace Catch
jamie@264 6629
jamie@264 6630 #ifdef __clang__
jamie@264 6631 #pragma clang diagnostic pop
jamie@264 6632 #endif
jamie@264 6633 // #included from: catch_common.hpp
jamie@264 6634 #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
jamie@264 6635
jamie@264 6636 namespace Catch {
jamie@264 6637
jamie@264 6638 bool startsWith( std::string const& s, std::string const& prefix ) {
jamie@264 6639 return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
jamie@264 6640 }
jamie@264 6641 bool endsWith( std::string const& s, std::string const& suffix ) {
jamie@264 6642 return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
jamie@264 6643 }
jamie@264 6644 bool contains( std::string const& s, std::string const& infix ) {
jamie@264 6645 return s.find( infix ) != std::string::npos;
jamie@264 6646 }
jamie@264 6647 void toLowerInPlace( std::string& s ) {
jamie@264 6648 std::transform( s.begin(), s.end(), s.begin(), ::tolower );
jamie@264 6649 }
jamie@264 6650 std::string toLower( std::string const& s ) {
jamie@264 6651 std::string lc = s;
jamie@264 6652 toLowerInPlace( lc );
jamie@264 6653 return lc;
jamie@264 6654 }
jamie@264 6655 std::string trim( std::string const& str ) {
jamie@264 6656 static char const* whitespaceChars = "\n\r\t ";
jamie@264 6657 std::string::size_type start = str.find_first_not_of( whitespaceChars );
jamie@264 6658 std::string::size_type end = str.find_last_not_of( whitespaceChars );
jamie@264 6659
jamie@264 6660 return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
jamie@264 6661 }
jamie@264 6662
jamie@264 6663 pluralise::pluralise( std::size_t count, std::string const& label )
jamie@264 6664 : m_count( count ),
jamie@264 6665 m_label( label )
jamie@264 6666 {}
jamie@264 6667
jamie@264 6668 std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
jamie@264 6669 os << pluraliser.m_count << " " << pluraliser.m_label;
jamie@264 6670 if( pluraliser.m_count != 1 )
jamie@264 6671 os << "s";
jamie@264 6672 return os;
jamie@264 6673 }
jamie@264 6674
jamie@264 6675 SourceLineInfo::SourceLineInfo() : line( 0 ){}
jamie@264 6676 SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
jamie@264 6677 : file( _file ),
jamie@264 6678 line( _line )
jamie@264 6679 {}
jamie@264 6680 SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
jamie@264 6681 : file( other.file ),
jamie@264 6682 line( other.line )
jamie@264 6683 {}
jamie@264 6684 bool SourceLineInfo::empty() const {
jamie@264 6685 return file.empty();
jamie@264 6686 }
jamie@264 6687 bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
jamie@264 6688 return line == other.line && file == other.file;
jamie@264 6689 }
jamie@264 6690
jamie@264 6691 std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
jamie@264 6692 #ifndef __GNUG__
jamie@264 6693 os << info.file << "(" << info.line << ")";
jamie@264 6694 #else
jamie@264 6695 os << info.file << ":" << info.line;
jamie@264 6696 #endif
jamie@264 6697 return os;
jamie@264 6698 }
jamie@264 6699
jamie@264 6700 void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
jamie@264 6701 std::ostringstream oss;
jamie@264 6702 oss << locationInfo << ": Internal Catch error: '" << message << "'";
jamie@264 6703 if( alwaysTrue() )
jamie@264 6704 throw std::logic_error( oss.str() );
jamie@264 6705 }
jamie@264 6706 }
jamie@264 6707
jamie@264 6708 // #included from: catch_section.hpp
jamie@264 6709 #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
jamie@264 6710
jamie@264 6711 namespace Catch {
jamie@264 6712
jamie@264 6713 SectionInfo::SectionInfo
jamie@264 6714 ( SourceLineInfo const& _lineInfo,
jamie@264 6715 std::string const& _name,
jamie@264 6716 std::string const& _description )
jamie@264 6717 : name( _name ),
jamie@264 6718 description( _description ),
jamie@264 6719 lineInfo( _lineInfo )
jamie@264 6720 {}
jamie@264 6721
jamie@264 6722 Section::Section( SectionInfo const& info )
jamie@264 6723 : m_info( info ),
jamie@264 6724 m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
jamie@264 6725 {
jamie@264 6726 m_timer.start();
jamie@264 6727 }
jamie@264 6728
jamie@264 6729 Section::~Section() {
jamie@264 6730 if( m_sectionIncluded )
jamie@264 6731 getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
jamie@264 6732 }
jamie@264 6733
jamie@264 6734 // This indicates whether the section should be executed or not
jamie@264 6735 Section::operator bool() const {
jamie@264 6736 return m_sectionIncluded;
jamie@264 6737 }
jamie@264 6738
jamie@264 6739 } // end namespace Catch
jamie@264 6740
jamie@264 6741 // #included from: catch_debugger.hpp
jamie@264 6742 #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
jamie@264 6743
jamie@264 6744 #include <iostream>
jamie@264 6745
jamie@264 6746 #ifdef CATCH_PLATFORM_MAC
jamie@264 6747
jamie@264 6748 #include <assert.h>
jamie@264 6749 #include <stdbool.h>
jamie@264 6750 #include <sys/types.h>
jamie@264 6751 #include <unistd.h>
jamie@264 6752 #include <sys/sysctl.h>
jamie@264 6753
jamie@264 6754 namespace Catch{
jamie@264 6755
jamie@264 6756 // The following function is taken directly from the following technical note:
jamie@264 6757 // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
jamie@264 6758
jamie@264 6759 // Returns true if the current process is being debugged (either
jamie@264 6760 // running under the debugger or has a debugger attached post facto).
jamie@264 6761 bool isDebuggerActive(){
jamie@264 6762
jamie@264 6763 int mib[4];
jamie@264 6764 struct kinfo_proc info;
jamie@264 6765 size_t size;
jamie@264 6766
jamie@264 6767 // Initialize the flags so that, if sysctl fails for some bizarre
jamie@264 6768 // reason, we get a predictable result.
jamie@264 6769
jamie@264 6770 info.kp_proc.p_flag = 0;
jamie@264 6771
jamie@264 6772 // Initialize mib, which tells sysctl the info we want, in this case
jamie@264 6773 // we're looking for information about a specific process ID.
jamie@264 6774
jamie@264 6775 mib[0] = CTL_KERN;
jamie@264 6776 mib[1] = KERN_PROC;
jamie@264 6777 mib[2] = KERN_PROC_PID;
jamie@264 6778 mib[3] = getpid();
jamie@264 6779
jamie@264 6780 // Call sysctl.
jamie@264 6781
jamie@264 6782 size = sizeof(info);
jamie@264 6783 if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) {
jamie@264 6784 std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
jamie@264 6785 return false;
jamie@264 6786 }
jamie@264 6787
jamie@264 6788 // We're being debugged if the P_TRACED flag is set.
jamie@264 6789
jamie@264 6790 return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
jamie@264 6791 }
jamie@264 6792 } // namespace Catch
jamie@264 6793
jamie@264 6794 #elif defined(_MSC_VER)
jamie@264 6795 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
jamie@264 6796 namespace Catch {
jamie@264 6797 bool isDebuggerActive() {
jamie@264 6798 return IsDebuggerPresent() != 0;
jamie@264 6799 }
jamie@264 6800 }
jamie@264 6801 #elif defined(__MINGW32__)
jamie@264 6802 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
jamie@264 6803 namespace Catch {
jamie@264 6804 bool isDebuggerActive() {
jamie@264 6805 return IsDebuggerPresent() != 0;
jamie@264 6806 }
jamie@264 6807 }
jamie@264 6808 #else
jamie@264 6809 namespace Catch {
jamie@264 6810 inline bool isDebuggerActive() { return false; }
jamie@264 6811 }
jamie@264 6812 #endif // Platform
jamie@264 6813
jamie@264 6814 #ifdef CATCH_PLATFORM_WINDOWS
jamie@264 6815 extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
jamie@264 6816 namespace Catch {
jamie@264 6817 void writeToDebugConsole( std::string const& text ) {
jamie@264 6818 ::OutputDebugStringA( text.c_str() );
jamie@264 6819 }
jamie@264 6820 }
jamie@264 6821 #else
jamie@264 6822 namespace Catch {
jamie@264 6823 void writeToDebugConsole( std::string const& text ) {
jamie@264 6824 // !TBD: Need a version for Mac/ XCode and other IDEs
jamie@264 6825 std::cout << text;
jamie@264 6826 }
jamie@264 6827 }
jamie@264 6828 #endif // Platform
jamie@264 6829
jamie@264 6830 // #included from: catch_tostring.hpp
jamie@264 6831 #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
jamie@264 6832
jamie@264 6833 namespace Catch {
jamie@264 6834
jamie@264 6835 namespace Detail {
jamie@264 6836
jamie@264 6837 namespace {
jamie@264 6838 struct Endianness {
jamie@264 6839 enum Arch { Big, Little };
jamie@264 6840
jamie@264 6841 static Arch which() {
jamie@264 6842 union _{
jamie@264 6843 int asInt;
jamie@264 6844 char asChar[sizeof (int)];
jamie@264 6845 } u;
jamie@264 6846
jamie@264 6847 u.asInt = 1;
jamie@264 6848 return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
jamie@264 6849 }
jamie@264 6850 };
jamie@264 6851 }
jamie@264 6852
jamie@264 6853 std::string rawMemoryToString( const void *object, std::size_t size )
jamie@264 6854 {
jamie@264 6855 // Reverse order for little endian architectures
jamie@264 6856 int i = 0, end = static_cast<int>( size ), inc = 1;
jamie@264 6857 if( Endianness::which() == Endianness::Little ) {
jamie@264 6858 i = end-1;
jamie@264 6859 end = inc = -1;
jamie@264 6860 }
jamie@264 6861
jamie@264 6862 unsigned char const *bytes = static_cast<unsigned char const *>(object);
jamie@264 6863 std::ostringstream os;
jamie@264 6864 os << "0x" << std::setfill('0') << std::hex;
jamie@264 6865 for( ; i != end; i += inc )
jamie@264 6866 os << std::setw(2) << static_cast<unsigned>(bytes[i]);
jamie@264 6867 return os.str();
jamie@264 6868 }
jamie@264 6869 }
jamie@264 6870
jamie@264 6871 std::string toString( std::string const& value ) {
jamie@264 6872 std::string s = value;
jamie@264 6873 if( getCurrentContext().getConfig()->showInvisibles() ) {
jamie@264 6874 for(size_t i = 0; i < s.size(); ++i ) {
jamie@264 6875 std::string subs;
jamie@264 6876 switch( s[i] ) {
jamie@264 6877 case '\n': subs = "\\n"; break;
jamie@264 6878 case '\t': subs = "\\t"; break;
jamie@264 6879 default: break;
jamie@264 6880 }
jamie@264 6881 if( !subs.empty() ) {
jamie@264 6882 s = s.substr( 0, i ) + subs + s.substr( i+1 );
jamie@264 6883 ++i;
jamie@264 6884 }
jamie@264 6885 }
jamie@264 6886 }
jamie@264 6887 return "\"" + s + "\"";
jamie@264 6888 }
jamie@264 6889 std::string toString( std::wstring const& value ) {
jamie@264 6890
jamie@264 6891 std::string s;
jamie@264 6892 s.reserve( value.size() );
jamie@264 6893 for(size_t i = 0; i < value.size(); ++i )
jamie@264 6894 s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
jamie@264 6895 return toString( s );
jamie@264 6896 }
jamie@264 6897
jamie@264 6898 std::string toString( const char* const value ) {
jamie@264 6899 return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
jamie@264 6900 }
jamie@264 6901
jamie@264 6902 std::string toString( char* const value ) {
jamie@264 6903 return Catch::toString( static_cast<const char*>( value ) );
jamie@264 6904 }
jamie@264 6905
jamie@264 6906 std::string toString( const wchar_t* const value )
jamie@264 6907 {
jamie@264 6908 return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
jamie@264 6909 }
jamie@264 6910
jamie@264 6911 std::string toString( wchar_t* const value )
jamie@264 6912 {
jamie@264 6913 return Catch::toString( static_cast<const wchar_t*>( value ) );
jamie@264 6914 }
jamie@264 6915
jamie@264 6916 std::string toString( int value ) {
jamie@264 6917 std::ostringstream oss;
jamie@264 6918 oss << value;
jamie@264 6919 return oss.str();
jamie@264 6920 }
jamie@264 6921
jamie@264 6922 std::string toString( unsigned long value ) {
jamie@264 6923 std::ostringstream oss;
jamie@264 6924 if( value > 8192 )
jamie@264 6925 oss << "0x" << std::hex << value;
jamie@264 6926 else
jamie@264 6927 oss << value;
jamie@264 6928 return oss.str();
jamie@264 6929 }
jamie@264 6930
jamie@264 6931 std::string toString( unsigned int value ) {
jamie@264 6932 return toString( static_cast<unsigned long>( value ) );
jamie@264 6933 }
jamie@264 6934
jamie@264 6935 template<typename T>
jamie@264 6936 std::string fpToString( T value, int precision ) {
jamie@264 6937 std::ostringstream oss;
jamie@264 6938 oss << std::setprecision( precision )
jamie@264 6939 << std::fixed
jamie@264 6940 << value;
jamie@264 6941 std::string d = oss.str();
jamie@264 6942 std::size_t i = d.find_last_not_of( '0' );
jamie@264 6943 if( i != std::string::npos && i != d.size()-1 ) {
jamie@264 6944 if( d[i] == '.' )
jamie@264 6945 i++;
jamie@264 6946 d = d.substr( 0, i+1 );
jamie@264 6947 }
jamie@264 6948 return d;
jamie@264 6949 }
jamie@264 6950
jamie@264 6951 std::string toString( const double value ) {
jamie@264 6952 return fpToString( value, 10 );
jamie@264 6953 }
jamie@264 6954 std::string toString( const float value ) {
jamie@264 6955 return fpToString( value, 5 ) + "f";
jamie@264 6956 }
jamie@264 6957
jamie@264 6958 std::string toString( bool value ) {
jamie@264 6959 return value ? "true" : "false";
jamie@264 6960 }
jamie@264 6961
jamie@264 6962 std::string toString( char value ) {
jamie@264 6963 return value < ' '
jamie@264 6964 ? toString( static_cast<unsigned int>( value ) )
jamie@264 6965 : Detail::makeString( value );
jamie@264 6966 }
jamie@264 6967
jamie@264 6968 std::string toString( signed char value ) {
jamie@264 6969 return toString( static_cast<char>( value ) );
jamie@264 6970 }
jamie@264 6971
jamie@264 6972 std::string toString( unsigned char value ) {
jamie@264 6973 return toString( static_cast<char>( value ) );
jamie@264 6974 }
jamie@264 6975
jamie@264 6976 #ifdef CATCH_CONFIG_CPP11_NULLPTR
jamie@264 6977 std::string toString( std::nullptr_t ) {
jamie@264 6978 return "nullptr";
jamie@264 6979 }
jamie@264 6980 #endif
jamie@264 6981
jamie@264 6982 #ifdef __OBJC__
jamie@264 6983 std::string toString( NSString const * const& nsstring ) {
jamie@264 6984 if( !nsstring )
jamie@264 6985 return "nil";
jamie@264 6986 return "@" + toString([nsstring UTF8String]);
jamie@264 6987 }
jamie@264 6988 std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
jamie@264 6989 if( !nsstring )
jamie@264 6990 return "nil";
jamie@264 6991 return "@" + toString([nsstring UTF8String]);
jamie@264 6992 }
jamie@264 6993 std::string toString( NSObject* const& nsObject ) {
jamie@264 6994 return toString( [nsObject description] );
jamie@264 6995 }
jamie@264 6996 #endif
jamie@264 6997
jamie@264 6998 } // end namespace Catch
jamie@264 6999
jamie@264 7000 // #included from: catch_result_builder.hpp
jamie@264 7001 #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
jamie@264 7002
jamie@264 7003 namespace Catch {
jamie@264 7004
jamie@264 7005 ResultBuilder::ResultBuilder( char const* macroName,
jamie@264 7006 SourceLineInfo const& lineInfo,
jamie@264 7007 char const* capturedExpression,
jamie@264 7008 ResultDisposition::Flags resultDisposition )
jamie@264 7009 : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ),
jamie@264 7010 m_shouldDebugBreak( false ),
jamie@264 7011 m_shouldThrow( false )
jamie@264 7012 {}
jamie@264 7013
jamie@264 7014 ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
jamie@264 7015 m_data.resultType = result;
jamie@264 7016 return *this;
jamie@264 7017 }
jamie@264 7018 ResultBuilder& ResultBuilder::setResultType( bool result ) {
jamie@264 7019 m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
jamie@264 7020 return *this;
jamie@264 7021 }
jamie@264 7022 ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
jamie@264 7023 m_exprComponents.lhs = lhs;
jamie@264 7024 return *this;
jamie@264 7025 }
jamie@264 7026 ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
jamie@264 7027 m_exprComponents.rhs = rhs;
jamie@264 7028 return *this;
jamie@264 7029 }
jamie@264 7030 ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
jamie@264 7031 m_exprComponents.op = op;
jamie@264 7032 return *this;
jamie@264 7033 }
jamie@264 7034
jamie@264 7035 void ResultBuilder::endExpression() {
jamie@264 7036 m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
jamie@264 7037 captureExpression();
jamie@264 7038 }
jamie@264 7039
jamie@264 7040 void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
jamie@264 7041 m_assertionInfo.resultDisposition = resultDisposition;
jamie@264 7042 m_stream.oss << Catch::translateActiveException();
jamie@264 7043 captureResult( ResultWas::ThrewException );
jamie@264 7044 }
jamie@264 7045
jamie@264 7046 void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
jamie@264 7047 setResultType( resultType );
jamie@264 7048 captureExpression();
jamie@264 7049 }
jamie@264 7050
jamie@264 7051 void ResultBuilder::captureExpression() {
jamie@264 7052 AssertionResult result = build();
jamie@264 7053 getResultCapture().assertionEnded( result );
jamie@264 7054
jamie@264 7055 if( !result.isOk() ) {
jamie@264 7056 if( getCurrentContext().getConfig()->shouldDebugBreak() )
jamie@264 7057 m_shouldDebugBreak = true;
jamie@264 7058 if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal )
jamie@264 7059 m_shouldThrow = true;
jamie@264 7060 }
jamie@264 7061 }
jamie@264 7062 void ResultBuilder::react() {
jamie@264 7063 if( m_shouldThrow )
jamie@264 7064 throw Catch::TestFailureException();
jamie@264 7065 }
jamie@264 7066
jamie@264 7067 bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
jamie@264 7068 bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
jamie@264 7069
jamie@264 7070 AssertionResult ResultBuilder::build() const
jamie@264 7071 {
jamie@264 7072 assert( m_data.resultType != ResultWas::Unknown );
jamie@264 7073
jamie@264 7074 AssertionResultData data = m_data;
jamie@264 7075
jamie@264 7076 // Flip bool results if testFalse is set
jamie@264 7077 if( m_exprComponents.testFalse ) {
jamie@264 7078 if( data.resultType == ResultWas::Ok )
jamie@264 7079 data.resultType = ResultWas::ExpressionFailed;
jamie@264 7080 else if( data.resultType == ResultWas::ExpressionFailed )
jamie@264 7081 data.resultType = ResultWas::Ok;
jamie@264 7082 }
jamie@264 7083
jamie@264 7084 data.message = m_stream.oss.str();
jamie@264 7085 data.reconstructedExpression = reconstructExpression();
jamie@264 7086 if( m_exprComponents.testFalse ) {
jamie@264 7087 if( m_exprComponents.op == "" )
jamie@264 7088 data.reconstructedExpression = "!" + data.reconstructedExpression;
jamie@264 7089 else
jamie@264 7090 data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
jamie@264 7091 }
jamie@264 7092 return AssertionResult( m_assertionInfo, data );
jamie@264 7093 }
jamie@264 7094 std::string ResultBuilder::reconstructExpression() const {
jamie@264 7095 if( m_exprComponents.op == "" )
jamie@264 7096 return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
jamie@264 7097 else if( m_exprComponents.op == "matches" )
jamie@264 7098 return m_exprComponents.lhs + " " + m_exprComponents.rhs;
jamie@264 7099 else if( m_exprComponents.op != "!" ) {
jamie@264 7100 if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
jamie@264 7101 m_exprComponents.lhs.find("\n") == std::string::npos &&
jamie@264 7102 m_exprComponents.rhs.find("\n") == std::string::npos )
jamie@264 7103 return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
jamie@264 7104 else
jamie@264 7105 return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
jamie@264 7106 }
jamie@264 7107 else
jamie@264 7108 return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
jamie@264 7109 }
jamie@264 7110
jamie@264 7111 } // end namespace Catch
jamie@264 7112
jamie@264 7113 // #included from: catch_tag_alias_registry.hpp
jamie@264 7114 #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
jamie@264 7115
jamie@264 7116 // #included from: catch_tag_alias_registry.h
jamie@264 7117 #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
jamie@264 7118
jamie@264 7119 #include <map>
jamie@264 7120
jamie@264 7121 namespace Catch {
jamie@264 7122
jamie@264 7123 class TagAliasRegistry : public ITagAliasRegistry {
jamie@264 7124 public:
jamie@264 7125 virtual ~TagAliasRegistry();
jamie@264 7126 virtual Option<TagAlias> find( std::string const& alias ) const;
jamie@264 7127 virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
jamie@264 7128 void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
jamie@264 7129 static TagAliasRegistry& get();
jamie@264 7130
jamie@264 7131 private:
jamie@264 7132 std::map<std::string, TagAlias> m_registry;
jamie@264 7133 };
jamie@264 7134
jamie@264 7135 } // end namespace Catch
jamie@264 7136
jamie@264 7137 #include <map>
jamie@264 7138 #include <iostream>
jamie@264 7139
jamie@264 7140 namespace Catch {
jamie@264 7141
jamie@264 7142 TagAliasRegistry::~TagAliasRegistry() {}
jamie@264 7143
jamie@264 7144 Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
jamie@264 7145 std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
jamie@264 7146 if( it != m_registry.end() )
jamie@264 7147 return it->second;
jamie@264 7148 else
jamie@264 7149 return Option<TagAlias>();
jamie@264 7150 }
jamie@264 7151
jamie@264 7152 std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
jamie@264 7153 std::string expandedTestSpec = unexpandedTestSpec;
jamie@264 7154 for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
jamie@264 7155 it != itEnd;
jamie@264 7156 ++it ) {
jamie@264 7157 std::size_t pos = expandedTestSpec.find( it->first );
jamie@264 7158 if( pos != std::string::npos ) {
jamie@264 7159 expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
jamie@264 7160 it->second.tag +
jamie@264 7161 expandedTestSpec.substr( pos + it->first.size() );
jamie@264 7162 }
jamie@264 7163 }
jamie@264 7164 return expandedTestSpec;
jamie@264 7165 }
jamie@264 7166
jamie@264 7167 void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
jamie@264 7168
jamie@264 7169 if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
jamie@264 7170 std::ostringstream oss;
jamie@264 7171 oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
jamie@264 7172 throw std::domain_error( oss.str().c_str() );
jamie@264 7173 }
jamie@264 7174 if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
jamie@264 7175 std::ostringstream oss;
jamie@264 7176 oss << "error: tag alias, \"" << alias << "\" already registered.\n"
jamie@264 7177 << "\tFirst seen at " << find(alias)->lineInfo << "\n"
jamie@264 7178 << "\tRedefined at " << lineInfo;
jamie@264 7179 throw std::domain_error( oss.str().c_str() );
jamie@264 7180 }
jamie@264 7181 }
jamie@264 7182
jamie@264 7183 TagAliasRegistry& TagAliasRegistry::get() {
jamie@264 7184 static TagAliasRegistry instance;
jamie@264 7185 return instance;
jamie@264 7186
jamie@264 7187 }
jamie@264 7188
jamie@264 7189 ITagAliasRegistry::~ITagAliasRegistry() {}
jamie@264 7190 ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
jamie@264 7191
jamie@264 7192 RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
jamie@264 7193 try {
jamie@264 7194 TagAliasRegistry::get().add( alias, tag, lineInfo );
jamie@264 7195 }
jamie@264 7196 catch( std::exception& ex ) {
jamie@264 7197 Colour colourGuard( Colour::Red );
jamie@264 7198 std::cerr << ex.what() << std::endl;
jamie@264 7199 exit(1);
jamie@264 7200 }
jamie@264 7201 }
jamie@264 7202
jamie@264 7203 } // end namespace Catch
jamie@264 7204
jamie@264 7205 // #included from: ../reporters/catch_reporter_xml.hpp
jamie@264 7206 #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
jamie@264 7207
jamie@264 7208 // #included from: catch_reporter_bases.hpp
jamie@264 7209 #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
jamie@264 7210
jamie@264 7211 namespace Catch {
jamie@264 7212
jamie@264 7213 struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
jamie@264 7214
jamie@264 7215 StreamingReporterBase( ReporterConfig const& _config )
jamie@264 7216 : m_config( _config.fullConfig() ),
jamie@264 7217 stream( _config.stream() )
jamie@264 7218 {}
jamie@264 7219
jamie@264 7220 virtual ~StreamingReporterBase();
jamie@264 7221
jamie@264 7222 virtual void noMatchingTestCases( std::string const& ) {}
jamie@264 7223
jamie@264 7224 virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
jamie@264 7225 currentTestRunInfo = _testRunInfo;
jamie@264 7226 }
jamie@264 7227 virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
jamie@264 7228 currentGroupInfo = _groupInfo;
jamie@264 7229 }
jamie@264 7230
jamie@264 7231 virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
jamie@264 7232 currentTestCaseInfo = _testInfo;
jamie@264 7233 }
jamie@264 7234 virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
jamie@264 7235 m_sectionStack.push_back( _sectionInfo );
jamie@264 7236 }
jamie@264 7237
jamie@264 7238 virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
jamie@264 7239 m_sectionStack.pop_back();
jamie@264 7240 }
jamie@264 7241 virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
jamie@264 7242 currentTestCaseInfo.reset();
jamie@264 7243 assert( m_sectionStack.empty() );
jamie@264 7244 }
jamie@264 7245 virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
jamie@264 7246 currentGroupInfo.reset();
jamie@264 7247 }
jamie@264 7248 virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
jamie@264 7249 currentTestCaseInfo.reset();
jamie@264 7250 currentGroupInfo.reset();
jamie@264 7251 currentTestRunInfo.reset();
jamie@264 7252 }
jamie@264 7253
jamie@264 7254 Ptr<IConfig> m_config;
jamie@264 7255 std::ostream& stream;
jamie@264 7256
jamie@264 7257 LazyStat<TestRunInfo> currentTestRunInfo;
jamie@264 7258 LazyStat<GroupInfo> currentGroupInfo;
jamie@264 7259 LazyStat<TestCaseInfo> currentTestCaseInfo;
jamie@264 7260
jamie@264 7261 std::vector<SectionInfo> m_sectionStack;
jamie@264 7262 };
jamie@264 7263
jamie@264 7264 struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
jamie@264 7265 template<typename T, typename ChildNodeT>
jamie@264 7266 struct Node : SharedImpl<> {
jamie@264 7267 explicit Node( T const& _value ) : value( _value ) {}
jamie@264 7268 virtual ~Node() {}
jamie@264 7269
jamie@264 7270 typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
jamie@264 7271 T value;
jamie@264 7272 ChildNodes children;
jamie@264 7273 };
jamie@264 7274 struct SectionNode : SharedImpl<> {
jamie@264 7275 explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
jamie@264 7276 virtual ~SectionNode();
jamie@264 7277
jamie@264 7278 bool operator == ( SectionNode const& other ) const {
jamie@264 7279 return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
jamie@264 7280 }
jamie@264 7281 bool operator == ( Ptr<SectionNode> const& other ) const {
jamie@264 7282 return operator==( *other );
jamie@264 7283 }
jamie@264 7284
jamie@264 7285 SectionStats stats;
jamie@264 7286 typedef std::vector<Ptr<SectionNode> > ChildSections;
jamie@264 7287 typedef std::vector<AssertionStats> Assertions;
jamie@264 7288 ChildSections childSections;
jamie@264 7289 Assertions assertions;
jamie@264 7290 std::string stdOut;
jamie@264 7291 std::string stdErr;
jamie@264 7292 };
jamie@264 7293
jamie@264 7294 struct BySectionInfo {
jamie@264 7295 BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
jamie@264 7296 BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
jamie@264 7297 bool operator() ( Ptr<SectionNode> const& node ) const {
jamie@264 7298 return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
jamie@264 7299 }
jamie@264 7300 private:
jamie@264 7301 void operator=( BySectionInfo const& );
jamie@264 7302 SectionInfo const& m_other;
jamie@264 7303 };
jamie@264 7304
jamie@264 7305 typedef Node<TestCaseStats, SectionNode> TestCaseNode;
jamie@264 7306 typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
jamie@264 7307 typedef Node<TestRunStats, TestGroupNode> TestRunNode;
jamie@264 7308
jamie@264 7309 CumulativeReporterBase( ReporterConfig const& _config )
jamie@264 7310 : m_config( _config.fullConfig() ),
jamie@264 7311 stream( _config.stream() )
jamie@264 7312 {}
jamie@264 7313 ~CumulativeReporterBase();
jamie@264 7314
jamie@264 7315 virtual void testRunStarting( TestRunInfo const& ) {}
jamie@264 7316 virtual void testGroupStarting( GroupInfo const& ) {}
jamie@264 7317
jamie@264 7318 virtual void testCaseStarting( TestCaseInfo const& ) {}
jamie@264 7319
jamie@264 7320 virtual void sectionStarting( SectionInfo const& sectionInfo ) {
jamie@264 7321 SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
jamie@264 7322 Ptr<SectionNode> node;
jamie@264 7323 if( m_sectionStack.empty() ) {
jamie@264 7324 if( !m_rootSection )
jamie@264 7325 m_rootSection = new SectionNode( incompleteStats );
jamie@264 7326 node = m_rootSection;
jamie@264 7327 }
jamie@264 7328 else {
jamie@264 7329 SectionNode& parentNode = *m_sectionStack.back();
jamie@264 7330 SectionNode::ChildSections::const_iterator it =
jamie@264 7331 std::find_if( parentNode.childSections.begin(),
jamie@264 7332 parentNode.childSections.end(),
jamie@264 7333 BySectionInfo( sectionInfo ) );
jamie@264 7334 if( it == parentNode.childSections.end() ) {
jamie@264 7335 node = new SectionNode( incompleteStats );
jamie@264 7336 parentNode.childSections.push_back( node );
jamie@264 7337 }
jamie@264 7338 else
jamie@264 7339 node = *it;
jamie@264 7340 }
jamie@264 7341 m_sectionStack.push_back( node );
jamie@264 7342 m_deepestSection = node;
jamie@264 7343 }
jamie@264 7344
jamie@264 7345 virtual void assertionStarting( AssertionInfo const& ) {}
jamie@264 7346
jamie@264 7347 virtual bool assertionEnded( AssertionStats const& assertionStats ) {
jamie@264 7348 assert( !m_sectionStack.empty() );
jamie@264 7349 SectionNode& sectionNode = *m_sectionStack.back();
jamie@264 7350 sectionNode.assertions.push_back( assertionStats );
jamie@264 7351 return true;
jamie@264 7352 }
jamie@264 7353 virtual void sectionEnded( SectionStats const& sectionStats ) {
jamie@264 7354 assert( !m_sectionStack.empty() );
jamie@264 7355 SectionNode& node = *m_sectionStack.back();
jamie@264 7356 node.stats = sectionStats;
jamie@264 7357 m_sectionStack.pop_back();
jamie@264 7358 }
jamie@264 7359 virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
jamie@264 7360 Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
jamie@264 7361 assert( m_sectionStack.size() == 0 );
jamie@264 7362 node->children.push_back( m_rootSection );
jamie@264 7363 m_testCases.push_back( node );
jamie@264 7364 m_rootSection.reset();
jamie@264 7365
jamie@264 7366 assert( m_deepestSection );
jamie@264 7367 m_deepestSection->stdOut = testCaseStats.stdOut;
jamie@264 7368 m_deepestSection->stdErr = testCaseStats.stdErr;
jamie@264 7369 }
jamie@264 7370 virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
jamie@264 7371 Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
jamie@264 7372 node->children.swap( m_testCases );
jamie@264 7373 m_testGroups.push_back( node );
jamie@264 7374 }
jamie@264 7375 virtual void testRunEnded( TestRunStats const& testRunStats ) {
jamie@264 7376 Ptr<TestRunNode> node = new TestRunNode( testRunStats );
jamie@264 7377 node->children.swap( m_testGroups );
jamie@264 7378 m_testRuns.push_back( node );
jamie@264 7379 testRunEndedCumulative();
jamie@264 7380 }
jamie@264 7381 virtual void testRunEndedCumulative() = 0;
jamie@264 7382
jamie@264 7383 Ptr<IConfig> m_config;
jamie@264 7384 std::ostream& stream;
jamie@264 7385 std::vector<AssertionStats> m_assertions;
jamie@264 7386 std::vector<std::vector<Ptr<SectionNode> > > m_sections;
jamie@264 7387 std::vector<Ptr<TestCaseNode> > m_testCases;
jamie@264 7388 std::vector<Ptr<TestGroupNode> > m_testGroups;
jamie@264 7389
jamie@264 7390 std::vector<Ptr<TestRunNode> > m_testRuns;
jamie@264 7391
jamie@264 7392 Ptr<SectionNode> m_rootSection;
jamie@264 7393 Ptr<SectionNode> m_deepestSection;
jamie@264 7394 std::vector<Ptr<SectionNode> > m_sectionStack;
jamie@264 7395
jamie@264 7396 };
jamie@264 7397
jamie@264 7398 } // end namespace Catch
jamie@264 7399
jamie@264 7400 // #included from: ../internal/catch_reporter_registrars.hpp
jamie@264 7401 #define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
jamie@264 7402
jamie@264 7403 namespace Catch {
jamie@264 7404
jamie@264 7405 template<typename T>
jamie@264 7406 class LegacyReporterRegistrar {
jamie@264 7407
jamie@264 7408 class ReporterFactory : public IReporterFactory {
jamie@264 7409 virtual IStreamingReporter* create( ReporterConfig const& config ) const {
jamie@264 7410 return new LegacyReporterAdapter( new T( config ) );
jamie@264 7411 }
jamie@264 7412
jamie@264 7413 virtual std::string getDescription() const {
jamie@264 7414 return T::getDescription();
jamie@264 7415 }
jamie@264 7416 };
jamie@264 7417
jamie@264 7418 public:
jamie@264 7419
jamie@264 7420 LegacyReporterRegistrar( std::string const& name ) {
jamie@264 7421 getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
jamie@264 7422 }
jamie@264 7423 };
jamie@264 7424
jamie@264 7425 template<typename T>
jamie@264 7426 class ReporterRegistrar {
jamie@264 7427
jamie@264 7428 class ReporterFactory : public IReporterFactory {
jamie@264 7429
jamie@264 7430 // *** Please Note ***:
jamie@264 7431 // - If you end up here looking at a compiler error because it's trying to register
jamie@264 7432 // your custom reporter class be aware that the native reporter interface has changed
jamie@264 7433 // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
jamie@264 7434 // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
jamie@264 7435 // However please consider updating to the new interface as the old one is now
jamie@264 7436 // deprecated and will probably be removed quite soon!
jamie@264 7437 // Please contact me via github if you have any questions at all about this.
jamie@264 7438 // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
jamie@264 7439 // no idea who is actually using custom reporters at all (possibly no-one!).
jamie@264 7440 // The new interface is designed to minimise exposure to interface changes in the future.
jamie@264 7441 virtual IStreamingReporter* create( ReporterConfig const& config ) const {
jamie@264 7442 return new T( config );
jamie@264 7443 }
jamie@264 7444
jamie@264 7445 virtual std::string getDescription() const {
jamie@264 7446 return T::getDescription();
jamie@264 7447 }
jamie@264 7448 };
jamie@264 7449
jamie@264 7450 public:
jamie@264 7451
jamie@264 7452 ReporterRegistrar( std::string const& name ) {
jamie@264 7453 getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
jamie@264 7454 }
jamie@264 7455 };
jamie@264 7456 }
jamie@264 7457
jamie@264 7458 #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
jamie@264 7459 namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
jamie@264 7460 #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
jamie@264 7461 namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
jamie@264 7462
jamie@264 7463 // #included from: ../internal/catch_xmlwriter.hpp
jamie@264 7464 #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
jamie@264 7465
jamie@264 7466 #include <sstream>
jamie@264 7467 #include <iostream>
jamie@264 7468 #include <string>
jamie@264 7469 #include <vector>
jamie@264 7470
jamie@264 7471 namespace Catch {
jamie@264 7472
jamie@264 7473 class XmlWriter {
jamie@264 7474 public:
jamie@264 7475
jamie@264 7476 class ScopedElement {
jamie@264 7477 public:
jamie@264 7478 ScopedElement( XmlWriter* writer )
jamie@264 7479 : m_writer( writer )
jamie@264 7480 {}
jamie@264 7481
jamie@264 7482 ScopedElement( ScopedElement const& other )
jamie@264 7483 : m_writer( other.m_writer ){
jamie@264 7484 other.m_writer = NULL;
jamie@264 7485 }
jamie@264 7486
jamie@264 7487 ~ScopedElement() {
jamie@264 7488 if( m_writer )
jamie@264 7489 m_writer->endElement();
jamie@264 7490 }
jamie@264 7491
jamie@264 7492 ScopedElement& writeText( std::string const& text, bool indent = true ) {
jamie@264 7493 m_writer->writeText( text, indent );
jamie@264 7494 return *this;
jamie@264 7495 }
jamie@264 7496
jamie@264 7497 template<typename T>
jamie@264 7498 ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
jamie@264 7499 m_writer->writeAttribute( name, attribute );
jamie@264 7500 return *this;
jamie@264 7501 }
jamie@264 7502
jamie@264 7503 private:
jamie@264 7504 mutable XmlWriter* m_writer;
jamie@264 7505 };
jamie@264 7506
jamie@264 7507 XmlWriter()
jamie@264 7508 : m_tagIsOpen( false ),
jamie@264 7509 m_needsNewline( false ),
jamie@264 7510 m_os( &std::cout )
jamie@264 7511 {}
jamie@264 7512
jamie@264 7513 XmlWriter( std::ostream& os )
jamie@264 7514 : m_tagIsOpen( false ),
jamie@264 7515 m_needsNewline( false ),
jamie@264 7516 m_os( &os )
jamie@264 7517 {}
jamie@264 7518
jamie@264 7519 ~XmlWriter() {
jamie@264 7520 while( !m_tags.empty() )
jamie@264 7521 endElement();
jamie@264 7522 }
jamie@264 7523
jamie@264 7524 //# ifndef CATCH_CPP11_OR_GREATER
jamie@264 7525 // XmlWriter& operator = ( XmlWriter const& other ) {
jamie@264 7526 // XmlWriter temp( other );
jamie@264 7527 // swap( temp );
jamie@264 7528 // return *this;
jamie@264 7529 // }
jamie@264 7530 //# else
jamie@264 7531 // XmlWriter( XmlWriter const& ) = default;
jamie@264 7532 // XmlWriter( XmlWriter && ) = default;
jamie@264 7533 // XmlWriter& operator = ( XmlWriter const& ) = default;
jamie@264 7534 // XmlWriter& operator = ( XmlWriter && ) = default;
jamie@264 7535 //# endif
jamie@264 7536 //
jamie@264 7537 // void swap( XmlWriter& other ) {
jamie@264 7538 // std::swap( m_tagIsOpen, other.m_tagIsOpen );
jamie@264 7539 // std::swap( m_needsNewline, other.m_needsNewline );
jamie@264 7540 // std::swap( m_tags, other.m_tags );
jamie@264 7541 // std::swap( m_indent, other.m_indent );
jamie@264 7542 // std::swap( m_os, other.m_os );
jamie@264 7543 // }
jamie@264 7544
jamie@264 7545 XmlWriter& startElement( std::string const& name ) {
jamie@264 7546 ensureTagClosed();
jamie@264 7547 newlineIfNecessary();
jamie@264 7548 stream() << m_indent << "<" << name;
jamie@264 7549 m_tags.push_back( name );
jamie@264 7550 m_indent += " ";
jamie@264 7551 m_tagIsOpen = true;
jamie@264 7552 return *this;
jamie@264 7553 }
jamie@264 7554
jamie@264 7555 ScopedElement scopedElement( std::string const& name ) {
jamie@264 7556 ScopedElement scoped( this );
jamie@264 7557 startElement( name );
jamie@264 7558 return scoped;
jamie@264 7559 }
jamie@264 7560
jamie@264 7561 XmlWriter& endElement() {
jamie@264 7562 newlineIfNecessary();
jamie@264 7563 m_indent = m_indent.substr( 0, m_indent.size()-2 );
jamie@264 7564 if( m_tagIsOpen ) {
jamie@264 7565 stream() << "/>\n";
jamie@264 7566 m_tagIsOpen = false;
jamie@264 7567 }
jamie@264 7568 else {
jamie@264 7569 stream() << m_indent << "</" << m_tags.back() << ">\n";
jamie@264 7570 }
jamie@264 7571 m_tags.pop_back();
jamie@264 7572 return *this;
jamie@264 7573 }
jamie@264 7574
jamie@264 7575 XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
jamie@264 7576 if( !name.empty() && !attribute.empty() ) {
jamie@264 7577 stream() << " " << name << "=\"";
jamie@264 7578 writeEncodedText( attribute );
jamie@264 7579 stream() << "\"";
jamie@264 7580 }
jamie@264 7581 return *this;
jamie@264 7582 }
jamie@264 7583
jamie@264 7584 XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
jamie@264 7585 stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
jamie@264 7586 return *this;
jamie@264 7587 }
jamie@264 7588
jamie@264 7589 template<typename T>
jamie@264 7590 XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
jamie@264 7591 if( !name.empty() )
jamie@264 7592 stream() << " " << name << "=\"" << attribute << "\"";
jamie@264 7593 return *this;
jamie@264 7594 }
jamie@264 7595
jamie@264 7596 XmlWriter& writeText( std::string const& text, bool indent = true ) {
jamie@264 7597 if( !text.empty() ){
jamie@264 7598 bool tagWasOpen = m_tagIsOpen;
jamie@264 7599 ensureTagClosed();
jamie@264 7600 if( tagWasOpen && indent )
jamie@264 7601 stream() << m_indent;
jamie@264 7602 writeEncodedText( text );
jamie@264 7603 m_needsNewline = true;
jamie@264 7604 }
jamie@264 7605 return *this;
jamie@264 7606 }
jamie@264 7607
jamie@264 7608 XmlWriter& writeComment( std::string const& text ) {
jamie@264 7609 ensureTagClosed();
jamie@264 7610 stream() << m_indent << "<!--" << text << "-->";
jamie@264 7611 m_needsNewline = true;
jamie@264 7612 return *this;
jamie@264 7613 }
jamie@264 7614
jamie@264 7615 XmlWriter& writeBlankLine() {
jamie@264 7616 ensureTagClosed();
jamie@264 7617 stream() << "\n";
jamie@264 7618 return *this;
jamie@264 7619 }
jamie@264 7620
jamie@264 7621 void setStream( std::ostream& os ) {
jamie@264 7622 m_os = &os;
jamie@264 7623 }
jamie@264 7624
jamie@264 7625 private:
jamie@264 7626 XmlWriter( XmlWriter const& );
jamie@264 7627 void operator=( XmlWriter const& );
jamie@264 7628
jamie@264 7629 std::ostream& stream() {
jamie@264 7630 return *m_os;
jamie@264 7631 }
jamie@264 7632
jamie@264 7633 void ensureTagClosed() {
jamie@264 7634 if( m_tagIsOpen ) {
jamie@264 7635 stream() << ">\n";
jamie@264 7636 m_tagIsOpen = false;
jamie@264 7637 }
jamie@264 7638 }
jamie@264 7639
jamie@264 7640 void newlineIfNecessary() {
jamie@264 7641 if( m_needsNewline ) {
jamie@264 7642 stream() << "\n";
jamie@264 7643 m_needsNewline = false;
jamie@264 7644 }
jamie@264 7645 }
jamie@264 7646
jamie@264 7647 void writeEncodedText( std::string const& text ) {
jamie@264 7648 static const char* charsToEncode = "<&\"";
jamie@264 7649 std::string mtext = text;
jamie@264 7650 std::string::size_type pos = mtext.find_first_of( charsToEncode );
jamie@264 7651 while( pos != std::string::npos ) {
jamie@264 7652 stream() << mtext.substr( 0, pos );
jamie@264 7653
jamie@264 7654 switch( mtext[pos] ) {
jamie@264 7655 case '<':
jamie@264 7656 stream() << "&lt;";
jamie@264 7657 break;
jamie@264 7658 case '&':
jamie@264 7659 stream() << "&amp;";
jamie@264 7660 break;
jamie@264 7661 case '\"':
jamie@264 7662 stream() << "&quot;";
jamie@264 7663 break;
jamie@264 7664 }
jamie@264 7665 mtext = mtext.substr( pos+1 );
jamie@264 7666 pos = mtext.find_first_of( charsToEncode );
jamie@264 7667 }
jamie@264 7668 stream() << mtext;
jamie@264 7669 }
jamie@264 7670
jamie@264 7671 bool m_tagIsOpen;
jamie@264 7672 bool m_needsNewline;
jamie@264 7673 std::vector<std::string> m_tags;
jamie@264 7674 std::string m_indent;
jamie@264 7675 std::ostream* m_os;
jamie@264 7676 };
jamie@264 7677
jamie@264 7678 }
jamie@264 7679 namespace Catch {
jamie@264 7680 class XmlReporter : public SharedImpl<IReporter> {
jamie@264 7681 public:
jamie@264 7682 XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {}
jamie@264 7683
jamie@264 7684 static std::string getDescription() {
jamie@264 7685 return "Reports test results as an XML document";
jamie@264 7686 }
jamie@264 7687 virtual ~XmlReporter();
jamie@264 7688
jamie@264 7689 private: // IReporter
jamie@264 7690
jamie@264 7691 virtual bool shouldRedirectStdout() const {
jamie@264 7692 return true;
jamie@264 7693 }
jamie@264 7694
jamie@264 7695 virtual void StartTesting() {
jamie@264 7696 m_xml.setStream( m_config.stream() );
jamie@264 7697 m_xml.startElement( "Catch" );
jamie@264 7698 if( !m_config.fullConfig()->name().empty() )
jamie@264 7699 m_xml.writeAttribute( "name", m_config.fullConfig()->name() );
jamie@264 7700 }
jamie@264 7701
jamie@264 7702 virtual void EndTesting( const Totals& totals ) {
jamie@264 7703 m_xml.scopedElement( "OverallResults" )
jamie@264 7704 .writeAttribute( "successes", totals.assertions.passed )
jamie@264 7705 .writeAttribute( "failures", totals.assertions.failed )
jamie@264 7706 .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
jamie@264 7707 m_xml.endElement();
jamie@264 7708 }
jamie@264 7709
jamie@264 7710 virtual void StartGroup( const std::string& groupName ) {
jamie@264 7711 m_xml.startElement( "Group" )
jamie@264 7712 .writeAttribute( "name", groupName );
jamie@264 7713 }
jamie@264 7714
jamie@264 7715 virtual void EndGroup( const std::string&, const Totals& totals ) {
jamie@264 7716 m_xml.scopedElement( "OverallResults" )
jamie@264 7717 .writeAttribute( "successes", totals.assertions.passed )
jamie@264 7718 .writeAttribute( "failures", totals.assertions.failed )
jamie@264 7719 .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
jamie@264 7720 m_xml.endElement();
jamie@264 7721 }
jamie@264 7722
jamie@264 7723 virtual void StartSection( const std::string& sectionName, const std::string& description ) {
jamie@264 7724 if( m_sectionDepth++ > 0 ) {
jamie@264 7725 m_xml.startElement( "Section" )
jamie@264 7726 .writeAttribute( "name", trim( sectionName ) )
jamie@264 7727 .writeAttribute( "description", description );
jamie@264 7728 }
jamie@264 7729 }
jamie@264 7730 virtual void NoAssertionsInSection( const std::string& ) {}
jamie@264 7731 virtual void NoAssertionsInTestCase( const std::string& ) {}
jamie@264 7732
jamie@264 7733 virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
jamie@264 7734 if( --m_sectionDepth > 0 ) {
jamie@264 7735 m_xml.scopedElement( "OverallResults" )
jamie@264 7736 .writeAttribute( "successes", assertions.passed )
jamie@264 7737 .writeAttribute( "failures", assertions.failed )
jamie@264 7738 .writeAttribute( "expectedFailures", assertions.failedButOk );
jamie@264 7739 m_xml.endElement();
jamie@264 7740 }
jamie@264 7741 }
jamie@264 7742
jamie@264 7743 virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
jamie@264 7744 m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
jamie@264 7745 m_currentTestSuccess = true;
jamie@264 7746 }
jamie@264 7747
jamie@264 7748 virtual void Result( const Catch::AssertionResult& assertionResult ) {
jamie@264 7749 if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok )
jamie@264 7750 return;
jamie@264 7751
jamie@264 7752 if( assertionResult.hasExpression() ) {
jamie@264 7753 m_xml.startElement( "Expression" )
jamie@264 7754 .writeAttribute( "success", assertionResult.succeeded() )
jamie@264 7755 .writeAttribute( "filename", assertionResult.getSourceInfo().file )
jamie@264 7756 .writeAttribute( "line", assertionResult.getSourceInfo().line );
jamie@264 7757
jamie@264 7758 m_xml.scopedElement( "Original" )
jamie@264 7759 .writeText( assertionResult.getExpression() );
jamie@264 7760 m_xml.scopedElement( "Expanded" )
jamie@264 7761 .writeText( assertionResult.getExpandedExpression() );
jamie@264 7762 m_currentTestSuccess &= assertionResult.succeeded();
jamie@264 7763 }
jamie@264 7764
jamie@264 7765 switch( assertionResult.getResultType() ) {
jamie@264 7766 case ResultWas::ThrewException:
jamie@264 7767 m_xml.scopedElement( "Exception" )
jamie@264 7768 .writeAttribute( "filename", assertionResult.getSourceInfo().file )
jamie@264 7769 .writeAttribute( "line", assertionResult.getSourceInfo().line )
jamie@264 7770 .writeText( assertionResult.getMessage() );
jamie@264 7771 m_currentTestSuccess = false;
jamie@264 7772 break;
jamie@264 7773 case ResultWas::Info:
jamie@264 7774 m_xml.scopedElement( "Info" )
jamie@264 7775 .writeText( assertionResult.getMessage() );
jamie@264 7776 break;
jamie@264 7777 case ResultWas::Warning:
jamie@264 7778 m_xml.scopedElement( "Warning" )
jamie@264 7779 .writeText( assertionResult.getMessage() );
jamie@264 7780 break;
jamie@264 7781 case ResultWas::ExplicitFailure:
jamie@264 7782 m_xml.scopedElement( "Failure" )
jamie@264 7783 .writeText( assertionResult.getMessage() );
jamie@264 7784 m_currentTestSuccess = false;
jamie@264 7785 break;
jamie@264 7786 case ResultWas::Unknown:
jamie@264 7787 case ResultWas::Ok:
jamie@264 7788 case ResultWas::FailureBit:
jamie@264 7789 case ResultWas::ExpressionFailed:
jamie@264 7790 case ResultWas::Exception:
jamie@264 7791 case ResultWas::DidntThrowException:
jamie@264 7792 break;
jamie@264 7793 }
jamie@264 7794 if( assertionResult.hasExpression() )
jamie@264 7795 m_xml.endElement();
jamie@264 7796 }
jamie@264 7797
jamie@264 7798 virtual void Aborted() {
jamie@264 7799 // !TBD
jamie@264 7800 }
jamie@264 7801
jamie@264 7802 virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
jamie@264 7803 m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
jamie@264 7804 m_xml.endElement();
jamie@264 7805 }
jamie@264 7806
jamie@264 7807 private:
jamie@264 7808 ReporterConfig m_config;
jamie@264 7809 bool m_currentTestSuccess;
jamie@264 7810 XmlWriter m_xml;
jamie@264 7811 int m_sectionDepth;
jamie@264 7812 };
jamie@264 7813
jamie@264 7814 } // end namespace Catch
jamie@264 7815
jamie@264 7816 // #included from: ../reporters/catch_reporter_junit.hpp
jamie@264 7817 #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
jamie@264 7818
jamie@264 7819 #include <assert.h>
jamie@264 7820
jamie@264 7821 namespace Catch {
jamie@264 7822
jamie@264 7823 class JunitReporter : public CumulativeReporterBase {
jamie@264 7824 public:
jamie@264 7825 JunitReporter( ReporterConfig const& _config )
jamie@264 7826 : CumulativeReporterBase( _config ),
jamie@264 7827 xml( _config.stream() )
jamie@264 7828 {}
jamie@264 7829
jamie@264 7830 ~JunitReporter();
jamie@264 7831
jamie@264 7832 static std::string getDescription() {
jamie@264 7833 return "Reports test results in an XML format that looks like Ant's junitreport target";
jamie@264 7834 }
jamie@264 7835
jamie@264 7836 virtual void noMatchingTestCases( std::string const& /*spec*/ ) {}
jamie@264 7837
jamie@264 7838 virtual ReporterPreferences getPreferences() const {
jamie@264 7839 ReporterPreferences prefs;
jamie@264 7840 prefs.shouldRedirectStdOut = true;
jamie@264 7841 return prefs;
jamie@264 7842 }
jamie@264 7843
jamie@264 7844 virtual void testRunStarting( TestRunInfo const& runInfo ) {
jamie@264 7845 CumulativeReporterBase::testRunStarting( runInfo );
jamie@264 7846 xml.startElement( "testsuites" );
jamie@264 7847 }
jamie@264 7848
jamie@264 7849 virtual void testGroupStarting( GroupInfo const& groupInfo ) {
jamie@264 7850 suiteTimer.start();
jamie@264 7851 stdOutForSuite.str("");
jamie@264 7852 stdErrForSuite.str("");
jamie@264 7853 unexpectedExceptions = 0;
jamie@264 7854 CumulativeReporterBase::testGroupStarting( groupInfo );
jamie@264 7855 }
jamie@264 7856
jamie@264 7857 virtual bool assertionEnded( AssertionStats const& assertionStats ) {
jamie@264 7858 if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
jamie@264 7859 unexpectedExceptions++;
jamie@264 7860 return CumulativeReporterBase::assertionEnded( assertionStats );
jamie@264 7861 }
jamie@264 7862
jamie@264 7863 virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
jamie@264 7864 stdOutForSuite << testCaseStats.stdOut;
jamie@264 7865 stdErrForSuite << testCaseStats.stdErr;
jamie@264 7866 CumulativeReporterBase::testCaseEnded( testCaseStats );
jamie@264 7867 }
jamie@264 7868
jamie@264 7869 virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
jamie@264 7870 double suiteTime = suiteTimer.getElapsedSeconds();
jamie@264 7871 CumulativeReporterBase::testGroupEnded( testGroupStats );
jamie@264 7872 writeGroup( *m_testGroups.back(), suiteTime );
jamie@264 7873 }
jamie@264 7874
jamie@264 7875 virtual void testRunEndedCumulative() {
jamie@264 7876 xml.endElement();
jamie@264 7877 }
jamie@264 7878
jamie@264 7879 void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
jamie@264 7880 XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
jamie@264 7881 TestGroupStats const& stats = groupNode.value;
jamie@264 7882 xml.writeAttribute( "name", stats.groupInfo.name );
jamie@264 7883 xml.writeAttribute( "errors", unexpectedExceptions );
jamie@264 7884 xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
jamie@264 7885 xml.writeAttribute( "tests", stats.totals.assertions.total() );
jamie@264 7886 xml.writeAttribute( "hostname", "tbd" ); // !TBD
jamie@264 7887 if( m_config->showDurations() == ShowDurations::Never )
jamie@264 7888 xml.writeAttribute( "time", "" );
jamie@264 7889 else
jamie@264 7890 xml.writeAttribute( "time", suiteTime );
jamie@264 7891 xml.writeAttribute( "timestamp", "tbd" ); // !TBD
jamie@264 7892
jamie@264 7893 // Write test cases
jamie@264 7894 for( TestGroupNode::ChildNodes::const_iterator
jamie@264 7895 it = groupNode.children.begin(), itEnd = groupNode.children.end();
jamie@264 7896 it != itEnd;
jamie@264 7897 ++it )
jamie@264 7898 writeTestCase( **it );
jamie@264 7899
jamie@264 7900 xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
jamie@264 7901 xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
jamie@264 7902 }
jamie@264 7903
jamie@264 7904 void writeTestCase( TestCaseNode const& testCaseNode ) {
jamie@264 7905 TestCaseStats const& stats = testCaseNode.value;
jamie@264 7906
jamie@264 7907 // All test cases have exactly one section - which represents the
jamie@264 7908 // test case itself. That section may have 0-n nested sections
jamie@264 7909 assert( testCaseNode.children.size() == 1 );
jamie@264 7910 SectionNode const& rootSection = *testCaseNode.children.front();
jamie@264 7911
jamie@264 7912 std::string className = stats.testInfo.className;
jamie@264 7913
jamie@264 7914 if( className.empty() ) {
jamie@264 7915 if( rootSection.childSections.empty() )
jamie@264 7916 className = "global";
jamie@264 7917 }
jamie@264 7918 writeSection( className, "", rootSection );
jamie@264 7919 }
jamie@264 7920
jamie@264 7921 void writeSection( std::string const& className,
jamie@264 7922 std::string const& rootName,
jamie@264 7923 SectionNode const& sectionNode ) {
jamie@264 7924 std::string name = trim( sectionNode.stats.sectionInfo.name );
jamie@264 7925 if( !rootName.empty() )
jamie@264 7926 name = rootName + "/" + name;
jamie@264 7927
jamie@264 7928 if( !sectionNode.assertions.empty() ||
jamie@264 7929 !sectionNode.stdOut.empty() ||
jamie@264 7930 !sectionNode.stdErr.empty() ) {
jamie@264 7931 XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
jamie@264 7932 if( className.empty() ) {
jamie@264 7933 xml.writeAttribute( "classname", name );
jamie@264 7934 xml.writeAttribute( "name", "root" );
jamie@264 7935 }
jamie@264 7936 else {
jamie@264 7937 xml.writeAttribute( "classname", className );
jamie@264 7938 xml.writeAttribute( "name", name );
jamie@264 7939 }
jamie@264 7940 xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) );
jamie@264 7941
jamie@264 7942 writeAssertions( sectionNode );
jamie@264 7943
jamie@264 7944 if( !sectionNode.stdOut.empty() )
jamie@264 7945 xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
jamie@264 7946 if( !sectionNode.stdErr.empty() )
jamie@264 7947 xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
jamie@264 7948 }
jamie@264 7949 for( SectionNode::ChildSections::const_iterator
jamie@264 7950 it = sectionNode.childSections.begin(),
jamie@264 7951 itEnd = sectionNode.childSections.end();
jamie@264 7952 it != itEnd;
jamie@264 7953 ++it )
jamie@264 7954 if( className.empty() )
jamie@264 7955 writeSection( name, "", **it );
jamie@264 7956 else
jamie@264 7957 writeSection( className, name, **it );
jamie@264 7958 }
jamie@264 7959
jamie@264 7960 void writeAssertions( SectionNode const& sectionNode ) {
jamie@264 7961 for( SectionNode::Assertions::const_iterator
jamie@264 7962 it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
jamie@264 7963 it != itEnd;
jamie@264 7964 ++it )
jamie@264 7965 writeAssertion( *it );
jamie@264 7966 }
jamie@264 7967 void writeAssertion( AssertionStats const& stats ) {
jamie@264 7968 AssertionResult const& result = stats.assertionResult;
jamie@264 7969 if( !result.isOk() ) {
jamie@264 7970 std::string elementName;
jamie@264 7971 switch( result.getResultType() ) {
jamie@264 7972 case ResultWas::ThrewException:
jamie@264 7973 elementName = "error";
jamie@264 7974 break;
jamie@264 7975 case ResultWas::ExplicitFailure:
jamie@264 7976 elementName = "failure";
jamie@264 7977 break;
jamie@264 7978 case ResultWas::ExpressionFailed:
jamie@264 7979 elementName = "failure";
jamie@264 7980 break;
jamie@264 7981 case ResultWas::DidntThrowException:
jamie@264 7982 elementName = "failure";
jamie@264 7983 break;
jamie@264 7984
jamie@264 7985 // We should never see these here:
jamie@264 7986 case ResultWas::Info:
jamie@264 7987 case ResultWas::Warning:
jamie@264 7988 case ResultWas::Ok:
jamie@264 7989 case ResultWas::Unknown:
jamie@264 7990 case ResultWas::FailureBit:
jamie@264 7991 case ResultWas::Exception:
jamie@264 7992 elementName = "internalError";
jamie@264 7993 break;
jamie@264 7994 }
jamie@264 7995
jamie@264 7996 XmlWriter::ScopedElement e = xml.scopedElement( elementName );
jamie@264 7997
jamie@264 7998 xml.writeAttribute( "message", result.getExpandedExpression() );
jamie@264 7999 xml.writeAttribute( "type", result.getTestMacroName() );
jamie@264 8000
jamie@264 8001 std::ostringstream oss;
jamie@264 8002 if( !result.getMessage().empty() )
jamie@264 8003 oss << result.getMessage() << "\n";
jamie@264 8004 for( std::vector<MessageInfo>::const_iterator
jamie@264 8005 it = stats.infoMessages.begin(),
jamie@264 8006 itEnd = stats.infoMessages.end();
jamie@264 8007 it != itEnd;
jamie@264 8008 ++it )
jamie@264 8009 if( it->type == ResultWas::Info )
jamie@264 8010 oss << it->message << "\n";
jamie@264 8011
jamie@264 8012 oss << "at " << result.getSourceInfo();
jamie@264 8013 xml.writeText( oss.str(), false );
jamie@264 8014 }
jamie@264 8015 }
jamie@264 8016
jamie@264 8017 XmlWriter xml;
jamie@264 8018 Timer suiteTimer;
jamie@264 8019 std::ostringstream stdOutForSuite;
jamie@264 8020 std::ostringstream stdErrForSuite;
jamie@264 8021 unsigned int unexpectedExceptions;
jamie@264 8022 };
jamie@264 8023
jamie@264 8024 INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
jamie@264 8025
jamie@264 8026 } // end namespace Catch
jamie@264 8027
jamie@264 8028 // #included from: ../reporters/catch_reporter_console.hpp
jamie@264 8029 #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
jamie@264 8030
jamie@264 8031 #include <cstring>
jamie@264 8032
jamie@264 8033 namespace Catch {
jamie@264 8034
jamie@264 8035 struct ConsoleReporter : StreamingReporterBase {
jamie@264 8036 ConsoleReporter( ReporterConfig const& _config )
jamie@264 8037 : StreamingReporterBase( _config ),
jamie@264 8038 m_headerPrinted( false )
jamie@264 8039 {}
jamie@264 8040
jamie@264 8041 virtual ~ConsoleReporter();
jamie@264 8042 static std::string getDescription() {
jamie@264 8043 return "Reports test results as plain lines of text";
jamie@264 8044 }
jamie@264 8045 virtual ReporterPreferences getPreferences() const {
jamie@264 8046 ReporterPreferences prefs;
jamie@264 8047 prefs.shouldRedirectStdOut = false;
jamie@264 8048 return prefs;
jamie@264 8049 }
jamie@264 8050
jamie@264 8051 virtual void noMatchingTestCases( std::string const& spec ) {
jamie@264 8052 stream << "No test cases matched '" << spec << "'" << std::endl;
jamie@264 8053 }
jamie@264 8054
jamie@264 8055 virtual void assertionStarting( AssertionInfo const& ) {
jamie@264 8056 }
jamie@264 8057
jamie@264 8058 virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
jamie@264 8059 AssertionResult const& result = _assertionStats.assertionResult;
jamie@264 8060
jamie@264 8061 bool printInfoMessages = true;
jamie@264 8062
jamie@264 8063 // Drop out if result was successful and we're not printing those
jamie@264 8064 if( !m_config->includeSuccessfulResults() && result.isOk() ) {
jamie@264 8065 if( result.getResultType() != ResultWas::Warning )
jamie@264 8066 return false;
jamie@264 8067 printInfoMessages = false;
jamie@264 8068 }
jamie@264 8069
jamie@264 8070 lazyPrint();
jamie@264 8071
jamie@264 8072 AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
jamie@264 8073 printer.print();
jamie@264 8074 stream << std::endl;
jamie@264 8075 return true;
jamie@264 8076 }
jamie@264 8077
jamie@264 8078 virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
jamie@264 8079 m_headerPrinted = false;
jamie@264 8080 StreamingReporterBase::sectionStarting( _sectionInfo );
jamie@264 8081 }
jamie@264 8082 virtual void sectionEnded( SectionStats const& _sectionStats ) {
jamie@264 8083 if( _sectionStats.missingAssertions ) {
jamie@264 8084 lazyPrint();
jamie@264 8085 Colour colour( Colour::ResultError );
jamie@264 8086 if( m_sectionStack.size() > 1 )
jamie@264 8087 stream << "\nNo assertions in section";
jamie@264 8088 else
jamie@264 8089 stream << "\nNo assertions in test case";
jamie@264 8090 stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
jamie@264 8091 }
jamie@264 8092 if( m_headerPrinted ) {
jamie@264 8093 if( m_config->showDurations() == ShowDurations::Always )
jamie@264 8094 stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
jamie@264 8095 m_headerPrinted = false;
jamie@264 8096 }
jamie@264 8097 else {
jamie@264 8098 if( m_config->showDurations() == ShowDurations::Always )
jamie@264 8099 stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
jamie@264 8100 }
jamie@264 8101 StreamingReporterBase::sectionEnded( _sectionStats );
jamie@264 8102 }
jamie@264 8103
jamie@264 8104 virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) {
jamie@264 8105 StreamingReporterBase::testCaseEnded( _testCaseStats );
jamie@264 8106 m_headerPrinted = false;
jamie@264 8107 }
jamie@264 8108 virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
jamie@264 8109 if( currentGroupInfo.used ) {
jamie@264 8110 printSummaryDivider();
jamie@264 8111 stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
jamie@264 8112 printTotals( _testGroupStats.totals );
jamie@264 8113 stream << "\n" << std::endl;
jamie@264 8114 }
jamie@264 8115 StreamingReporterBase::testGroupEnded( _testGroupStats );
jamie@264 8116 }
jamie@264 8117 virtual void testRunEnded( TestRunStats const& _testRunStats ) {
jamie@264 8118 printTotalsDivider( _testRunStats.totals );
jamie@264 8119 printTotals( _testRunStats.totals );
jamie@264 8120 stream << std::endl;
jamie@264 8121 StreamingReporterBase::testRunEnded( _testRunStats );
jamie@264 8122 }
jamie@264 8123
jamie@264 8124 private:
jamie@264 8125
jamie@264 8126 class AssertionPrinter {
jamie@264 8127 void operator= ( AssertionPrinter const& );
jamie@264 8128 public:
jamie@264 8129 AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
jamie@264 8130 : stream( _stream ),
jamie@264 8131 stats( _stats ),
jamie@264 8132 result( _stats.assertionResult ),
jamie@264 8133 colour( Colour::None ),
jamie@264 8134 message( result.getMessage() ),
jamie@264 8135 messages( _stats.infoMessages ),
jamie@264 8136 printInfoMessages( _printInfoMessages )
jamie@264 8137 {
jamie@264 8138 switch( result.getResultType() ) {
jamie@264 8139 case ResultWas::Ok:
jamie@264 8140 colour = Colour::Success;
jamie@264 8141 passOrFail = "PASSED";
jamie@264 8142 //if( result.hasMessage() )
jamie@264 8143 if( _stats.infoMessages.size() == 1 )
jamie@264 8144 messageLabel = "with message";
jamie@264 8145 if( _stats.infoMessages.size() > 1 )
jamie@264 8146 messageLabel = "with messages";
jamie@264 8147 break;
jamie@264 8148 case ResultWas::ExpressionFailed:
jamie@264 8149 if( result.isOk() ) {
jamie@264 8150 colour = Colour::Success;
jamie@264 8151 passOrFail = "FAILED - but was ok";
jamie@264 8152 }
jamie@264 8153 else {
jamie@264 8154 colour = Colour::Error;
jamie@264 8155 passOrFail = "FAILED";
jamie@264 8156 }
jamie@264 8157 if( _stats.infoMessages.size() == 1 )
jamie@264 8158 messageLabel = "with message";
jamie@264 8159 if( _stats.infoMessages.size() > 1 )
jamie@264 8160 messageLabel = "with messages";
jamie@264 8161 break;
jamie@264 8162 case ResultWas::ThrewException:
jamie@264 8163 colour = Colour::Error;
jamie@264 8164 passOrFail = "FAILED";
jamie@264 8165 messageLabel = "due to unexpected exception with message";
jamie@264 8166 break;
jamie@264 8167 case ResultWas::DidntThrowException:
jamie@264 8168 colour = Colour::Error;
jamie@264 8169 passOrFail = "FAILED";
jamie@264 8170 messageLabel = "because no exception was thrown where one was expected";
jamie@264 8171 break;
jamie@264 8172 case ResultWas::Info:
jamie@264 8173 messageLabel = "info";
jamie@264 8174 break;
jamie@264 8175 case ResultWas::Warning:
jamie@264 8176 messageLabel = "warning";
jamie@264 8177 break;
jamie@264 8178 case ResultWas::ExplicitFailure:
jamie@264 8179 passOrFail = "FAILED";
jamie@264 8180 colour = Colour::Error;
jamie@264 8181 if( _stats.infoMessages.size() == 1 )
jamie@264 8182 messageLabel = "explicitly with message";
jamie@264 8183 if( _stats.infoMessages.size() > 1 )
jamie@264 8184 messageLabel = "explicitly with messages";
jamie@264 8185 break;
jamie@264 8186 // These cases are here to prevent compiler warnings
jamie@264 8187 case ResultWas::Unknown:
jamie@264 8188 case ResultWas::FailureBit:
jamie@264 8189 case ResultWas::Exception:
jamie@264 8190 passOrFail = "** internal error **";
jamie@264 8191 colour = Colour::Error;
jamie@264 8192 break;
jamie@264 8193 }
jamie@264 8194 }
jamie@264 8195
jamie@264 8196 void print() const {
jamie@264 8197 printSourceInfo();
jamie@264 8198 if( stats.totals.assertions.total() > 0 ) {
jamie@264 8199 if( result.isOk() )
jamie@264 8200 stream << "\n";
jamie@264 8201 printResultType();
jamie@264 8202 printOriginalExpression();
jamie@264 8203 printReconstructedExpression();
jamie@264 8204 }
jamie@264 8205 else {
jamie@264 8206 stream << "\n";
jamie@264 8207 }
jamie@264 8208 printMessage();
jamie@264 8209 }
jamie@264 8210
jamie@264 8211 private:
jamie@264 8212 void printResultType() const {
jamie@264 8213 if( !passOrFail.empty() ) {
jamie@264 8214 Colour colourGuard( colour );
jamie@264 8215 stream << passOrFail << ":\n";
jamie@264 8216 }
jamie@264 8217 }
jamie@264 8218 void printOriginalExpression() const {
jamie@264 8219 if( result.hasExpression() ) {
jamie@264 8220 Colour colourGuard( Colour::OriginalExpression );
jamie@264 8221 stream << " ";
jamie@264 8222 stream << result.getExpressionInMacro();
jamie@264 8223 stream << "\n";
jamie@264 8224 }
jamie@264 8225 }
jamie@264 8226 void printReconstructedExpression() const {
jamie@264 8227 if( result.hasExpandedExpression() ) {
jamie@264 8228 stream << "with expansion:\n";
jamie@264 8229 Colour colourGuard( Colour::ReconstructedExpression );
jamie@264 8230 stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n";
jamie@264 8231 }
jamie@264 8232 }
jamie@264 8233 void printMessage() const {
jamie@264 8234 if( !messageLabel.empty() )
jamie@264 8235 stream << messageLabel << ":" << "\n";
jamie@264 8236 for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
jamie@264 8237 it != itEnd;
jamie@264 8238 ++it ) {
jamie@264 8239 // If this assertion is a warning ignore any INFO messages
jamie@264 8240 if( printInfoMessages || it->type != ResultWas::Info )
jamie@264 8241 stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n";
jamie@264 8242 }
jamie@264 8243 }
jamie@264 8244 void printSourceInfo() const {
jamie@264 8245 Colour colourGuard( Colour::FileName );
jamie@264 8246 stream << result.getSourceInfo() << ": ";
jamie@264 8247 }
jamie@264 8248
jamie@264 8249 std::ostream& stream;
jamie@264 8250 AssertionStats const& stats;
jamie@264 8251 AssertionResult const& result;
jamie@264 8252 Colour::Code colour;
jamie@264 8253 std::string passOrFail;
jamie@264 8254 std::string messageLabel;
jamie@264 8255 std::string message;
jamie@264 8256 std::vector<MessageInfo> messages;
jamie@264 8257 bool printInfoMessages;
jamie@264 8258 };
jamie@264 8259
jamie@264 8260 void lazyPrint() {
jamie@264 8261
jamie@264 8262 if( !currentTestRunInfo.used )
jamie@264 8263 lazyPrintRunInfo();
jamie@264 8264 if( !currentGroupInfo.used )
jamie@264 8265 lazyPrintGroupInfo();
jamie@264 8266
jamie@264 8267 if( !m_headerPrinted ) {
jamie@264 8268 printTestCaseAndSectionHeader();
jamie@264 8269 m_headerPrinted = true;
jamie@264 8270 }
jamie@264 8271 }
jamie@264 8272 void lazyPrintRunInfo() {
jamie@264 8273 stream << "\n" << getLineOfChars<'~'>() << "\n";
jamie@264 8274 Colour colour( Colour::SecondaryText );
jamie@264 8275 stream << currentTestRunInfo->name
jamie@264 8276 << " is a Catch v" << libraryVersion.majorVersion << "."
jamie@264 8277 << libraryVersion.minorVersion << " b"
jamie@264 8278 << libraryVersion.buildNumber;
jamie@264 8279 if( libraryVersion.branchName != std::string( "master" ) )
jamie@264 8280 stream << " (" << libraryVersion.branchName << ")";
jamie@264 8281 stream << " host application.\n"
jamie@264 8282 << "Run with -? for options\n\n";
jamie@264 8283
jamie@264 8284 currentTestRunInfo.used = true;
jamie@264 8285 }
jamie@264 8286 void lazyPrintGroupInfo() {
jamie@264 8287 if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
jamie@264 8288 printClosedHeader( "Group: " + currentGroupInfo->name );
jamie@264 8289 currentGroupInfo.used = true;
jamie@264 8290 }
jamie@264 8291 }
jamie@264 8292 void printTestCaseAndSectionHeader() {
jamie@264 8293 assert( !m_sectionStack.empty() );
jamie@264 8294 printOpenHeader( currentTestCaseInfo->name );
jamie@264 8295
jamie@264 8296 if( m_sectionStack.size() > 1 ) {
jamie@264 8297 Colour colourGuard( Colour::Headers );
jamie@264 8298
jamie@264 8299 std::vector<SectionInfo>::const_iterator
jamie@264 8300 it = m_sectionStack.begin()+1, // Skip first section (test case)
jamie@264 8301 itEnd = m_sectionStack.end();
jamie@264 8302 for( ; it != itEnd; ++it )
jamie@264 8303 printHeaderString( it->name, 2 );
jamie@264 8304 }
jamie@264 8305
jamie@264 8306 SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
jamie@264 8307
jamie@264 8308 if( !lineInfo.empty() ){
jamie@264 8309 stream << getLineOfChars<'-'>() << "\n";
jamie@264 8310 Colour colourGuard( Colour::FileName );
jamie@264 8311 stream << lineInfo << "\n";
jamie@264 8312 }
jamie@264 8313 stream << getLineOfChars<'.'>() << "\n" << std::endl;
jamie@264 8314 }
jamie@264 8315
jamie@264 8316 void printClosedHeader( std::string const& _name ) {
jamie@264 8317 printOpenHeader( _name );
jamie@264 8318 stream << getLineOfChars<'.'>() << "\n";
jamie@264 8319 }
jamie@264 8320 void printOpenHeader( std::string const& _name ) {
jamie@264 8321 stream << getLineOfChars<'-'>() << "\n";
jamie@264 8322 {
jamie@264 8323 Colour colourGuard( Colour::Headers );
jamie@264 8324 printHeaderString( _name );
jamie@264 8325 }
jamie@264 8326 }
jamie@264 8327
jamie@264 8328 // if string has a : in first line will set indent to follow it on
jamie@264 8329 // subsequent lines
jamie@264 8330 void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
jamie@264 8331 std::size_t i = _string.find( ": " );
jamie@264 8332 if( i != std::string::npos )
jamie@264 8333 i+=2;
jamie@264 8334 else
jamie@264 8335 i = 0;
jamie@264 8336 stream << Text( _string, TextAttributes()
jamie@264 8337 .setIndent( indent+i)
jamie@264 8338 .setInitialIndent( indent ) ) << "\n";
jamie@264 8339 }
jamie@264 8340
jamie@264 8341 struct SummaryColumn {
jamie@264 8342
jamie@264 8343 SummaryColumn( std::string const& _label, Colour::Code _colour )
jamie@264 8344 : label( _label ),
jamie@264 8345 colour( _colour )
jamie@264 8346 {}
jamie@264 8347 SummaryColumn addRow( std::size_t count ) {
jamie@264 8348 std::ostringstream oss;
jamie@264 8349 oss << count;
jamie@264 8350 std::string row = oss.str();
jamie@264 8351 for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
jamie@264 8352 while( it->size() < row.size() )
jamie@264 8353 *it = " " + *it;
jamie@264 8354 while( it->size() > row.size() )
jamie@264 8355 row = " " + row;
jamie@264 8356 }
jamie@264 8357 rows.push_back( row );
jamie@264 8358 return *this;
jamie@264 8359 }
jamie@264 8360
jamie@264 8361 std::string label;
jamie@264 8362 Colour::Code colour;
jamie@264 8363 std::vector<std::string> rows;
jamie@264 8364
jamie@264 8365 };
jamie@264 8366
jamie@264 8367 void printTotals( Totals const& totals ) {
jamie@264 8368 if( totals.testCases.total() == 0 ) {
jamie@264 8369 stream << Colour( Colour::Warning ) << "No tests ran\n";
jamie@264 8370 }
jamie@264 8371 else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) {
jamie@264 8372 stream << Colour( Colour::ResultSuccess ) << "All tests passed";
jamie@264 8373 stream << " ("
jamie@264 8374 << pluralise( totals.assertions.passed, "assertion" ) << " in "
jamie@264 8375 << pluralise( totals.testCases.passed, "test case" ) << ")"
jamie@264 8376 << "\n";
jamie@264 8377 }
jamie@264 8378 else {
jamie@264 8379
jamie@264 8380 std::vector<SummaryColumn> columns;
jamie@264 8381 columns.push_back( SummaryColumn( "", Colour::None )
jamie@264 8382 .addRow( totals.testCases.total() )
jamie@264 8383 .addRow( totals.assertions.total() ) );
jamie@264 8384 columns.push_back( SummaryColumn( "passed", Colour::Success )
jamie@264 8385 .addRow( totals.testCases.passed )
jamie@264 8386 .addRow( totals.assertions.passed ) );
jamie@264 8387 columns.push_back( SummaryColumn( "failed", Colour::ResultError )
jamie@264 8388 .addRow( totals.testCases.failed )
jamie@264 8389 .addRow( totals.assertions.failed ) );
jamie@264 8390 columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
jamie@264 8391 .addRow( totals.testCases.failedButOk )
jamie@264 8392 .addRow( totals.assertions.failedButOk ) );
jamie@264 8393
jamie@264 8394 printSummaryRow( "test cases", columns, 0 );
jamie@264 8395 printSummaryRow( "assertions", columns, 1 );
jamie@264 8396 }
jamie@264 8397 }
jamie@264 8398 void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
jamie@264 8399 for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
jamie@264 8400 std::string value = it->rows[row];
jamie@264 8401 if( it->label.empty() ) {
jamie@264 8402 stream << label << ": ";
jamie@264 8403 if( value != "0" )
jamie@264 8404 stream << value;
jamie@264 8405 else
jamie@264 8406 stream << Colour( Colour::Warning ) << "- none -";
jamie@264 8407 }
jamie@264 8408 else if( value != "0" ) {
jamie@264 8409 stream << Colour( Colour::LightGrey ) << " | ";
jamie@264 8410 stream << Colour( it->colour )
jamie@264 8411 << value << " " << it->label;
jamie@264 8412 }
jamie@264 8413 }
jamie@264 8414 stream << "\n";
jamie@264 8415 }
jamie@264 8416
jamie@264 8417 static std::size_t makeRatio( std::size_t number, std::size_t total ) {
jamie@264 8418 std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
jamie@264 8419 return ( ratio == 0 && number > 0 ) ? 1 : ratio;
jamie@264 8420 }
jamie@264 8421 static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
jamie@264 8422 if( i > j && i > k )
jamie@264 8423 return i;
jamie@264 8424 else if( j > k )
jamie@264 8425 return j;
jamie@264 8426 else
jamie@264 8427 return k;
jamie@264 8428 }
jamie@264 8429
jamie@264 8430 void printTotalsDivider( Totals const& totals ) {
jamie@264 8431 if( totals.testCases.total() > 0 ) {
jamie@264 8432 std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
jamie@264 8433 std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
jamie@264 8434 std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
jamie@264 8435 while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
jamie@264 8436 findMax( failedRatio, failedButOkRatio, passedRatio )++;
jamie@264 8437 while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
jamie@264 8438 findMax( failedRatio, failedButOkRatio, passedRatio )--;
jamie@264 8439
jamie@264 8440 stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
jamie@264 8441 stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
jamie@264 8442 if( totals.testCases.allPassed() )
jamie@264 8443 stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
jamie@264 8444 else
jamie@264 8445 stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
jamie@264 8446 }
jamie@264 8447 else {
jamie@264 8448 stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
jamie@264 8449 }
jamie@264 8450 stream << "\n";
jamie@264 8451 }
jamie@264 8452 void printSummaryDivider() {
jamie@264 8453 stream << getLineOfChars<'-'>() << "\n";
jamie@264 8454 }
jamie@264 8455 template<char C>
jamie@264 8456 static char const* getLineOfChars() {
jamie@264 8457 static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
jamie@264 8458 if( !*line ) {
jamie@264 8459 memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
jamie@264 8460 line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
jamie@264 8461 }
jamie@264 8462 return line;
jamie@264 8463 }
jamie@264 8464
jamie@264 8465 private:
jamie@264 8466 bool m_headerPrinted;
jamie@264 8467 };
jamie@264 8468
jamie@264 8469 INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
jamie@264 8470
jamie@264 8471 } // end namespace Catch
jamie@264 8472
jamie@264 8473 // #included from: ../reporters/catch_reporter_compact.hpp
jamie@264 8474 #define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
jamie@264 8475
jamie@264 8476 namespace Catch {
jamie@264 8477
jamie@264 8478 struct CompactReporter : StreamingReporterBase {
jamie@264 8479
jamie@264 8480 CompactReporter( ReporterConfig const& _config )
jamie@264 8481 : StreamingReporterBase( _config )
jamie@264 8482 {}
jamie@264 8483
jamie@264 8484 virtual ~CompactReporter();
jamie@264 8485
jamie@264 8486 static std::string getDescription() {
jamie@264 8487 return "Reports test results on a single line, suitable for IDEs";
jamie@264 8488 }
jamie@264 8489
jamie@264 8490 virtual ReporterPreferences getPreferences() const {
jamie@264 8491 ReporterPreferences prefs;
jamie@264 8492 prefs.shouldRedirectStdOut = false;
jamie@264 8493 return prefs;
jamie@264 8494 }
jamie@264 8495
jamie@264 8496 virtual void noMatchingTestCases( std::string const& spec ) {
jamie@264 8497 stream << "No test cases matched '" << spec << "'" << std::endl;
jamie@264 8498 }
jamie@264 8499
jamie@264 8500 virtual void assertionStarting( AssertionInfo const& ) {
jamie@264 8501 }
jamie@264 8502
jamie@264 8503 virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
jamie@264 8504 AssertionResult const& result = _assertionStats.assertionResult;
jamie@264 8505
jamie@264 8506 bool printInfoMessages = true;
jamie@264 8507
jamie@264 8508 // Drop out if result was successful and we're not printing those
jamie@264 8509 if( !m_config->includeSuccessfulResults() && result.isOk() ) {
jamie@264 8510 if( result.getResultType() != ResultWas::Warning )
jamie@264 8511 return false;
jamie@264 8512 printInfoMessages = false;
jamie@264 8513 }
jamie@264 8514
jamie@264 8515 AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
jamie@264 8516 printer.print();
jamie@264 8517
jamie@264 8518 stream << std::endl;
jamie@264 8519 return true;
jamie@264 8520 }
jamie@264 8521
jamie@264 8522 virtual void testRunEnded( TestRunStats const& _testRunStats ) {
jamie@264 8523 printTotals( _testRunStats.totals );
jamie@264 8524 stream << "\n" << std::endl;
jamie@264 8525 StreamingReporterBase::testRunEnded( _testRunStats );
jamie@264 8526 }
jamie@264 8527
jamie@264 8528 private:
jamie@264 8529 class AssertionPrinter {
jamie@264 8530 void operator= ( AssertionPrinter const& );
jamie@264 8531 public:
jamie@264 8532 AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
jamie@264 8533 : stream( _stream )
jamie@264 8534 , stats( _stats )
jamie@264 8535 , result( _stats.assertionResult )
jamie@264 8536 , messages( _stats.infoMessages )
jamie@264 8537 , itMessage( _stats.infoMessages.begin() )
jamie@264 8538 , printInfoMessages( _printInfoMessages )
jamie@264 8539 {}
jamie@264 8540
jamie@264 8541 void print() {
jamie@264 8542 printSourceInfo();
jamie@264 8543
jamie@264 8544 itMessage = messages.begin();
jamie@264 8545
jamie@264 8546 switch( result.getResultType() ) {
jamie@264 8547 case ResultWas::Ok:
jamie@264 8548 printResultType( Colour::ResultSuccess, passedString() );
jamie@264 8549 printOriginalExpression();
jamie@264 8550 printReconstructedExpression();
jamie@264 8551 if ( ! result.hasExpression() )
jamie@264 8552 printRemainingMessages( Colour::None );
jamie@264 8553 else
jamie@264 8554 printRemainingMessages();
jamie@264 8555 break;
jamie@264 8556 case ResultWas::ExpressionFailed:
jamie@264 8557 if( result.isOk() )
jamie@264 8558 printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
jamie@264 8559 else
jamie@264 8560 printResultType( Colour::Error, failedString() );
jamie@264 8561 printOriginalExpression();
jamie@264 8562 printReconstructedExpression();
jamie@264 8563 printRemainingMessages();
jamie@264 8564 break;
jamie@264 8565 case ResultWas::ThrewException:
jamie@264 8566 printResultType( Colour::Error, failedString() );
jamie@264 8567 printIssue( "unexpected exception with message:" );
jamie@264 8568 printMessage();
jamie@264 8569 printExpressionWas();
jamie@264 8570 printRemainingMessages();
jamie@264 8571 break;
jamie@264 8572 case ResultWas::DidntThrowException:
jamie@264 8573 printResultType( Colour::Error, failedString() );
jamie@264 8574 printIssue( "expected exception, got none" );
jamie@264 8575 printExpressionWas();
jamie@264 8576 printRemainingMessages();
jamie@264 8577 break;
jamie@264 8578 case ResultWas::Info:
jamie@264 8579 printResultType( Colour::None, "info" );
jamie@264 8580 printMessage();
jamie@264 8581 printRemainingMessages();
jamie@264 8582 break;
jamie@264 8583 case ResultWas::Warning:
jamie@264 8584 printResultType( Colour::None, "warning" );
jamie@264 8585 printMessage();
jamie@264 8586 printRemainingMessages();
jamie@264 8587 break;
jamie@264 8588 case ResultWas::ExplicitFailure:
jamie@264 8589 printResultType( Colour::Error, failedString() );
jamie@264 8590 printIssue( "explicitly" );
jamie@264 8591 printRemainingMessages( Colour::None );
jamie@264 8592 break;
jamie@264 8593 // These cases are here to prevent compiler warnings
jamie@264 8594 case ResultWas::Unknown:
jamie@264 8595 case ResultWas::FailureBit:
jamie@264 8596 case ResultWas::Exception:
jamie@264 8597 printResultType( Colour::Error, "** internal error **" );
jamie@264 8598 break;
jamie@264 8599 }
jamie@264 8600 }
jamie@264 8601
jamie@264 8602 private:
jamie@264 8603 // Colour::LightGrey
jamie@264 8604
jamie@264 8605 static Colour::Code dimColour() { return Colour::FileName; }
jamie@264 8606
jamie@264 8607 #ifdef CATCH_PLATFORM_MAC
jamie@264 8608 static const char* failedString() { return "FAILED"; }
jamie@264 8609 static const char* passedString() { return "PASSED"; }
jamie@264 8610 #else
jamie@264 8611 static const char* failedString() { return "failed"; }
jamie@264 8612 static const char* passedString() { return "passed"; }
jamie@264 8613 #endif
jamie@264 8614
jamie@264 8615 void printSourceInfo() const {
jamie@264 8616 Colour colourGuard( Colour::FileName );
jamie@264 8617 stream << result.getSourceInfo() << ":";
jamie@264 8618 }
jamie@264 8619
jamie@264 8620 void printResultType( Colour::Code colour, std::string passOrFail ) const {
jamie@264 8621 if( !passOrFail.empty() ) {
jamie@264 8622 {
jamie@264 8623 Colour colourGuard( colour );
jamie@264 8624 stream << " " << passOrFail;
jamie@264 8625 }
jamie@264 8626 stream << ":";
jamie@264 8627 }
jamie@264 8628 }
jamie@264 8629
jamie@264 8630 void printIssue( std::string issue ) const {
jamie@264 8631 stream << " " << issue;
jamie@264 8632 }
jamie@264 8633
jamie@264 8634 void printExpressionWas() {
jamie@264 8635 if( result.hasExpression() ) {
jamie@264 8636 stream << ";";
jamie@264 8637 {
jamie@264 8638 Colour colour( dimColour() );
jamie@264 8639 stream << " expression was:";
jamie@264 8640 }
jamie@264 8641 printOriginalExpression();
jamie@264 8642 }
jamie@264 8643 }
jamie@264 8644
jamie@264 8645 void printOriginalExpression() const {
jamie@264 8646 if( result.hasExpression() ) {
jamie@264 8647 stream << " " << result.getExpression();
jamie@264 8648 }
jamie@264 8649 }
jamie@264 8650
jamie@264 8651 void printReconstructedExpression() const {
jamie@264 8652 if( result.hasExpandedExpression() ) {
jamie@264 8653 {
jamie@264 8654 Colour colour( dimColour() );
jamie@264 8655 stream << " for: ";
jamie@264 8656 }
jamie@264 8657 stream << result.getExpandedExpression();
jamie@264 8658 }
jamie@264 8659 }
jamie@264 8660
jamie@264 8661 void printMessage() {
jamie@264 8662 if ( itMessage != messages.end() ) {
jamie@264 8663 stream << " '" << itMessage->message << "'";
jamie@264 8664 ++itMessage;
jamie@264 8665 }
jamie@264 8666 }
jamie@264 8667
jamie@264 8668 void printRemainingMessages( Colour::Code colour = dimColour() ) {
jamie@264 8669 if ( itMessage == messages.end() )
jamie@264 8670 return;
jamie@264 8671
jamie@264 8672 // using messages.end() directly yields compilation error:
jamie@264 8673 std::vector<MessageInfo>::const_iterator itEnd = messages.end();
jamie@264 8674 const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
jamie@264 8675
jamie@264 8676 {
jamie@264 8677 Colour colourGuard( colour );
jamie@264 8678 stream << " with " << pluralise( N, "message" ) << ":";
jamie@264 8679 }
jamie@264 8680
jamie@264 8681 for(; itMessage != itEnd; ) {
jamie@264 8682 // If this assertion is a warning ignore any INFO messages
jamie@264 8683 if( printInfoMessages || itMessage->type != ResultWas::Info ) {
jamie@264 8684 stream << " '" << itMessage->message << "'";
jamie@264 8685 if ( ++itMessage != itEnd ) {
jamie@264 8686 Colour colourGuard( dimColour() );
jamie@264 8687 stream << " and";
jamie@264 8688 }
jamie@264 8689 }
jamie@264 8690 }
jamie@264 8691 }
jamie@264 8692
jamie@264 8693 private:
jamie@264 8694 std::ostream& stream;
jamie@264 8695 AssertionStats const& stats;
jamie@264 8696 AssertionResult const& result;
jamie@264 8697 std::vector<MessageInfo> messages;
jamie@264 8698 std::vector<MessageInfo>::const_iterator itMessage;
jamie@264 8699 bool printInfoMessages;
jamie@264 8700 };
jamie@264 8701
jamie@264 8702 // Colour, message variants:
jamie@264 8703 // - white: No tests ran.
jamie@264 8704 // - red: Failed [both/all] N test cases, failed [both/all] M assertions.
jamie@264 8705 // - white: Passed [both/all] N test cases (no assertions).
jamie@264 8706 // - red: Failed N tests cases, failed M assertions.
jamie@264 8707 // - green: Passed [both/all] N tests cases with M assertions.
jamie@264 8708
jamie@264 8709 std::string bothOrAll( std::size_t count ) const {
jamie@264 8710 return count == 1 ? "" : count == 2 ? "both " : "all " ;
jamie@264 8711 }
jamie@264 8712
jamie@264 8713 void printTotals( const Totals& totals ) const {
jamie@264 8714 if( totals.testCases.total() == 0 ) {
jamie@264 8715 stream << "No tests ran.";
jamie@264 8716 }
jamie@264 8717 else if( totals.testCases.failed == totals.testCases.total() ) {
jamie@264 8718 Colour colour( Colour::ResultError );
jamie@264 8719 const std::string qualify_assertions_failed =
jamie@264 8720 totals.assertions.failed == totals.assertions.total() ?
jamie@264 8721 bothOrAll( totals.assertions.failed ) : "";
jamie@264 8722 stream <<
jamie@264 8723 "Failed " << bothOrAll( totals.testCases.failed )
jamie@264 8724 << pluralise( totals.testCases.failed, "test case" ) << ", "
jamie@264 8725 "failed " << qualify_assertions_failed <<
jamie@264 8726 pluralise( totals.assertions.failed, "assertion" ) << ".";
jamie@264 8727 }
jamie@264 8728 else if( totals.assertions.total() == 0 ) {
jamie@264 8729 stream <<
jamie@264 8730 "Passed " << bothOrAll( totals.testCases.total() )
jamie@264 8731 << pluralise( totals.testCases.total(), "test case" )
jamie@264 8732 << " (no assertions).";
jamie@264 8733 }
jamie@264 8734 else if( totals.assertions.failed ) {
jamie@264 8735 Colour colour( Colour::ResultError );
jamie@264 8736 stream <<
jamie@264 8737 "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", "
jamie@264 8738 "failed " << pluralise( totals.assertions.failed, "assertion" ) << ".";
jamie@264 8739 }
jamie@264 8740 else {
jamie@264 8741 Colour colour( Colour::ResultSuccess );
jamie@264 8742 stream <<
jamie@264 8743 "Passed " << bothOrAll( totals.testCases.passed )
jamie@264 8744 << pluralise( totals.testCases.passed, "test case" ) <<
jamie@264 8745 " with " << pluralise( totals.assertions.passed, "assertion" ) << ".";
jamie@264 8746 }
jamie@264 8747 }
jamie@264 8748 };
jamie@264 8749
jamie@264 8750 INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
jamie@264 8751
jamie@264 8752 } // end namespace Catch
jamie@264 8753
jamie@264 8754 namespace Catch {
jamie@264 8755 NonCopyable::~NonCopyable() {}
jamie@264 8756 IShared::~IShared() {}
jamie@264 8757 StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
jamie@264 8758 IContext::~IContext() {}
jamie@264 8759 IResultCapture::~IResultCapture() {}
jamie@264 8760 ITestCase::~ITestCase() {}
jamie@264 8761 ITestCaseRegistry::~ITestCaseRegistry() {}
jamie@264 8762 IRegistryHub::~IRegistryHub() {}
jamie@264 8763 IMutableRegistryHub::~IMutableRegistryHub() {}
jamie@264 8764 IExceptionTranslator::~IExceptionTranslator() {}
jamie@264 8765 IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
jamie@264 8766 IReporter::~IReporter() {}
jamie@264 8767 IReporterFactory::~IReporterFactory() {}
jamie@264 8768 IReporterRegistry::~IReporterRegistry() {}
jamie@264 8769 IStreamingReporter::~IStreamingReporter() {}
jamie@264 8770 AssertionStats::~AssertionStats() {}
jamie@264 8771 SectionStats::~SectionStats() {}
jamie@264 8772 TestCaseStats::~TestCaseStats() {}
jamie@264 8773 TestGroupStats::~TestGroupStats() {}
jamie@264 8774 TestRunStats::~TestRunStats() {}
jamie@264 8775 CumulativeReporterBase::SectionNode::~SectionNode() {}
jamie@264 8776 CumulativeReporterBase::~CumulativeReporterBase() {}
jamie@264 8777
jamie@264 8778 StreamingReporterBase::~StreamingReporterBase() {}
jamie@264 8779 ConsoleReporter::~ConsoleReporter() {}
jamie@264 8780 CompactReporter::~CompactReporter() {}
jamie@264 8781 IRunner::~IRunner() {}
jamie@264 8782 IMutableContext::~IMutableContext() {}
jamie@264 8783 IConfig::~IConfig() {}
jamie@264 8784 XmlReporter::~XmlReporter() {}
jamie@264 8785 JunitReporter::~JunitReporter() {}
jamie@264 8786 TestRegistry::~TestRegistry() {}
jamie@264 8787 FreeFunctionTestCase::~FreeFunctionTestCase() {}
jamie@264 8788 IGeneratorInfo::~IGeneratorInfo() {}
jamie@264 8789 IGeneratorsForTest::~IGeneratorsForTest() {}
jamie@264 8790 TestSpec::Pattern::~Pattern() {}
jamie@264 8791 TestSpec::NamePattern::~NamePattern() {}
jamie@264 8792 TestSpec::TagPattern::~TagPattern() {}
jamie@264 8793 TestSpec::ExcludedPattern::~ExcludedPattern() {}
jamie@264 8794
jamie@264 8795 Matchers::Impl::StdString::Equals::~Equals() {}
jamie@264 8796 Matchers::Impl::StdString::Contains::~Contains() {}
jamie@264 8797 Matchers::Impl::StdString::StartsWith::~StartsWith() {}
jamie@264 8798 Matchers::Impl::StdString::EndsWith::~EndsWith() {}
jamie@264 8799
jamie@264 8800 void Config::dummy() {}
jamie@264 8801
jamie@264 8802 INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
jamie@264 8803 }
jamie@264 8804
jamie@264 8805 #ifdef __clang__
jamie@264 8806 #pragma clang diagnostic pop
jamie@264 8807 #endif
jamie@264 8808
jamie@264 8809 #endif
jamie@264 8810
jamie@264 8811 #ifdef CATCH_CONFIG_MAIN
jamie@264 8812 // #included from: internal/catch_default_main.hpp
jamie@264 8813 #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
jamie@264 8814
jamie@264 8815 #ifndef __OBJC__
jamie@264 8816
jamie@264 8817 // Standard C/C++ main entry point
jamie@264 8818 int main (int argc, char * const argv[]) {
jamie@264 8819 return Catch::Session().run( argc, argv );
jamie@264 8820 }
jamie@264 8821
jamie@264 8822 #else // __OBJC__
jamie@264 8823
jamie@264 8824 // Objective-C entry point
jamie@264 8825 int main (int argc, char * const argv[]) {
jamie@264 8826 #if !CATCH_ARC_ENABLED
jamie@264 8827 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
jamie@264 8828 #endif
jamie@264 8829
jamie@264 8830 Catch::registerTestMethods();
jamie@264 8831 int result = Catch::Session().run( argc, (char* const*)argv );
jamie@264 8832
jamie@264 8833 #if !CATCH_ARC_ENABLED
jamie@264 8834 [pool drain];
jamie@264 8835 #endif
jamie@264 8836
jamie@264 8837 return result;
jamie@264 8838 }
jamie@264 8839
jamie@264 8840 #endif // __OBJC__
jamie@264 8841
jamie@264 8842 #endif
jamie@264 8843
jamie@264 8844 #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
jamie@264 8845 # undef CLARA_CONFIG_MAIN
jamie@264 8846 #endif
jamie@264 8847
jamie@264 8848 //////
jamie@264 8849
jamie@264 8850 // If this config identifier is defined then all CATCH macros are prefixed with CATCH_
jamie@264 8851 #ifdef CATCH_CONFIG_PREFIX_ALL
jamie@264 8852
jamie@264 8853 #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
jamie@264 8854 #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
jamie@264 8855
jamie@264 8856 #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" )
jamie@264 8857 #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
jamie@264 8858 #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
jamie@264 8859
jamie@264 8860 #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
jamie@264 8861 #define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
jamie@264 8862 #define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
jamie@264 8863 #define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
jamie@264 8864 #define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
jamie@264 8865
jamie@264 8866 #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
jamie@264 8867 #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
jamie@264 8868 #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
jamie@264 8869
jamie@264 8870 #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
jamie@264 8871 #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
jamie@264 8872
jamie@264 8873 #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
jamie@264 8874 #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
jamie@264 8875 #define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
jamie@264 8876 #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
jamie@264 8877 #define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
jamie@264 8878
jamie@264 8879 #ifdef CATCH_CONFIG_VARIADIC_MACROS
jamie@264 8880 #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
jamie@264 8881 #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
jamie@264 8882 #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
jamie@264 8883 #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
jamie@264 8884 #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
jamie@264 8885 #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
jamie@264 8886 #else
jamie@264 8887 #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
jamie@264 8888 #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
jamie@264 8889 #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
jamie@264 8890 #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
jamie@264 8891 #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
jamie@264 8892 #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
jamie@264 8893 #endif
jamie@264 8894 #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
jamie@264 8895
jamie@264 8896 #define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
jamie@264 8897 #define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
jamie@264 8898
jamie@264 8899 #define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
jamie@264 8900
jamie@264 8901 // "BDD-style" convenience wrappers
jamie@264 8902 #ifdef CATCH_CONFIG_VARIADIC_MACROS
jamie@264 8903 #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
jamie@264 8904 #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
jamie@264 8905 #else
jamie@264 8906 #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
jamie@264 8907 #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
jamie@264 8908 #endif
jamie@264 8909 #define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" )
jamie@264 8910 #define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" )
jamie@264 8911 #define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" )
jamie@264 8912 #define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" )
jamie@264 8913 #define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" )
jamie@264 8914
jamie@264 8915 // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
jamie@264 8916 #else
jamie@264 8917
jamie@264 8918 #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
jamie@264 8919 #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
jamie@264 8920
jamie@264 8921 #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" )
jamie@264 8922 #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
jamie@264 8923 #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
jamie@264 8924
jamie@264 8925 #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
jamie@264 8926 #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
jamie@264 8927 #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
jamie@264 8928 #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
jamie@264 8929 #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
jamie@264 8930
jamie@264 8931 #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" )
jamie@264 8932 #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
jamie@264 8933 #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
jamie@264 8934
jamie@264 8935 #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
jamie@264 8936 #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
jamie@264 8937
jamie@264 8938 #define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
jamie@264 8939 #define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
jamie@264 8940 #define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
jamie@264 8941 #define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
jamie@264 8942 #define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
jamie@264 8943
jamie@264 8944 #ifdef CATCH_CONFIG_VARIADIC_MACROS
jamie@264 8945 #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
jamie@264 8946 #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
jamie@264 8947 #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
jamie@264 8948 #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
jamie@264 8949 #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
jamie@264 8950 #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
jamie@264 8951 #else
jamie@264 8952 #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
jamie@264 8953 #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
jamie@264 8954 #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
jamie@264 8955 #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
jamie@264 8956 #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
jamie@264 8957 #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
jamie@264 8958 #endif
jamie@264 8959 #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
jamie@264 8960
jamie@264 8961 #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
jamie@264 8962 #define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
jamie@264 8963
jamie@264 8964 #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
jamie@264 8965
jamie@264 8966 #endif
jamie@264 8967
jamie@264 8968 #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
jamie@264 8969
jamie@264 8970 // "BDD-style" convenience wrappers
jamie@264 8971 #ifdef CATCH_CONFIG_VARIADIC_MACROS
jamie@264 8972 #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
jamie@264 8973 #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
jamie@264 8974 #else
jamie@264 8975 #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
jamie@264 8976 #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
jamie@264 8977 #endif
jamie@264 8978 #define GIVEN( desc ) SECTION( " Given: " desc, "" )
jamie@264 8979 #define WHEN( desc ) SECTION( " When: " desc, "" )
jamie@264 8980 #define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
jamie@264 8981 #define THEN( desc ) SECTION( " Then: " desc, "" )
jamie@264 8982 #define AND_THEN( desc ) SECTION( " And: " desc, "" )
jamie@264 8983
jamie@264 8984 using Catch::Detail::Approx;
jamie@264 8985
jamie@264 8986 // #included from: internal/catch_reenable_warnings.h
jamie@264 8987
jamie@264 8988 #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
jamie@264 8989
jamie@264 8990 #ifdef __clang__
jamie@264 8991 #pragma clang diagnostic pop
jamie@264 8992 #elif defined __GNUC__
jamie@264 8993 #pragma GCC diagnostic pop
jamie@264 8994 #endif
jamie@264 8995
jamie@264 8996 #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
jamie@264 8997