Mercurial > hg > nsaunier > traffic-intelligence
comparison include/catch.hpp @ 231:249d65ff6c35
merged modifications for windows
| author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
|---|---|
| date | Mon, 02 Jul 2012 23:49:39 -0400 |
| parents | f0f800b95765 |
| children | c6f497291fd8 |
comparison
equal
deleted
inserted
replaced
| 230:bc4ea09b1743 | 231:249d65ff6c35 |
|---|---|
| 1 /* | |
| 2 * Generated: 2012-06-06 08:05:56.928287 | |
| 3 * ---------------------------------------------------------- | |
| 4 * This file has been merged from multiple headers. Please don't edit it directly | |
| 5 * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. | |
| 6 * | |
| 7 * Distributed under the Boost Software License, Version 1.0. (See accompanying | |
| 8 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
| 9 */ | |
| 10 #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED | |
| 11 #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED | |
| 12 | |
| 13 // #included from: internal/catch_context.h | |
| 14 | |
| 15 // #included from: catch_interfaces_reporter.h | |
| 16 | |
| 17 // #included from: catch_common.h | |
| 18 | |
| 19 #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line | |
| 20 #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) | |
| 21 #define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) | |
| 22 | |
| 23 #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr | |
| 24 #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) | |
| 25 | |
| 26 #ifdef __GNUC__ | |
| 27 #define ATTRIBUTE_NORETURN __attribute__ ((noreturn)) | |
| 28 #else | |
| 29 #define ATTRIBUTE_NORETURN | |
| 30 #endif | |
| 31 | |
| 32 #include <sstream> | |
| 33 #include <stdexcept> | |
| 34 #include <algorithm> | |
| 35 | |
| 36 namespace Catch { | |
| 37 | |
| 38 class NonCopyable { | |
| 39 NonCopyable( const NonCopyable& ); | |
| 40 void operator = ( const NonCopyable& ); | |
| 41 protected: | |
| 42 NonCopyable() {} | |
| 43 virtual ~NonCopyable() {} | |
| 44 }; | |
| 45 | |
| 46 class SafeBool { | |
| 47 public: | |
| 48 typedef void (SafeBool::*type)() const; | |
| 49 | |
| 50 static type makeSafe( bool value ) { | |
| 51 return value ? &SafeBool::trueValue : 0; | |
| 52 } | |
| 53 private: | |
| 54 void trueValue() const {} | |
| 55 }; | |
| 56 | |
| 57 template<typename ContainerT> | |
| 58 inline void deleteAll( ContainerT& container ) { | |
| 59 typename ContainerT::const_iterator it = container.begin(); | |
| 60 typename ContainerT::const_iterator itEnd = container.end(); | |
| 61 for(; it != itEnd; ++it ) | |
| 62 { | |
| 63 delete *it; | |
| 64 } | |
| 65 } | |
| 66 template<typename AssociativeContainerT> | |
| 67 inline void deleteAllValues( AssociativeContainerT& container ) { | |
| 68 typename AssociativeContainerT::const_iterator it = container.begin(); | |
| 69 typename AssociativeContainerT::const_iterator itEnd = container.end(); | |
| 70 for(; it != itEnd; ++it ) | |
| 71 { | |
| 72 delete it->second; | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 template<typename ContainerT, typename Function> | |
| 77 inline void forEach( ContainerT& container, Function function ) { | |
| 78 std::for_each( container.begin(), container.end(), function ); | |
| 79 } | |
| 80 | |
| 81 template<typename ContainerT, typename Function> | |
| 82 inline void forEach( const ContainerT& container, Function function ) { | |
| 83 std::for_each( container.begin(), container.end(), function ); | |
| 84 } | |
| 85 | |
| 86 struct SourceLineInfo { | |
| 87 | |
| 88 SourceLineInfo() : line( 0 ){} | |
| 89 SourceLineInfo( const std::string& _file, std::size_t _line ) | |
| 90 : file( _file ), | |
| 91 line( _line ) | |
| 92 {} | |
| 93 SourceLineInfo( const SourceLineInfo& other ) | |
| 94 : file( other.file ), | |
| 95 line( other.line ) | |
| 96 {} | |
| 97 void swap( SourceLineInfo& other ){ | |
| 98 file.swap( other.file ); | |
| 99 std::swap( line, other.line ); | |
| 100 } | |
| 101 | |
| 102 std::string file; | |
| 103 std::size_t line; | |
| 104 }; | |
| 105 | |
| 106 inline std::ostream& operator << ( std::ostream& os, const SourceLineInfo& info ) { | |
| 107 #ifndef __GNUG__ | |
| 108 os << info.file << "(" << info.line << "): "; | |
| 109 #else | |
| 110 os << info.file << ":" << info.line << ": "; | |
| 111 #endif | |
| 112 return os; | |
| 113 } | |
| 114 | |
| 115 ATTRIBUTE_NORETURN | |
| 116 inline void throwLogicError( const std::string& message, const std::string& file, std::size_t line ) { | |
| 117 std::ostringstream oss; | |
| 118 oss << "Internal Catch error: '" << message << "' at: " << SourceLineInfo( file, line ); | |
| 119 throw std::logic_error( oss.str() ); | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 #define CATCH_INTERNAL_ERROR( msg ) throwLogicError( msg, __FILE__, __LINE__ ); | |
| 124 #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, __LINE__ ) | |
| 125 | |
| 126 // #included from: catch_totals.hpp | |
| 127 | |
| 128 namespace Catch { | |
| 129 | |
| 130 struct Counts { | |
| 131 Counts() : passed( 0 ), failed( 0 ) {} | |
| 132 | |
| 133 Counts operator - ( const Counts& other ) const { | |
| 134 Counts diff; | |
| 135 diff.passed = passed - other.passed; | |
| 136 diff.failed = failed - other.failed; | |
| 137 return diff; | |
| 138 } | |
| 139 Counts& operator += ( const Counts& other ) { | |
| 140 passed += other.passed; | |
| 141 failed += other.failed; | |
| 142 return *this; | |
| 143 } | |
| 144 | |
| 145 std::size_t total() const { | |
| 146 return passed + failed; | |
| 147 } | |
| 148 | |
| 149 std::size_t passed; | |
| 150 std::size_t failed; | |
| 151 }; | |
| 152 | |
| 153 struct Totals { | |
| 154 | |
| 155 Totals operator - ( const Totals& other ) const { | |
| 156 Totals diff; | |
| 157 diff.assertions = assertions - other.assertions; | |
| 158 diff.testCases = testCases - other.testCases; | |
| 159 return diff; | |
| 160 } | |
| 161 | |
| 162 Totals delta( const Totals& prevTotals ) const { | |
| 163 Totals diff = *this - prevTotals; | |
| 164 if( diff.assertions.failed > 0 ) | |
| 165 ++diff.testCases.failed; | |
| 166 else | |
| 167 ++diff.testCases.passed; | |
| 168 return diff; | |
| 169 } | |
| 170 | |
| 171 Counts assertions; | |
| 172 Counts testCases; | |
| 173 }; | |
| 174 } | |
| 175 | |
| 176 // #included from: catch_ptr.hpp | |
| 177 | |
| 178 namespace Catch { | |
| 179 | |
| 180 // An intrusive reference counting smart pointer. | |
| 181 // T must implement addRef() and release() methods | |
| 182 // typically implementing the IShared interface | |
| 183 template<typename T> | |
| 184 class Ptr { | |
| 185 public: | |
| 186 Ptr() : m_p( NULL ){} | |
| 187 Ptr( T* p ) : m_p( p ){ | |
| 188 m_p->addRef(); | |
| 189 } | |
| 190 Ptr( const Ptr& other ) : m_p( other.m_p ){ | |
| 191 m_p->addRef(); | |
| 192 } | |
| 193 ~Ptr(){ | |
| 194 if( m_p ) | |
| 195 m_p->release(); | |
| 196 } | |
| 197 Ptr& operator = ( T* p ){ | |
| 198 Ptr temp( p ); | |
| 199 swap( temp ); | |
| 200 return *this; | |
| 201 } | |
| 202 Ptr& operator = ( Ptr& other ){ | |
| 203 Ptr temp( other ); | |
| 204 swap( temp ); | |
| 205 return *this; | |
| 206 } | |
| 207 void swap( Ptr& other ){ | |
| 208 std::swap( m_p, other.m_p ); | |
| 209 } | |
| 210 | |
| 211 T* get(){ | |
| 212 return m_p; | |
| 213 } | |
| 214 const T* get() const{ | |
| 215 return m_p; | |
| 216 } | |
| 217 | |
| 218 T& operator*(){ | |
| 219 return *m_p; | |
| 220 } | |
| 221 const T& operator*() const{ | |
| 222 return *m_p; | |
| 223 } | |
| 224 | |
| 225 T* operator->(){ | |
| 226 return m_p; | |
| 227 } | |
| 228 const T* operator->() const{ | |
| 229 return m_p; | |
| 230 } | |
| 231 | |
| 232 private: | |
| 233 T* m_p; | |
| 234 }; | |
| 235 | |
| 236 struct IShared : NonCopyable { | |
| 237 virtual ~IShared(){} | |
| 238 virtual void addRef() = 0; | |
| 239 virtual void release() = 0; | |
| 240 }; | |
| 241 | |
| 242 template<typename T> | |
| 243 struct SharedImpl : T { | |
| 244 | |
| 245 SharedImpl() : m_rc( 0 ){} | |
| 246 | |
| 247 virtual void addRef(){ | |
| 248 ++m_rc; | |
| 249 } | |
| 250 virtual void release(){ | |
| 251 if( --m_rc == 0 ) | |
| 252 delete this; | |
| 253 } | |
| 254 | |
| 255 int m_rc; | |
| 256 }; | |
| 257 | |
| 258 } // end namespace Catch | |
| 259 | |
| 260 #include <string> | |
| 261 #include <ostream> | |
| 262 #include <map> | |
| 263 | |
| 264 namespace Catch | |
| 265 { | |
| 266 struct IReporterConfig { | |
| 267 virtual ~IReporterConfig() {} | |
| 268 virtual std::ostream& stream () const = 0; | |
| 269 virtual bool includeSuccessfulResults () const = 0; | |
| 270 virtual std::string getName () const = 0; | |
| 271 }; | |
| 272 | |
| 273 class TestCaseInfo; | |
| 274 class ResultInfo; | |
| 275 | |
| 276 struct IReporter : IShared { | |
| 277 virtual ~IReporter() {} | |
| 278 virtual bool shouldRedirectStdout() const = 0; | |
| 279 virtual void StartTesting() = 0; | |
| 280 virtual void EndTesting( const Totals& totals ) = 0; | |
| 281 virtual void StartGroup( const std::string& groupName ) = 0; | |
| 282 virtual void EndGroup( const std::string& groupName, const Totals& totals ) = 0; | |
| 283 virtual void StartSection( const std::string& sectionName, const std::string& description ) = 0; | |
| 284 virtual void EndSection( const std::string& sectionName, const Counts& assertions ) = 0; | |
| 285 virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0; | |
| 286 virtual void Aborted() = 0; | |
| 287 virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr ) = 0; | |
| 288 virtual void Result( const ResultInfo& result ) = 0; | |
| 289 }; | |
| 290 | |
| 291 struct IReporterFactory { | |
| 292 virtual ~IReporterFactory() {} | |
| 293 virtual IReporter* create( const IReporterConfig& config ) const = 0; | |
| 294 virtual std::string getDescription() const = 0; | |
| 295 }; | |
| 296 | |
| 297 struct IReporterRegistry { | |
| 298 typedef std::map<std::string, IReporterFactory*> FactoryMap; | |
| 299 | |
| 300 virtual ~IReporterRegistry() {} | |
| 301 virtual IReporter* create( const std::string& name, const IReporterConfig& config ) const = 0; | |
| 302 virtual void registerReporter( const std::string& name, IReporterFactory* factory ) = 0; | |
| 303 virtual const FactoryMap& getFactories() const = 0; | |
| 304 }; | |
| 305 | |
| 306 inline std::string trim( const std::string& str ) { | |
| 307 std::string::size_type start = str.find_first_not_of( "\n\r\t " ); | |
| 308 std::string::size_type end = str.find_last_not_of( "\n\r\t " ); | |
| 309 | |
| 310 return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 // #included from: catch_interfaces_config.h | |
| 315 | |
| 316 namespace Catch { | |
| 317 | |
| 318 struct IConfig { | |
| 319 | |
| 320 virtual ~IConfig(){} | |
| 321 | |
| 322 virtual bool allowThrows() const = 0; | |
| 323 }; | |
| 324 } | |
| 325 | |
| 326 #include <memory> | |
| 327 #include <vector> | |
| 328 #include <stdlib.h> | |
| 329 | |
| 330 namespace Catch { | |
| 331 | |
| 332 class TestCaseInfo; | |
| 333 struct IResultCapture; | |
| 334 struct ITestCaseRegistry; | |
| 335 struct IRunner; | |
| 336 struct IExceptionTranslatorRegistry; | |
| 337 class GeneratorsForTest; | |
| 338 | |
| 339 class StreamBufBase : public std::streambuf{}; | |
| 340 | |
| 341 struct IContext | |
| 342 { | |
| 343 virtual ~IContext(){} | |
| 344 | |
| 345 virtual IResultCapture& getResultCapture() = 0; | |
| 346 virtual IRunner& getRunner() = 0; | |
| 347 virtual IReporterRegistry& getReporterRegistry() = 0; | |
| 348 virtual ITestCaseRegistry& getTestCaseRegistry() = 0; | |
| 349 virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; | |
| 350 virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) = 0; | |
| 351 virtual bool advanceGeneratorsForCurrentTest() = 0; | |
| 352 virtual const IConfig* getConfig() const = 0; | |
| 353 }; | |
| 354 | |
| 355 struct IMutableContext : IContext | |
| 356 { | |
| 357 virtual void setResultCapture( IResultCapture* resultCapture ) = 0; | |
| 358 virtual void setRunner( IRunner* runner ) = 0; | |
| 359 virtual void setConfig( const IConfig* config ) = 0; | |
| 360 }; | |
| 361 | |
| 362 IContext& getCurrentContext(); | |
| 363 IMutableContext& getCurrentMutableContext(); | |
| 364 | |
| 365 class Context : public IMutableContext { | |
| 366 | |
| 367 Context(); | |
| 368 Context( const Context& ); | |
| 369 void operator=( const Context& ); | |
| 370 | |
| 371 public: // IContext | |
| 372 virtual IResultCapture& getResultCapture(); | |
| 373 virtual IRunner& getRunner(); | |
| 374 virtual IReporterRegistry& getReporterRegistry(); | |
| 375 virtual ITestCaseRegistry& getTestCaseRegistry(); | |
| 376 virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry(); | |
| 377 virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize ); | |
| 378 virtual bool advanceGeneratorsForCurrentTest(); | |
| 379 virtual const IConfig* getConfig() const; | |
| 380 | |
| 381 public: // IMutableContext | |
| 382 virtual void setResultCapture( IResultCapture* resultCapture ); | |
| 383 virtual void setRunner( IRunner* runner ); | |
| 384 virtual void setConfig( const IConfig* config ); | |
| 385 | |
| 386 public: // Statics | |
| 387 static std::streambuf* createStreamBuf( const std::string& streamName ); | |
| 388 static void cleanUp(); | |
| 389 | |
| 390 friend IMutableContext& getCurrentMutableContext(); | |
| 391 | |
| 392 private: | |
| 393 GeneratorsForTest* findGeneratorsForCurrentTest(); | |
| 394 GeneratorsForTest& getGeneratorsForCurrentTest(); | |
| 395 | |
| 396 private: | |
| 397 std::auto_ptr<IReporterRegistry> m_reporterRegistry; | |
| 398 std::auto_ptr<ITestCaseRegistry> m_testCaseRegistry; | |
| 399 std::auto_ptr<IExceptionTranslatorRegistry> m_exceptionTranslatorRegistry; | |
| 400 IRunner* m_runner; | |
| 401 IResultCapture* m_resultCapture; | |
| 402 const IConfig* m_config; | |
| 403 std::map<std::string, GeneratorsForTest*> m_generatorsByTestName; | |
| 404 }; | |
| 405 } | |
| 406 | |
| 407 // #included from: internal/catch_test_registry.hpp | |
| 408 | |
| 409 // #included from: catch_interfaces_testcase.h | |
| 410 | |
| 411 #include <vector> | |
| 412 | |
| 413 namespace Catch { | |
| 414 struct ITestCase { | |
| 415 virtual ~ITestCase(){} | |
| 416 virtual void invoke () const = 0; | |
| 417 virtual ITestCase* clone() const = 0; | |
| 418 virtual bool operator == ( const ITestCase& other ) const = 0; | |
| 419 virtual bool operator < ( const ITestCase& other ) const = 0; | |
| 420 }; | |
| 421 | |
| 422 class TestCaseInfo; | |
| 423 | |
| 424 struct ITestCaseRegistry { | |
| 425 virtual ~ITestCaseRegistry(){} | |
| 426 virtual void registerTest( const TestCaseInfo& testInfo ) = 0; | |
| 427 virtual const std::vector<TestCaseInfo>& getAllTests() const = 0; | |
| 428 virtual std::vector<TestCaseInfo> getMatchingTestCases( const std::string& rawTestSpec ) = 0; | |
| 429 }; | |
| 430 } | |
| 431 | |
| 432 namespace Catch { | |
| 433 | |
| 434 template<typename C> | |
| 435 class MethodTestCase : public ITestCase { | |
| 436 | |
| 437 public: | |
| 438 MethodTestCase( void (C::*method)() ) : m_method( method ) {} | |
| 439 | |
| 440 virtual void invoke() const { | |
| 441 C obj; | |
| 442 (obj.*m_method)(); | |
| 443 } | |
| 444 | |
| 445 virtual ITestCase* clone() const { | |
| 446 return new MethodTestCase<C>( m_method ); | |
| 447 } | |
| 448 | |
| 449 virtual bool operator == ( const ITestCase& other ) const { | |
| 450 const MethodTestCase* mtOther = dynamic_cast<const MethodTestCase*>( &other ); | |
| 451 return mtOther && m_method == mtOther->m_method; | |
| 452 } | |
| 453 | |
| 454 virtual bool operator < ( const ITestCase& other ) const { | |
| 455 const MethodTestCase* mtOther = dynamic_cast<const MethodTestCase*>( &other ); | |
| 456 return mtOther && &m_method < &mtOther->m_method; | |
| 457 } | |
| 458 | |
| 459 private: | |
| 460 void (C::*m_method)(); | |
| 461 }; | |
| 462 | |
| 463 typedef void(*TestFunction)(); | |
| 464 | |
| 465 struct AutoReg { | |
| 466 | |
| 467 AutoReg( TestFunction function, | |
| 468 const char* name, | |
| 469 const char* description, | |
| 470 const SourceLineInfo& lineInfo ); | |
| 471 | |
| 472 template<typename C> | |
| 473 AutoReg( void (C::*method)(), | |
| 474 const char* name, | |
| 475 const char* description, | |
| 476 const SourceLineInfo& lineInfo ) { | |
| 477 registerTestCase( new MethodTestCase<C>( method ), name, description, lineInfo ); | |
| 478 } | |
| 479 | |
| 480 void registerTestCase( ITestCase* testCase, | |
| 481 const char* name, | |
| 482 const char* description, | |
| 483 const SourceLineInfo& lineInfo ); | |
| 484 | |
| 485 ~AutoReg(); | |
| 486 | |
| 487 private: | |
| 488 AutoReg( const AutoReg& ); | |
| 489 void operator= ( const AutoReg& ); | |
| 490 }; | |
| 491 | |
| 492 } // end namespace Catch | |
| 493 | |
| 494 /////////////////////////////////////////////////////////////////////////////// | |
| 495 #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ | |
| 496 static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )(); \ | |
| 497 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ ), Name, Desc, CATCH_INTERNAL_LINEINFO ); }\ | |
| 498 static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )() | |
| 499 | |
| 500 /////////////////////////////////////////////////////////////////////////////// | |
| 501 #define INTERNAL_CATCH_TESTCASE_NORETURN( Name, Desc ) \ | |
| 502 static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )() ATTRIBUTE_NORETURN; \ | |
| 503 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ ), Name, Desc, CATCH_INTERNAL_LINEINFO ); }\ | |
| 504 static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )() | |
| 505 | |
| 506 /////////////////////////////////////////////////////////////////////////////// | |
| 507 #define CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ | |
| 508 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, Name, Desc, CATCH_INTERNAL_LINEINFO ); } | |
| 509 | |
| 510 /////////////////////////////////////////////////////////////////////////////// | |
| 511 #define TEST_CASE_METHOD( ClassName, TestName, Desc )\ | |
| 512 namespace{ \ | |
| 513 struct INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ ) : ClassName{ \ | |
| 514 void test(); \ | |
| 515 }; \ | |
| 516 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ )::test, TestName, Desc, CATCH_INTERNAL_LINEINFO ); \ | |
| 517 } \ | |
| 518 void INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ )::test() | |
| 519 | |
| 520 // #included from: internal/catch_capture.hpp | |
| 521 | |
| 522 // #included from: catch_expression_builder.hpp | |
| 523 | |
| 524 // #included from: catch_expression.hpp | |
| 525 | |
| 526 // #included from: catch_resultinfo_builder.hpp | |
| 527 | |
| 528 // #included from: catch_tostring.hpp | |
| 529 | |
| 530 #include <sstream> | |
| 531 | |
| 532 namespace Catch { | |
| 533 namespace Detail { | |
| 534 | |
| 535 struct NonStreamable { | |
| 536 template<typename T> NonStreamable( const T& ){} | |
| 537 }; | |
| 538 | |
| 539 // If the type does not have its own << overload for ostream then | |
| 540 // this one will be used instead | |
| 541 inline std::ostream& operator << ( std::ostream& ss, NonStreamable ){ | |
| 542 return ss << "{?}"; | |
| 543 } | |
| 544 | |
| 545 template<typename T> | |
| 546 inline std::string makeString( const T& value ) { | |
| 547 std::ostringstream oss; | |
| 548 oss << value; | |
| 549 return oss.str(); | |
| 550 } | |
| 551 | |
| 552 template<typename T> | |
| 553 inline std::string makeString( T* p ) { | |
| 554 if( !p ) | |
| 555 return INTERNAL_CATCH_STRINGIFY( NULL ); | |
| 556 std::ostringstream oss; | |
| 557 oss << p; | |
| 558 return oss.str(); | |
| 559 } | |
| 560 | |
| 561 template<typename T> | |
| 562 inline std::string makeString( const T* p ) { | |
| 563 if( !p ) | |
| 564 return INTERNAL_CATCH_STRINGIFY( NULL ); | |
| 565 std::ostringstream oss; | |
| 566 oss << p; | |
| 567 return oss.str(); | |
| 568 } | |
| 569 | |
| 570 } // end namespace Detail | |
| 571 | |
| 572 /// \brief converts any type to a string | |
| 573 /// | |
| 574 /// The default template forwards on to ostringstream - except when an | |
| 575 /// ostringstream overload does not exist - in which case it attempts to detect | |
| 576 /// that and writes {?}. | |
| 577 /// Overload (not specialise) this template for custom typs that you don't want | |
| 578 /// to provide an ostream overload for. | |
| 579 template<typename T> | |
| 580 std::string toString( const T& value ) { | |
| 581 return Detail::makeString( value ); | |
| 582 } | |
| 583 | |
| 584 // Built in overloads | |
| 585 | |
| 586 inline std::string toString( const std::string& value ) { | |
| 587 return "\"" + value + "\""; | |
| 588 } | |
| 589 | |
| 590 inline std::string toString( const std::wstring& value ) { | |
| 591 std::ostringstream oss; | |
| 592 oss << "\""; | |
| 593 for(size_t i = 0; i < value.size(); ++i ) | |
| 594 oss << static_cast<char>( value[i] <= 0xff ? value[i] : '?'); | |
| 595 oss << "\""; | |
| 596 return oss.str(); | |
| 597 } | |
| 598 | |
| 599 inline std::string toString( const char* const value ) { | |
| 600 return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); | |
| 601 } | |
| 602 | |
| 603 inline std::string toString( char* const value ) { | |
| 604 return Catch::toString( static_cast<const char*>( value ) ); | |
| 605 } | |
| 606 | |
| 607 inline std::string toString( int value ) { | |
| 608 std::ostringstream oss; | |
| 609 oss << value; | |
| 610 return oss.str(); | |
| 611 } | |
| 612 | |
| 613 inline std::string toString( unsigned long value ) { | |
| 614 std::ostringstream oss; | |
| 615 if( value > 8192 ) | |
| 616 oss << "0x" << std::hex << value; | |
| 617 else | |
| 618 oss << value; | |
| 619 return oss.str(); | |
| 620 } | |
| 621 | |
| 622 inline std::string toString( unsigned int value ) { | |
| 623 return toString( static_cast<unsigned long>( value ) ); | |
| 624 } | |
| 625 | |
| 626 inline std::string toString( const double value ) { | |
| 627 std::ostringstream oss; | |
| 628 oss << value; | |
| 629 return oss.str(); | |
| 630 } | |
| 631 | |
| 632 inline std::string toString( bool value ) { | |
| 633 return value ? "true" : "false"; | |
| 634 } | |
| 635 | |
| 636 inline std::string toString( char value ) { | |
| 637 return value < ' ' | |
| 638 ? toString( (unsigned int)value ) | |
| 639 : Detail::makeString( value ); | |
| 640 } | |
| 641 | |
| 642 inline std::string toString( signed char value ) { | |
| 643 return toString( static_cast<char>( value ) ); | |
| 644 } | |
| 645 | |
| 646 #ifdef CATCH_CONFIG_CPP11_NULLPTR | |
| 647 inline std::string toString( std::nullptr_t ) { | |
| 648 return "nullptr"; | |
| 649 } | |
| 650 #endif | |
| 651 | |
| 652 } // end namespace Catch | |
| 653 | |
| 654 // #included from: catch_resultinfo.hpp | |
| 655 | |
| 656 #include <string> | |
| 657 // #included from: catch_result_type.h | |
| 658 | |
| 659 namespace Catch { | |
| 660 | |
| 661 struct ResultWas { enum OfType { | |
| 662 Unknown = -1, | |
| 663 Ok = 0, | |
| 664 Info = 1, | |
| 665 Warning = 2, | |
| 666 | |
| 667 FailureBit = 0x10, | |
| 668 | |
| 669 ExpressionFailed = FailureBit | 1, | |
| 670 ExplicitFailure = FailureBit | 2, | |
| 671 | |
| 672 Exception = 0x100 | FailureBit, | |
| 673 | |
| 674 ThrewException = Exception | 1, | |
| 675 DidntThrowException = Exception | 2 | |
| 676 | |
| 677 }; }; | |
| 678 | |
| 679 struct ResultAction { enum Value { | |
| 680 None, | |
| 681 Failed = 1, // Failure - but no debug break if Debug bit not set | |
| 682 Debug = 2, // If this bit is set, invoke the debugger | |
| 683 Abort = 4 // Test run should abort | |
| 684 }; }; | |
| 685 | |
| 686 } | |
| 687 | |
| 688 | |
| 689 namespace Catch { | |
| 690 | |
| 691 class ResultInfo { | |
| 692 public: | |
| 693 ResultInfo() | |
| 694 : m_macroName(), | |
| 695 m_expr(), | |
| 696 m_lhs(), | |
| 697 m_rhs(), | |
| 698 m_op(), | |
| 699 m_message(), | |
| 700 m_result( ResultWas::Unknown ), | |
| 701 m_isNot( false ) | |
| 702 {} | |
| 703 | |
| 704 ResultInfo( const char* expr, | |
| 705 ResultWas::OfType result, | |
| 706 bool isNot, | |
| 707 const SourceLineInfo& lineInfo, | |
| 708 const char* macroName, | |
| 709 const char* message ) | |
| 710 : m_macroName( macroName ), | |
| 711 m_lineInfo( lineInfo ), | |
| 712 m_expr( expr ), | |
| 713 m_lhs(), | |
| 714 m_rhs(), | |
| 715 m_op( isNotExpression( expr ) ? "!" : "" ), | |
| 716 m_message( message ), | |
| 717 m_result( result ), | |
| 718 m_isNot( isNot ) | |
| 719 { | |
| 720 if( isNot ) | |
| 721 m_expr = "!" + m_expr; | |
| 722 } | |
| 723 | |
| 724 virtual ~ResultInfo() {} | |
| 725 | |
| 726 bool ok() const { | |
| 727 return ( m_result & ResultWas::FailureBit ) != ResultWas::FailureBit; | |
| 728 } | |
| 729 | |
| 730 ResultWas::OfType getResultType() const { | |
| 731 return m_result; | |
| 732 } | |
| 733 | |
| 734 bool hasExpression() const { | |
| 735 return !m_expr.empty(); | |
| 736 } | |
| 737 | |
| 738 bool hasMessage() const { | |
| 739 return !m_message.empty(); | |
| 740 } | |
| 741 | |
| 742 std::string getExpression() const { | |
| 743 return m_expr; | |
| 744 } | |
| 745 | |
| 746 bool hasExpandedExpression() const { | |
| 747 return hasExpression() && getExpandedExpressionInternal() != m_expr; | |
| 748 } | |
| 749 | |
| 750 std::string getExpandedExpression() const { | |
| 751 return hasExpression() ? getExpandedExpressionInternal() : ""; | |
| 752 } | |
| 753 | |
| 754 std::string getMessage() const { | |
| 755 return m_message; | |
| 756 } | |
| 757 | |
| 758 std::string getFilename() const { | |
| 759 return m_lineInfo.file; | |
| 760 } | |
| 761 | |
| 762 std::size_t getLine() const { | |
| 763 return m_lineInfo.line; | |
| 764 } | |
| 765 | |
| 766 std::string getTestMacroName() const { | |
| 767 return m_macroName; | |
| 768 } | |
| 769 | |
| 770 protected: | |
| 771 | |
| 772 std::string getExpandedExpressionInternal() const { | |
| 773 if( m_op == "" || m_isNot ) | |
| 774 return m_lhs.empty() ? m_expr : m_op + m_lhs; | |
| 775 else if( m_op == "matches" ) | |
| 776 return m_lhs + " " + m_rhs; | |
| 777 else if( m_op != "!" ) | |
| 778 { | |
| 779 if( m_lhs.size() + m_rhs.size() < 30 ) | |
| 780 return m_lhs + " " + m_op + " " + m_rhs; | |
| 781 else if( m_lhs.size() < 70 && m_rhs.size() < 70 ) | |
| 782 return "\n\t" + m_lhs + "\n\t" + m_op + "\n\t" + m_rhs; | |
| 783 else | |
| 784 return "\n" + m_lhs + "\n" + m_op + "\n" + m_rhs + "\n\n"; | |
| 785 } | |
| 786 else | |
| 787 return "{can't expand - use " + m_macroName + "_FALSE( " + m_expr.substr(1) + " ) instead of " + m_macroName + "( " + m_expr + " ) for better diagnostics}"; | |
| 788 } | |
| 789 | |
| 790 bool isNotExpression( const char* expr ) { | |
| 791 return expr && expr[0] == '!'; | |
| 792 } | |
| 793 | |
| 794 protected: | |
| 795 std::string m_macroName; | |
| 796 SourceLineInfo m_lineInfo; | |
| 797 std::string m_expr, m_lhs, m_rhs, m_op; | |
| 798 std::string m_message; | |
| 799 ResultWas::OfType m_result; | |
| 800 bool m_isNot; | |
| 801 }; | |
| 802 | |
| 803 } // end namespace Catch | |
| 804 | |
| 805 // #included from: catch_evaluate.hpp | |
| 806 | |
| 807 namespace Catch { | |
| 808 namespace Internal { | |
| 809 | |
| 810 enum Operator { | |
| 811 IsEqualTo, | |
| 812 IsNotEqualTo, | |
| 813 IsLessThan, | |
| 814 IsGreaterThan, | |
| 815 IsLessThanOrEqualTo, | |
| 816 IsGreaterThanOrEqualTo | |
| 817 }; | |
| 818 | |
| 819 template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } }; | |
| 820 template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } }; | |
| 821 template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } }; | |
| 822 template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } }; | |
| 823 template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } }; | |
| 824 template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } }; | |
| 825 template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } }; | |
| 826 | |
| 827 // So the compare overloads can be operator agnostic we convey the operator as a template | |
| 828 // enum, which is used to specialise an Evaluator for doing the comparison. | |
| 829 template<typename T1, typename T2, Operator Op> | |
| 830 class Evaluator{}; | |
| 831 | |
| 832 template<typename T1, typename T2> | |
| 833 struct Evaluator<T1, T2, IsEqualTo> { | |
| 834 static bool evaluate( const T1& lhs, const T2& rhs) { | |
| 835 return const_cast<T1&>( lhs ) == const_cast<T2&>( rhs ); | |
| 836 } | |
| 837 }; | |
| 838 template<typename T1, typename T2> | |
| 839 struct Evaluator<T1, T2, IsNotEqualTo> { | |
| 840 static bool evaluate( const T1& lhs, const T2& rhs ) { | |
| 841 return const_cast<T1&>( lhs ) != const_cast<T2&>( rhs ); | |
| 842 } | |
| 843 }; | |
| 844 template<typename T1, typename T2> | |
| 845 struct Evaluator<T1, T2, IsLessThan> { | |
| 846 static bool evaluate( const T1& lhs, const T2& rhs ) { | |
| 847 return const_cast<T1&>( lhs ) < const_cast<T2&>( rhs ); | |
| 848 } | |
| 849 }; | |
| 850 template<typename T1, typename T2> | |
| 851 struct Evaluator<T1, T2, IsGreaterThan> { | |
| 852 static bool evaluate( const T1& lhs, const T2& rhs ) { | |
| 853 return const_cast<T1&>( lhs ) > const_cast<T2&>( rhs ); | |
| 854 } | |
| 855 }; | |
| 856 template<typename T1, typename T2> | |
| 857 struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> { | |
| 858 static bool evaluate( const T1& lhs, const T2& rhs ) { | |
| 859 return const_cast<T1&>( lhs ) >= const_cast<T2&>( rhs ); | |
| 860 } | |
| 861 }; | |
| 862 template<typename T1, typename T2> | |
| 863 struct Evaluator<T1, T2, IsLessThanOrEqualTo> { | |
| 864 static bool evaluate( const T1& lhs, const T2& rhs ) { | |
| 865 return const_cast<T1&>( lhs ) <= const_cast<T2&>( rhs ); | |
| 866 } | |
| 867 }; | |
| 868 | |
| 869 template<Operator Op, typename T1, typename T2> | |
| 870 bool applyEvaluator( const T1& lhs, const T2& rhs ) { | |
| 871 return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); | |
| 872 } | |
| 873 | |
| 874 // "base" overload | |
| 875 template<Operator Op, typename T1, typename T2> | |
| 876 bool compare( const T1& lhs, const T2& rhs ) { | |
| 877 return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); | |
| 878 } | |
| 879 | |
| 880 // unsigned X to int | |
| 881 template<Operator Op> bool compare( unsigned int lhs, int rhs ) { | |
| 882 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); | |
| 883 } | |
| 884 template<Operator Op> bool compare( unsigned long lhs, int rhs ) { | |
| 885 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); | |
| 886 } | |
| 887 template<Operator Op> bool compare( unsigned char lhs, int rhs ) { | |
| 888 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); | |
| 889 } | |
| 890 | |
| 891 // unsigned X to long | |
| 892 template<Operator Op> bool compare( unsigned int lhs, long rhs ) { | |
| 893 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); | |
| 894 } | |
| 895 template<Operator Op> bool compare( unsigned long lhs, long rhs ) { | |
| 896 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); | |
| 897 } | |
| 898 template<Operator Op> bool compare( unsigned char lhs, long rhs ) { | |
| 899 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); | |
| 900 } | |
| 901 | |
| 902 // int to unsigned X | |
| 903 template<Operator Op> bool compare( int lhs, unsigned int rhs ) { | |
| 904 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); | |
| 905 } | |
| 906 template<Operator Op> bool compare( int lhs, unsigned long rhs ) { | |
| 907 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); | |
| 908 } | |
| 909 template<Operator Op> bool compare( int lhs, unsigned char rhs ) { | |
| 910 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); | |
| 911 } | |
| 912 | |
| 913 // long to unsigned X | |
| 914 template<Operator Op> bool compare( long lhs, unsigned int rhs ) { | |
| 915 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
| 916 } | |
| 917 template<Operator Op> bool compare( long lhs, unsigned long rhs ) { | |
| 918 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
| 919 } | |
| 920 template<Operator Op> bool compare( long lhs, unsigned char rhs ) { | |
| 921 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
| 922 } | |
| 923 | |
| 924 // pointer to long (when comparing against NULL) | |
| 925 template<Operator Op, typename T> | |
| 926 bool compare( long lhs, const T* rhs ) { | |
| 927 return Evaluator<const T*, const T*, Op>::evaluate( reinterpret_cast<const T*>( lhs ), rhs ); | |
| 928 } | |
| 929 | |
| 930 template<Operator Op, typename T> | |
| 931 bool compare( long lhs, T* rhs ) { | |
| 932 return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); | |
| 933 } | |
| 934 | |
| 935 template<Operator Op, typename T> | |
| 936 bool compare( const T* lhs, long rhs ) { | |
| 937 return Evaluator<const T*, const T*, Op>::evaluate( lhs, reinterpret_cast<const T*>( rhs ) ); | |
| 938 } | |
| 939 | |
| 940 template<Operator Op, typename T> | |
| 941 bool compare( T* lhs, long rhs ) { | |
| 942 return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); | |
| 943 } | |
| 944 | |
| 945 // pointer to int (when comparing against NULL) | |
| 946 template<Operator Op, typename T> | |
| 947 bool compare( int lhs, const T* rhs ) { | |
| 948 return Evaluator<const T*, const T*, Op>::evaluate( reinterpret_cast<const T*>( lhs ), rhs ); | |
| 949 } | |
| 950 | |
| 951 template<Operator Op, typename T> | |
| 952 bool compare( int lhs, T* rhs ) { | |
| 953 return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); | |
| 954 } | |
| 955 | |
| 956 template<Operator Op, typename T> | |
| 957 bool compare( const T* lhs, int rhs ) { | |
| 958 return Evaluator<const T*, const T*, Op>::evaluate( lhs, reinterpret_cast<const T*>( rhs ) ); | |
| 959 } | |
| 960 | |
| 961 template<Operator Op, typename T> | |
| 962 bool compare( T* lhs, int rhs ) { | |
| 963 return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); | |
| 964 } | |
| 965 | |
| 966 } // end of namespace Internal | |
| 967 } // end of namespace Catch | |
| 968 | |
| 969 namespace Catch { | |
| 970 | |
| 971 struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; | |
| 972 | |
| 973 class ResultInfoBuilder : public ResultInfo { | |
| 974 | |
| 975 public: | |
| 976 | |
| 977 ResultInfoBuilder() {} | |
| 978 | |
| 979 ResultInfoBuilder( const char* expr, | |
| 980 bool isNot, | |
| 981 const SourceLineInfo& lineInfo, | |
| 982 const char* macroName, | |
| 983 const char* message = "" ) | |
| 984 : ResultInfo( expr, ResultWas::Unknown, isNot, lineInfo, macroName, message ) | |
| 985 {} | |
| 986 | |
| 987 void setResultType( ResultWas::OfType result ) { | |
| 988 // Flip bool results if isNot is set | |
| 989 if( m_isNot && result == ResultWas::Ok ) | |
| 990 m_result = ResultWas::ExpressionFailed; | |
| 991 else if( m_isNot && result == ResultWas::ExpressionFailed ) | |
| 992 m_result = ResultWas::Ok; | |
| 993 else | |
| 994 m_result = result; | |
| 995 } | |
| 996 | |
| 997 void setMessage( const std::string& message ) { | |
| 998 m_message = message; | |
| 999 } | |
| 1000 | |
| 1001 void setLineInfo( const SourceLineInfo& lineInfo ) { | |
| 1002 m_lineInfo = lineInfo; | |
| 1003 } | |
| 1004 | |
| 1005 void setLhs( const std::string& lhs ) { | |
| 1006 m_lhs = lhs; | |
| 1007 } | |
| 1008 | |
| 1009 void setRhs( const std::string& rhs ) { | |
| 1010 m_rhs = rhs; | |
| 1011 } | |
| 1012 | |
| 1013 void setOp( const std::string& op ) { | |
| 1014 m_op = op; | |
| 1015 } | |
| 1016 | |
| 1017 template<typename RhsT> | |
| 1018 STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || | |
| 1019 ( | |
| 1020 const RhsT& | |
| 1021 ); | |
| 1022 | |
| 1023 template<typename RhsT> | |
| 1024 STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && | |
| 1025 ( | |
| 1026 const RhsT& | |
| 1027 ); | |
| 1028 | |
| 1029 private: | |
| 1030 friend class ExpressionBuilder; | |
| 1031 template<typename T> friend class Expression; | |
| 1032 | |
| 1033 template<typename T> friend class PtrExpression; | |
| 1034 | |
| 1035 ResultInfoBuilder& captureBoolExpression( bool result ) { | |
| 1036 m_lhs = Catch::toString( result ); | |
| 1037 m_op = m_isNot ? "!" : ""; | |
| 1038 setResultType( result ? ResultWas::Ok : ResultWas::ExpressionFailed ); | |
| 1039 return *this; | |
| 1040 } | |
| 1041 | |
| 1042 template<Internal::Operator Op, typename T1, typename T2> | |
| 1043 ResultInfoBuilder& captureExpression( const T1& lhs, const T2& rhs ) { | |
| 1044 setResultType( Internal::compare<Op>( lhs, rhs ) ? ResultWas::Ok : ResultWas::ExpressionFailed ); | |
| 1045 m_lhs = Catch::toString( lhs ); | |
| 1046 m_rhs = Catch::toString( rhs ); | |
| 1047 m_op = Internal::OperatorTraits<Op>::getName(); | |
| 1048 return *this; | |
| 1049 } | |
| 1050 | |
| 1051 template<Internal::Operator Op, typename T> | |
| 1052 ResultInfoBuilder& captureExpression( const T* lhs, int rhs ) { | |
| 1053 return captureExpression<Op>( lhs, reinterpret_cast<const T*>( rhs ) ); | |
| 1054 } | |
| 1055 }; | |
| 1056 | |
| 1057 } // end namespace Catch | |
| 1058 | |
| 1059 namespace Catch { | |
| 1060 | |
| 1061 template<typename T> | |
| 1062 class Expression { | |
| 1063 void operator = ( const Expression& ); | |
| 1064 | |
| 1065 public: | |
| 1066 Expression( ResultInfoBuilder& result, T lhs ) | |
| 1067 : m_result( result ), | |
| 1068 m_lhs( lhs ) | |
| 1069 {} | |
| 1070 | |
| 1071 template<typename RhsT> | |
| 1072 ResultInfoBuilder& operator == ( const RhsT& rhs ) { | |
| 1073 return m_result.captureExpression<Internal::IsEqualTo>( m_lhs, rhs ); | |
| 1074 } | |
| 1075 | |
| 1076 template<typename RhsT> | |
| 1077 ResultInfoBuilder& operator != ( const RhsT& rhs ) { | |
| 1078 return m_result.captureExpression<Internal::IsNotEqualTo>( m_lhs, rhs ); | |
| 1079 } | |
| 1080 | |
| 1081 template<typename RhsT> | |
| 1082 ResultInfoBuilder& operator < ( const RhsT& rhs ) { | |
| 1083 return m_result.captureExpression<Internal::IsLessThan>( m_lhs, rhs ); | |
| 1084 } | |
| 1085 | |
| 1086 template<typename RhsT> | |
| 1087 ResultInfoBuilder& operator > ( const RhsT& rhs ) { | |
| 1088 return m_result.captureExpression<Internal::IsGreaterThan>( m_lhs, rhs ); | |
| 1089 } | |
| 1090 | |
| 1091 template<typename RhsT> | |
| 1092 ResultInfoBuilder& operator <= ( const RhsT& rhs ) { | |
| 1093 return m_result.captureExpression<Internal::IsLessThanOrEqualTo>( m_lhs, rhs ); | |
| 1094 } | |
| 1095 | |
| 1096 template<typename RhsT> | |
| 1097 ResultInfoBuilder& operator >= ( const RhsT& rhs ) { | |
| 1098 return m_result.captureExpression<Internal::IsGreaterThanOrEqualTo>( m_lhs, rhs ); | |
| 1099 } | |
| 1100 | |
| 1101 ResultInfoBuilder& operator == ( bool rhs ) { | |
| 1102 return m_result.captureExpression<Internal::IsEqualTo>( m_lhs, rhs ); | |
| 1103 } | |
| 1104 | |
| 1105 ResultInfoBuilder& operator != ( bool rhs ) { | |
| 1106 return m_result.captureExpression<Internal::IsNotEqualTo>( m_lhs, rhs ); | |
| 1107 } | |
| 1108 | |
| 1109 operator ResultInfoBuilder& () { | |
| 1110 return m_result.captureBoolExpression( m_lhs ); | |
| 1111 } | |
| 1112 | |
| 1113 template<typename RhsT> | |
| 1114 STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( const RhsT& ); | |
| 1115 | |
| 1116 template<typename RhsT> | |
| 1117 STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( const RhsT& ); | |
| 1118 | |
| 1119 private: | |
| 1120 ResultInfoBuilder& m_result; | |
| 1121 T m_lhs; | |
| 1122 }; | |
| 1123 | |
| 1124 } // end namespace Catch | |
| 1125 | |
| 1126 #include <sstream> | |
| 1127 | |
| 1128 namespace Catch { | |
| 1129 | |
| 1130 class ExpressionBuilder { | |
| 1131 public: | |
| 1132 | |
| 1133 ExpressionBuilder( const SourceLineInfo& lineInfo, | |
| 1134 const char* macroName, | |
| 1135 const char* expr = "", | |
| 1136 bool isNot = false ) | |
| 1137 : m_result( expr, isNot, lineInfo, macroName ), | |
| 1138 m_messageStream() | |
| 1139 {} | |
| 1140 | |
| 1141 template<typename T> | |
| 1142 Expression<const T&> operator->* ( const T & operand ) { | |
| 1143 Expression<const T&> expr( m_result, operand ); | |
| 1144 return expr; | |
| 1145 } | |
| 1146 | |
| 1147 Expression<bool> operator->* ( bool value ) { | |
| 1148 Expression<bool> expr( m_result, value ); | |
| 1149 return expr; | |
| 1150 } | |
| 1151 | |
| 1152 template<typename T> | |
| 1153 ExpressionBuilder& operator << ( const T & value ) { | |
| 1154 m_messageStream << Catch::toString( value ); | |
| 1155 return *this; | |
| 1156 } | |
| 1157 | |
| 1158 template<typename MatcherT, typename ArgT> | |
| 1159 ExpressionBuilder& acceptMatcher( const MatcherT& matcher, | |
| 1160 const ArgT& arg, | |
| 1161 const std::string& matcherCallAsString ) { | |
| 1162 std::string matcherAsString = Catch::toString( matcher ); | |
| 1163 if( matcherAsString == "{?}" ) | |
| 1164 matcherAsString = matcherCallAsString; | |
| 1165 m_result.setLhs( Catch::toString( arg ) ); | |
| 1166 m_result.setRhs( matcherAsString ); | |
| 1167 m_result.setOp( "matches" ); | |
| 1168 m_result.setResultType( matcher( arg ) ? ResultWas::Ok : ResultWas::ExpressionFailed ); | |
| 1169 return *this; | |
| 1170 } | |
| 1171 | |
| 1172 template<typename MatcherT, typename ArgT> | |
| 1173 ExpressionBuilder& acceptMatcher( const MatcherT& matcher, | |
| 1174 ArgT* arg, | |
| 1175 const std::string& matcherCallAsString ) { | |
| 1176 std::string matcherAsString = Catch::toString( matcher ); | |
| 1177 if( matcherAsString == "{?}" ) | |
| 1178 matcherAsString = matcherCallAsString; | |
| 1179 m_result.setLhs( Catch::toString( arg ) ); | |
| 1180 m_result.setRhs( matcherAsString ); | |
| 1181 m_result.setOp( "matches" ); | |
| 1182 m_result.setResultType( matcher( arg ) ? ResultWas::Ok : ResultWas::ExpressionFailed ); | |
| 1183 return *this; | |
| 1184 } | |
| 1185 | |
| 1186 ExpressionBuilder& setResultType( ResultWas::OfType resultType ) { | |
| 1187 m_result.setResultType( resultType ); | |
| 1188 return *this; | |
| 1189 } | |
| 1190 | |
| 1191 operator ResultInfoBuilder&() { | |
| 1192 m_result.setMessage( m_messageStream.str() ); | |
| 1193 return m_result; | |
| 1194 } | |
| 1195 | |
| 1196 private: | |
| 1197 ResultInfoBuilder m_result; | |
| 1198 std::ostringstream m_messageStream; | |
| 1199 }; | |
| 1200 | |
| 1201 } // end namespace Catch | |
| 1202 | |
| 1203 // #included from: catch_interfaces_capture.h | |
| 1204 | |
| 1205 #include <string> | |
| 1206 | |
| 1207 namespace Catch { | |
| 1208 | |
| 1209 class TestCaseInfo; | |
| 1210 class ScopedInfo; | |
| 1211 class ResultInfoBuilder; | |
| 1212 class ResultInfo; | |
| 1213 | |
| 1214 struct IResultCapture { | |
| 1215 | |
| 1216 virtual ~IResultCapture(){} | |
| 1217 | |
| 1218 virtual void testEnded( const ResultInfo& result ) = 0; | |
| 1219 virtual bool sectionStarted( const std::string& name, | |
| 1220 const std::string& description, | |
| 1221 const SourceLineInfo& lineInfo, | |
| 1222 Counts& assertions ) = 0; | |
| 1223 virtual void sectionEnded( const std::string& name, const Counts& assertions ) = 0; | |
| 1224 virtual void pushScopedInfo( ScopedInfo* scopedInfo ) = 0; | |
| 1225 virtual void popScopedInfo( ScopedInfo* scopedInfo ) = 0; | |
| 1226 virtual bool shouldDebugBreak() const = 0; | |
| 1227 | |
| 1228 virtual ResultAction::Value acceptResult( bool result ) = 0; | |
| 1229 virtual ResultAction::Value acceptResult( ResultWas::OfType result ) = 0; | |
| 1230 virtual ResultAction::Value acceptExpression( const ResultInfoBuilder& resultInfo ) = 0; | |
| 1231 virtual void acceptMessage( const std::string& msg ) = 0; | |
| 1232 | |
| 1233 virtual std::string getCurrentTestName() const = 0; | |
| 1234 virtual const ResultInfo* getLastResult() const = 0; | |
| 1235 }; | |
| 1236 } | |
| 1237 | |
| 1238 // #included from: catch_debugger.hpp | |
| 1239 | |
| 1240 #include <iostream> | |
| 1241 | |
| 1242 #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) | |
| 1243 #define CATCH_PLATFORM_MAC | |
| 1244 #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) | |
| 1245 #define CATCH_PLATFORM_IPHONE | |
| 1246 #elif defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) | |
| 1247 #define CATCH_PLATFORM_WINDOWS | |
| 1248 #endif | |
| 1249 | |
| 1250 #ifdef CATCH_PLATFORM_MAC | |
| 1251 | |
| 1252 #include <assert.h> | |
| 1253 #include <stdbool.h> | |
| 1254 #include <sys/types.h> | |
| 1255 #include <unistd.h> | |
| 1256 #include <sys/sysctl.h> | |
| 1257 | |
| 1258 namespace Catch{ | |
| 1259 | |
| 1260 // The following function is taken directly from the following technical note: | |
| 1261 // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html | |
| 1262 | |
| 1263 // Returns true if the current process is being debugged (either | |
| 1264 // running under the debugger or has a debugger attached post facto). | |
| 1265 inline bool isDebuggerActive(){ | |
| 1266 | |
| 1267 int junk; | |
| 1268 int mib[4]; | |
| 1269 struct kinfo_proc info; | |
| 1270 size_t size; | |
| 1271 | |
| 1272 // Initialize the flags so that, if sysctl fails for some bizarre | |
| 1273 // reason, we get a predictable result. | |
| 1274 | |
| 1275 info.kp_proc.p_flag = 0; | |
| 1276 | |
| 1277 // Initialize mib, which tells sysctl the info we want, in this case | |
| 1278 // we're looking for information about a specific process ID. | |
| 1279 | |
| 1280 mib[0] = CTL_KERN; | |
| 1281 mib[1] = KERN_PROC; | |
| 1282 mib[2] = KERN_PROC_PID; | |
| 1283 mib[3] = getpid(); | |
| 1284 | |
| 1285 // Call sysctl. | |
| 1286 | |
| 1287 size = sizeof(info); | |
| 1288 junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); | |
| 1289 assert(junk == 0); | |
| 1290 | |
| 1291 // We're being debugged if the P_TRACED flag is set. | |
| 1292 | |
| 1293 return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); | |
| 1294 } | |
| 1295 } | |
| 1296 | |
| 1297 // The following code snippet taken from: | |
| 1298 // http://cocoawithlove.com/2008/03/break-into-debugger.html | |
| 1299 #ifdef DEBUG | |
| 1300 #if defined(__ppc64__) || defined(__ppc__) | |
| 1301 #define BreakIntoDebugger() \ | |
| 1302 if( Catch::isDebuggerActive() ) { \ | |
| 1303 __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ | |
| 1304 : : : "memory","r0","r3","r4" ); \ | |
| 1305 } | |
| 1306 #else | |
| 1307 #define BreakIntoDebugger() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} | |
| 1308 #endif | |
| 1309 #else | |
| 1310 inline void BreakIntoDebugger(){} | |
| 1311 #endif | |
| 1312 | |
| 1313 #elif defined(_MSC_VER) | |
| 1314 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); | |
| 1315 #define BreakIntoDebugger() if (IsDebuggerPresent() ) { __debugbreak(); } | |
| 1316 inline bool isDebuggerActive() { | |
| 1317 return IsDebuggerPresent() != 0; | |
| 1318 } | |
| 1319 #elif defined(__MINGW32__) | |
| 1320 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); | |
| 1321 extern "C" __declspec(dllimport) void __stdcall DebugBreak(); | |
| 1322 #define BreakIntoDebugger() if (IsDebuggerPresent() ) { DebugBreak(); } | |
| 1323 inline bool isDebuggerActive() { | |
| 1324 return IsDebuggerPresent() != 0; | |
| 1325 } | |
| 1326 #else | |
| 1327 inline void BreakIntoDebugger(){} | |
| 1328 inline bool isDebuggerActive() { return false; } | |
| 1329 #endif | |
| 1330 | |
| 1331 #ifdef CATCH_PLATFORM_WINDOWS | |
| 1332 extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); | |
| 1333 inline void writeToDebugConsole( const std::string& text ) { | |
| 1334 ::OutputDebugStringA( text.c_str() ); | |
| 1335 } | |
| 1336 #else | |
| 1337 inline void writeToDebugConsole( const std::string& text ) { | |
| 1338 // !TBD: Need a version for Mac/ XCode and other IDEs | |
| 1339 std::cout << text; | |
| 1340 } | |
| 1341 #endif // CATCH_PLATFORM_WINDOWS | |
| 1342 | |
| 1343 #include <ostream> | |
| 1344 | |
| 1345 namespace Catch { | |
| 1346 | |
| 1347 struct TestFailureException{}; | |
| 1348 | |
| 1349 class ScopedInfo { | |
| 1350 public: | |
| 1351 ScopedInfo() : m_oss() { | |
| 1352 getCurrentContext().getResultCapture().pushScopedInfo( this ); | |
| 1353 } | |
| 1354 | |
| 1355 ~ScopedInfo() { | |
| 1356 getCurrentContext().getResultCapture().popScopedInfo( this ); | |
| 1357 } | |
| 1358 | |
| 1359 template<typename T> | |
| 1360 ScopedInfo& operator << ( const T& value ) { | |
| 1361 m_oss << value; | |
| 1362 return *this; | |
| 1363 } | |
| 1364 | |
| 1365 std::string getInfo () const { | |
| 1366 return m_oss.str(); | |
| 1367 } | |
| 1368 | |
| 1369 private: | |
| 1370 std::ostringstream m_oss; | |
| 1371 }; | |
| 1372 | |
| 1373 // This is just here to avoid compiler warnings with macro constants | |
| 1374 inline bool isTrue( bool value ){ return value; } | |
| 1375 | |
| 1376 } // end namespace Catch | |
| 1377 | |
| 1378 /////////////////////////////////////////////////////////////////////////////// | |
| 1379 #define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \ | |
| 1380 if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) { \ | |
| 1381 if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \ | |
| 1382 if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \ | |
| 1383 if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \ | |
| 1384 if( Catch::isTrue( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \ | |
| 1385 } | |
| 1386 | |
| 1387 /////////////////////////////////////////////////////////////////////////////// | |
| 1388 #define INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ) \ | |
| 1389 do { try { \ | |
| 1390 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr, isNot )->*expr ), stopOnFailure, expr ); \ | |
| 1391 } catch( Catch::TestFailureException& ) { \ | |
| 1392 throw; \ | |
| 1393 } catch( ... ) { \ | |
| 1394 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, expr ); \ | |
| 1395 throw; \ | |
| 1396 } } while( Catch::isTrue( false ) ) | |
| 1397 | |
| 1398 /////////////////////////////////////////////////////////////////////////////// | |
| 1399 #define INTERNAL_CATCH_IF( expr, isNot, stopOnFailure, macroName ) \ | |
| 1400 INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \ | |
| 1401 if( Catch::getCurrentContext().getResultCapture().getLastResult()->ok() ) | |
| 1402 | |
| 1403 /////////////////////////////////////////////////////////////////////////////// | |
| 1404 #define INTERNAL_CATCH_ELSE( expr, isNot, stopOnFailure, macroName ) \ | |
| 1405 INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \ | |
| 1406 if( !Catch::getCurrentContext().getResultCapture().getLastResult()->ok() ) | |
| 1407 | |
| 1408 /////////////////////////////////////////////////////////////////////////////// | |
| 1409 #define INTERNAL_CATCH_NO_THROW( expr, stopOnFailure, macroName ) \ | |
| 1410 try { \ | |
| 1411 expr; \ | |
| 1412 INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::Ok ), stopOnFailure, false ); \ | |
| 1413 } \ | |
| 1414 catch( ... ) { \ | |
| 1415 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \ | |
| 1416 } | |
| 1417 | |
| 1418 /////////////////////////////////////////////////////////////////////////////// | |
| 1419 #define INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \ | |
| 1420 try { \ | |
| 1421 if( Catch::getCurrentContext().getConfig()->allowThrows() ) { \ | |
| 1422 expr; \ | |
| 1423 INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::DidntThrowException ), stopOnFailure, false ); \ | |
| 1424 } \ | |
| 1425 } \ | |
| 1426 catch( Catch::TestFailureException& ) { \ | |
| 1427 throw; \ | |
| 1428 } \ | |
| 1429 catch( exceptionType ) { \ | |
| 1430 INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::Ok ), stopOnFailure, false ); \ | |
| 1431 } | |
| 1432 | |
| 1433 /////////////////////////////////////////////////////////////////////////////// | |
| 1434 #define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, stopOnFailure, macroName ) \ | |
| 1435 INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \ | |
| 1436 catch( ... ) { \ | |
| 1437 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \ | |
| 1438 } | |
| 1439 | |
| 1440 /////////////////////////////////////////////////////////////////////////////// | |
| 1441 #define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \ | |
| 1442 Catch::getCurrentContext().getResultCapture().acceptExpression( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName ) << reason ).setResultType( resultType ) ); | |
| 1443 | |
| 1444 /////////////////////////////////////////////////////////////////////////////// | |
| 1445 #define INTERNAL_CATCH_SCOPED_INFO( log ) \ | |
| 1446 Catch::ScopedInfo INTERNAL_CATCH_UNIQUE_NAME( info ); \ | |
| 1447 INTERNAL_CATCH_UNIQUE_NAME( info ) << log | |
| 1448 | |
| 1449 /////////////////////////////////////////////////////////////////////////////// | |
| 1450 #define INTERNAL_CHECK_THAT( arg, matcher, stopOnFailure, macroName ) \ | |
| 1451 do { try { \ | |
| 1452 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher, false ).acceptMatcher( ::Catch::Matchers::matcher, arg, #matcher ) ), stopOnFailure, false ); \ | |
| 1453 } catch( Catch::TestFailureException& ) { \ | |
| 1454 throw; \ | |
| 1455 } catch( ... ) { \ | |
| 1456 INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, false ); \ | |
| 1457 throw; \ | |
| 1458 }}while( Catch::isTrue( false ) ) | |
| 1459 | |
| 1460 // #included from: internal/catch_section.hpp | |
| 1461 | |
| 1462 #include <string> | |
| 1463 | |
| 1464 namespace Catch { | |
| 1465 | |
| 1466 class Section { | |
| 1467 public: | |
| 1468 Section( const std::string& name, | |
| 1469 const std::string& description, | |
| 1470 const SourceLineInfo& lineInfo ) | |
| 1471 : m_name( name ), | |
| 1472 m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( name, description, lineInfo, m_assertions ) ) | |
| 1473 {} | |
| 1474 | |
| 1475 ~Section() { | |
| 1476 if( m_sectionIncluded ) | |
| 1477 getCurrentContext().getResultCapture().sectionEnded( m_name, m_assertions ); | |
| 1478 } | |
| 1479 | |
| 1480 // This indicates whether the section should be executed or not | |
| 1481 operator bool() { | |
| 1482 return m_sectionIncluded; | |
| 1483 } | |
| 1484 | |
| 1485 private: | |
| 1486 | |
| 1487 std::string m_name; | |
| 1488 Counts m_assertions; | |
| 1489 bool m_sectionIncluded; | |
| 1490 }; | |
| 1491 | |
| 1492 } // end namespace Catch | |
| 1493 | |
| 1494 #define INTERNAL_CATCH_SECTION( name, desc ) \ | |
| 1495 if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( name, desc, CATCH_INTERNAL_LINEINFO ) ) | |
| 1496 | |
| 1497 // #included from: internal/catch_generators.hpp | |
| 1498 | |
| 1499 #include <iterator> | |
| 1500 #include <vector> | |
| 1501 #include <string> | |
| 1502 #include <stdlib.h> | |
| 1503 | |
| 1504 namespace Catch { | |
| 1505 | |
| 1506 template<typename T> | |
| 1507 struct IGenerator { | |
| 1508 virtual ~IGenerator() {} | |
| 1509 virtual T getValue( std::size_t index ) const = 0; | |
| 1510 virtual std::size_t size () const = 0; | |
| 1511 }; | |
| 1512 | |
| 1513 template<typename T> | |
| 1514 class BetweenGenerator : public IGenerator<T> { | |
| 1515 public: | |
| 1516 BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} | |
| 1517 | |
| 1518 virtual T getValue( std::size_t index ) const { | |
| 1519 return m_from+static_cast<T>( index ); | |
| 1520 } | |
| 1521 | |
| 1522 virtual std::size_t size() const { | |
| 1523 return static_cast<std::size_t>( 1+m_to-m_from ); | |
| 1524 } | |
| 1525 | |
| 1526 private: | |
| 1527 | |
| 1528 T m_from; | |
| 1529 T m_to; | |
| 1530 }; | |
| 1531 | |
| 1532 template<typename T> | |
| 1533 class ValuesGenerator : public IGenerator<T> { | |
| 1534 public: | |
| 1535 ValuesGenerator(){} | |
| 1536 | |
| 1537 void add( T value ) { | |
| 1538 m_values.push_back( value ); | |
| 1539 } | |
| 1540 | |
| 1541 virtual T getValue( std::size_t index ) const { | |
| 1542 return m_values[index]; | |
| 1543 } | |
| 1544 | |
| 1545 virtual std::size_t size() const { | |
| 1546 return m_values.size(); | |
| 1547 } | |
| 1548 | |
| 1549 private: | |
| 1550 std::vector<T> m_values; | |
| 1551 }; | |
| 1552 | |
| 1553 template<typename T> | |
| 1554 class CompositeGenerator { | |
| 1555 public: | |
| 1556 CompositeGenerator() : m_totalSize( 0 ) {} | |
| 1557 | |
| 1558 // *** Move semantics, similar to auto_ptr *** | |
| 1559 CompositeGenerator( CompositeGenerator& other ) | |
| 1560 : m_fileInfo( other.m_fileInfo ), | |
| 1561 m_totalSize( 0 ) | |
| 1562 { | |
| 1563 move( other ); | |
| 1564 } | |
| 1565 | |
| 1566 CompositeGenerator& setFileInfo( const char* fileInfo ) { | |
| 1567 m_fileInfo = fileInfo; | |
| 1568 return *this; | |
| 1569 } | |
| 1570 | |
| 1571 ~CompositeGenerator() { | |
| 1572 deleteAll( m_composed ); | |
| 1573 } | |
| 1574 | |
| 1575 operator T () const { | |
| 1576 size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); | |
| 1577 | |
| 1578 typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); | |
| 1579 typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); | |
| 1580 for( size_t index = 0; it != itEnd; ++it ) | |
| 1581 { | |
| 1582 const IGenerator<T>* generator = *it; | |
| 1583 if( overallIndex >= index && overallIndex < index + generator->size() ) | |
| 1584 { | |
| 1585 return generator->getValue( overallIndex-index ); | |
| 1586 } | |
| 1587 index += generator->size(); | |
| 1588 } | |
| 1589 CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); | |
| 1590 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 | |
| 1591 } | |
| 1592 | |
| 1593 void add( const IGenerator<T>* generator ) { | |
| 1594 m_totalSize += generator->size(); | |
| 1595 m_composed.push_back( generator ); | |
| 1596 } | |
| 1597 | |
| 1598 CompositeGenerator& then( CompositeGenerator& other ) { | |
| 1599 move( other ); | |
| 1600 return *this; | |
| 1601 } | |
| 1602 | |
| 1603 CompositeGenerator& then( T value ) { | |
| 1604 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); | |
| 1605 valuesGen->add( value ); | |
| 1606 add( valuesGen ); | |
| 1607 return *this; | |
| 1608 } | |
| 1609 | |
| 1610 private: | |
| 1611 | |
| 1612 void move( CompositeGenerator& other ) { | |
| 1613 std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); | |
| 1614 m_totalSize += other.m_totalSize; | |
| 1615 other.m_composed.clear(); | |
| 1616 } | |
| 1617 | |
| 1618 std::vector<const IGenerator<T>*> m_composed; | |
| 1619 std::string m_fileInfo; | |
| 1620 size_t m_totalSize; | |
| 1621 }; | |
| 1622 | |
| 1623 namespace Generators | |
| 1624 { | |
| 1625 template<typename T> | |
| 1626 CompositeGenerator<T> between( T from, T to ) { | |
| 1627 CompositeGenerator<T> generators; | |
| 1628 generators.add( new BetweenGenerator<T>( from, to ) ); | |
| 1629 return generators; | |
| 1630 } | |
| 1631 | |
| 1632 template<typename T> | |
| 1633 CompositeGenerator<T> values( T val1, T val2 ) { | |
| 1634 CompositeGenerator<T> generators; | |
| 1635 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); | |
| 1636 valuesGen->add( val1 ); | |
| 1637 valuesGen->add( val2 ); | |
| 1638 generators.add( valuesGen ); | |
| 1639 return generators; | |
| 1640 } | |
| 1641 | |
| 1642 template<typename T> | |
| 1643 CompositeGenerator<T> values( T val1, T val2, T val3 ){ | |
| 1644 CompositeGenerator<T> generators; | |
| 1645 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); | |
| 1646 valuesGen->add( val1 ); | |
| 1647 valuesGen->add( val2 ); | |
| 1648 valuesGen->add( val3 ); | |
| 1649 generators.add( valuesGen ); | |
| 1650 return generators; | |
| 1651 } | |
| 1652 | |
| 1653 template<typename T> | |
| 1654 CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) { | |
| 1655 CompositeGenerator<T> generators; | |
| 1656 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); | |
| 1657 valuesGen->add( val1 ); | |
| 1658 valuesGen->add( val2 ); | |
| 1659 valuesGen->add( val3 ); | |
| 1660 valuesGen->add( val4 ); | |
| 1661 generators.add( valuesGen ); | |
| 1662 return generators; | |
| 1663 } | |
| 1664 | |
| 1665 } // end namespace Generators | |
| 1666 | |
| 1667 using namespace Generators; | |
| 1668 | |
| 1669 } // end namespace Catch | |
| 1670 | |
| 1671 #define INTERNAL_CATCH_LINESTR2( line ) #line | |
| 1672 #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) | |
| 1673 | |
| 1674 #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) | |
| 1675 | |
| 1676 // #included from: internal/catch_interfaces_exception.h | |
| 1677 | |
| 1678 #include <string> | |
| 1679 | |
| 1680 namespace Catch { | |
| 1681 | |
| 1682 typedef std::string(*exceptionTranslateFunction)(); | |
| 1683 | |
| 1684 struct IExceptionTranslator { | |
| 1685 virtual ~IExceptionTranslator(){} | |
| 1686 virtual std::string translate() const = 0; | |
| 1687 }; | |
| 1688 | |
| 1689 struct IExceptionTranslatorRegistry { | |
| 1690 virtual ~IExceptionTranslatorRegistry(){} | |
| 1691 | |
| 1692 virtual void registerTranslator( IExceptionTranslator* translator ) = 0; | |
| 1693 virtual std::string translateActiveException() const = 0; | |
| 1694 }; | |
| 1695 | |
| 1696 class ExceptionTranslatorRegistrar { | |
| 1697 template<typename T> | |
| 1698 class ExceptionTranslator : public IExceptionTranslator { | |
| 1699 public: | |
| 1700 | |
| 1701 ExceptionTranslator( std::string(*translateFunction)( T& ) ) | |
| 1702 : m_translateFunction( translateFunction ) | |
| 1703 {} | |
| 1704 | |
| 1705 virtual std::string translate() const { | |
| 1706 try { | |
| 1707 throw; | |
| 1708 } | |
| 1709 catch( T& ex ) { | |
| 1710 return m_translateFunction( ex ); | |
| 1711 } | |
| 1712 } | |
| 1713 | |
| 1714 protected: | |
| 1715 std::string(*m_translateFunction)( T& ); | |
| 1716 }; | |
| 1717 | |
| 1718 public: | |
| 1719 template<typename T> | |
| 1720 ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { | |
| 1721 getCurrentContext().getExceptionTranslatorRegistry().registerTranslator | |
| 1722 ( new ExceptionTranslator<T>( translateFunction ) ); | |
| 1723 } | |
| 1724 }; | |
| 1725 } | |
| 1726 | |
| 1727 /////////////////////////////////////////////////////////////////////////////// | |
| 1728 #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ | |
| 1729 static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ | |
| 1730 namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ | |
| 1731 static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) | |
| 1732 | |
| 1733 // #included from: internal/catch_approx.hpp | |
| 1734 | |
| 1735 #include <cmath> | |
| 1736 #include <limits> | |
| 1737 | |
| 1738 namespace Catch { | |
| 1739 namespace Detail { | |
| 1740 | |
| 1741 class Approx { | |
| 1742 public: | |
| 1743 explicit Approx ( double value ) | |
| 1744 : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), | |
| 1745 m_scale( 1.0 ), | |
| 1746 m_value( value ) | |
| 1747 {} | |
| 1748 | |
| 1749 Approx( const Approx& other ) | |
| 1750 : m_epsilon( other.m_epsilon ), | |
| 1751 m_scale( other.m_scale ), | |
| 1752 m_value( other.m_value ) | |
| 1753 {} | |
| 1754 | |
| 1755 static Approx custom() { | |
| 1756 return Approx( 0 ); | |
| 1757 } | |
| 1758 | |
| 1759 Approx operator()( double value ) { | |
| 1760 Approx approx( value ); | |
| 1761 approx.epsilon( m_epsilon ); | |
| 1762 approx.scale( m_scale ); | |
| 1763 return approx; | |
| 1764 } | |
| 1765 | |
| 1766 friend bool operator == ( double lhs, const Approx& rhs ) { | |
| 1767 // Thanks to Richard Harris for his help refining this formula | |
| 1768 return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); | |
| 1769 } | |
| 1770 | |
| 1771 friend bool operator == ( const Approx& lhs, double rhs ) { | |
| 1772 return operator==( rhs, lhs ); | |
| 1773 } | |
| 1774 | |
| 1775 friend bool operator != ( double lhs, const Approx& rhs ) { | |
| 1776 return !operator==( lhs, rhs ); | |
| 1777 } | |
| 1778 | |
| 1779 friend bool operator != ( const Approx& lhs, double rhs ) { | |
| 1780 return !operator==( rhs, lhs ); | |
| 1781 } | |
| 1782 | |
| 1783 Approx& epsilon( double newEpsilon ) { | |
| 1784 m_epsilon = newEpsilon; | |
| 1785 return *this; | |
| 1786 } | |
| 1787 | |
| 1788 Approx& scale( double newScale ) { | |
| 1789 m_scale = newScale; | |
| 1790 return *this; | |
| 1791 } | |
| 1792 | |
| 1793 std::string toString() const { | |
| 1794 std::ostringstream oss; | |
| 1795 oss << "Approx( " << m_value << ")"; | |
| 1796 return oss.str(); | |
| 1797 } | |
| 1798 | |
| 1799 private: | |
| 1800 double m_epsilon; | |
| 1801 double m_scale; | |
| 1802 double m_value; | |
| 1803 }; | |
| 1804 } | |
| 1805 | |
| 1806 template<> | |
| 1807 inline std::string toString<Detail::Approx>( const Detail::Approx& value ) { | |
| 1808 return value.toString(); | |
| 1809 } | |
| 1810 | |
| 1811 } // end namespace Catch | |
| 1812 | |
| 1813 // #included from: internal/catch_matchers.hpp | |
| 1814 | |
| 1815 namespace Catch { | |
| 1816 namespace Matchers { | |
| 1817 namespace Impl { | |
| 1818 namespace StdString { | |
| 1819 | |
| 1820 struct Equals { | |
| 1821 Equals( const std::string& str ) : m_str( str ){} | |
| 1822 | |
| 1823 bool operator()( const std::string& str ) const | |
| 1824 { | |
| 1825 return str == m_str; | |
| 1826 } | |
| 1827 | |
| 1828 friend std::ostream& operator<<( std::ostream& os, const Equals& matcher ) | |
| 1829 { | |
| 1830 os << "equals: \"" << matcher.m_str << "\""; | |
| 1831 return os; | |
| 1832 } | |
| 1833 std::string m_str; | |
| 1834 }; | |
| 1835 | |
| 1836 struct Contains { | |
| 1837 Contains( const std::string& substr ) : m_substr( substr ){} | |
| 1838 | |
| 1839 bool operator()( const std::string& str ) const | |
| 1840 { | |
| 1841 return str.find( m_substr ) != std::string::npos; | |
| 1842 } | |
| 1843 | |
| 1844 friend std::ostream& operator<<( std::ostream& os, const Contains& matcher ) | |
| 1845 { | |
| 1846 os << "contains: \"" << matcher.m_substr << "\""; | |
| 1847 return os; | |
| 1848 } | |
| 1849 std::string m_substr; | |
| 1850 }; | |
| 1851 | |
| 1852 struct StartsWith { | |
| 1853 StartsWith( const std::string& substr ) : m_substr( substr ){} | |
| 1854 | |
| 1855 bool operator()( const std::string& str ) const | |
| 1856 { | |
| 1857 return str.find( m_substr ) == 0; | |
| 1858 } | |
| 1859 | |
| 1860 friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher ) | |
| 1861 { | |
| 1862 os << "starts with: \"" << matcher.m_substr << "\""; | |
| 1863 return os; | |
| 1864 } | |
| 1865 std::string m_substr; | |
| 1866 }; | |
| 1867 | |
| 1868 struct EndsWith { | |
| 1869 EndsWith( const std::string& substr ) : m_substr( substr ){} | |
| 1870 | |
| 1871 bool operator()( const std::string& str ) const | |
| 1872 { | |
| 1873 return str.find( m_substr ) == str.size() - m_substr.size(); | |
| 1874 } | |
| 1875 | |
| 1876 friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher ) | |
| 1877 { | |
| 1878 os << "ends with: \"" << matcher.m_substr << "\""; | |
| 1879 return os; | |
| 1880 } | |
| 1881 std::string m_substr; | |
| 1882 }; | |
| 1883 } // namespace StdString | |
| 1884 } // namespace Impl | |
| 1885 | |
| 1886 inline Impl::StdString::Equals Equals( const std::string& str ){ return Impl::StdString::Equals( str ); } | |
| 1887 inline Impl::StdString::Contains Contains( const std::string& substr ){ return Impl::StdString::Contains( substr ); } | |
| 1888 inline Impl::StdString::StartsWith StartsWith( const std::string& substr ){ return Impl::StdString::StartsWith( substr ); } | |
| 1889 inline Impl::StdString::EndsWith EndsWith( const std::string& substr ){ return Impl::StdString::EndsWith( substr ); } | |
| 1890 | |
| 1891 } // namespace Matchers | |
| 1892 | |
| 1893 using namespace Matchers; | |
| 1894 | |
| 1895 } // namespace Catch | |
| 1896 | |
| 1897 // These files are included here so the single_include script doesn't put them | |
| 1898 // in the conditionally compiled sections | |
| 1899 // #included from: internal/catch_test_case_info.hpp | |
| 1900 | |
| 1901 #include <map> | |
| 1902 #include <string> | |
| 1903 | |
| 1904 namespace Catch { | |
| 1905 | |
| 1906 class TestCaseInfo { | |
| 1907 public: | |
| 1908 TestCaseInfo( ITestCase* testCase, | |
| 1909 const char* name, | |
| 1910 const char* description, | |
| 1911 const SourceLineInfo& lineInfo ) | |
| 1912 : m_test( testCase ), | |
| 1913 m_name( name ), | |
| 1914 m_description( description ), | |
| 1915 m_lineInfo( lineInfo ) | |
| 1916 {} | |
| 1917 | |
| 1918 TestCaseInfo() | |
| 1919 : m_test( NULL ), | |
| 1920 m_name(), | |
| 1921 m_description() | |
| 1922 {} | |
| 1923 | |
| 1924 TestCaseInfo( const TestCaseInfo& other ) | |
| 1925 : m_test( other.m_test->clone() ), | |
| 1926 m_name( other.m_name ), | |
| 1927 m_description( other.m_description ), | |
| 1928 m_lineInfo( other.m_lineInfo ) | |
| 1929 {} | |
| 1930 | |
| 1931 TestCaseInfo( const TestCaseInfo& other, const std::string& name ) | |
| 1932 : m_test( other.m_test->clone() ), | |
| 1933 m_name( name ), | |
| 1934 m_description( other.m_description ), | |
| 1935 m_lineInfo( other.m_lineInfo ) | |
| 1936 {} | |
| 1937 | |
| 1938 TestCaseInfo& operator = ( const TestCaseInfo& other ) { | |
| 1939 TestCaseInfo temp( other ); | |
| 1940 swap( temp ); | |
| 1941 return *this; | |
| 1942 } | |
| 1943 | |
| 1944 ~TestCaseInfo() { | |
| 1945 delete m_test; | |
| 1946 } | |
| 1947 | |
| 1948 void invoke() const { | |
| 1949 m_test->invoke(); | |
| 1950 } | |
| 1951 | |
| 1952 const std::string& getName() const { | |
| 1953 return m_name; | |
| 1954 } | |
| 1955 | |
| 1956 const std::string& getDescription() const { | |
| 1957 return m_description; | |
| 1958 } | |
| 1959 | |
| 1960 const SourceLineInfo& getLineInfo() const { | |
| 1961 return m_lineInfo; | |
| 1962 } | |
| 1963 | |
| 1964 bool isHidden() const { | |
| 1965 return m_name.size() >= 2 && m_name[0] == '.' && m_name[1] == '/'; | |
| 1966 } | |
| 1967 | |
| 1968 void swap( TestCaseInfo& other ) { | |
| 1969 std::swap( m_test, other.m_test ); | |
| 1970 m_name.swap( other.m_name ); | |
| 1971 m_description.swap( other.m_description ); | |
| 1972 m_lineInfo.swap( other.m_lineInfo ); | |
| 1973 } | |
| 1974 | |
| 1975 bool operator == ( const TestCaseInfo& other ) const { | |
| 1976 return *m_test == *other.m_test && m_name == other.m_name; | |
| 1977 } | |
| 1978 | |
| 1979 bool operator < ( const TestCaseInfo& other ) const { | |
| 1980 return m_name < other.m_name; | |
| 1981 } | |
| 1982 | |
| 1983 private: | |
| 1984 ITestCase* m_test; | |
| 1985 std::string m_name; | |
| 1986 std::string m_description; | |
| 1987 SourceLineInfo m_lineInfo; | |
| 1988 }; | |
| 1989 | |
| 1990 /////////////////////////////////////////////////////////////////////////// | |
| 1991 | |
| 1992 class TestSpec { | |
| 1993 public: | |
| 1994 TestSpec( const std::string& rawSpec ) | |
| 1995 : m_rawSpec( rawSpec ), | |
| 1996 m_isWildcarded( false ) { | |
| 1997 | |
| 1998 if( m_rawSpec[m_rawSpec.size()-1] == '*' ) { | |
| 1999 m_rawSpec = m_rawSpec.substr( 0, m_rawSpec.size()-1 ); | |
| 2000 m_isWildcarded = true; | |
| 2001 } | |
| 2002 } | |
| 2003 | |
| 2004 bool matches ( const std::string& testName ) const { | |
| 2005 if( !m_isWildcarded ) | |
| 2006 return m_rawSpec == testName; | |
| 2007 else | |
| 2008 return testName.size() >= m_rawSpec.size() && testName.substr( 0, m_rawSpec.size() ) == m_rawSpec; | |
| 2009 } | |
| 2010 | |
| 2011 private: | |
| 2012 std::string m_rawSpec; | |
| 2013 bool m_isWildcarded; | |
| 2014 }; | |
| 2015 } | |
| 2016 | |
| 2017 // #included from: internal/catch_interfaces_runner.h | |
| 2018 | |
| 2019 #include <string> | |
| 2020 | |
| 2021 namespace Catch { | |
| 2022 class TestCaseInfo; | |
| 2023 | |
| 2024 struct IRunner { | |
| 2025 virtual ~IRunner() {} | |
| 2026 virtual void runAll( bool runHiddenTests = false ) = 0; | |
| 2027 virtual std::size_t runMatching( const std::string& rawTestSpec ) = 0; | |
| 2028 virtual Totals getTotals() const = 0; | |
| 2029 }; | |
| 2030 } | |
| 2031 | |
| 2032 | |
| 2033 #ifdef __OBJC__ | |
| 2034 // #included from: internal/catch_objc.hpp | |
| 2035 | |
| 2036 #import <Foundation/Foundation.h> | |
| 2037 #import <objc/runtime.h> | |
| 2038 | |
| 2039 #include <string> | |
| 2040 | |
| 2041 // NB. Any general catch headers included here must be included | |
| 2042 // in catch.hpp first to make sure they are included by the single | |
| 2043 // header for non obj-usage | |
| 2044 | |
| 2045 #ifdef __has_feature | |
| 2046 #define CATCH_ARC_ENABLED __has_feature(objc_arc) | |
| 2047 #else | |
| 2048 #define CATCH_ARC_ENABLED 0 | |
| 2049 #endif | |
| 2050 | |
| 2051 void arcSafeRelease( NSObject* obj ); | |
| 2052 id performOptionalSelector( id obj, SEL sel ); | |
| 2053 | |
| 2054 #if !CATCH_ARC_ENABLED | |
| 2055 inline void arcSafeRelease( NSObject* obj ) { | |
| 2056 [obj release]; | |
| 2057 } | |
| 2058 inline id performOptionalSelector( id obj, SEL sel ) { | |
| 2059 if( [obj respondsToSelector: sel] ) | |
| 2060 return [obj performSelector: sel]; | |
| 2061 return nil; | |
| 2062 } | |
| 2063 #define CATCH_UNSAFE_UNRETAINED | |
| 2064 #else | |
| 2065 inline void arcSafeRelease( NSObject* ){} | |
| 2066 inline id performOptionalSelector( id obj, SEL sel ) { | |
| 2067 #pragma clang diagnostic push | |
| 2068 #pragma clang diagnostic ignored "-Warc-performSelector-leaks" | |
| 2069 if( [obj respondsToSelector: sel] ) | |
| 2070 return [obj performSelector: sel]; | |
| 2071 #pragma clang diagnostic pop | |
| 2072 return nil; | |
| 2073 } | |
| 2074 #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained | |
| 2075 #endif | |
| 2076 | |
| 2077 /////////////////////////////////////////////////////////////////////////////// | |
| 2078 // This protocol is really only here for (self) documenting purposes, since | |
| 2079 // all its methods are optional. | |
| 2080 @protocol OcFixture | |
| 2081 | |
| 2082 @optional | |
| 2083 | |
| 2084 -(void) setUp; | |
| 2085 -(void) tearDown; | |
| 2086 | |
| 2087 @end | |
| 2088 | |
| 2089 namespace Catch { | |
| 2090 | |
| 2091 class OcMethod : public ITestCase { | |
| 2092 | |
| 2093 public: | |
| 2094 OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} | |
| 2095 | |
| 2096 virtual void invoke() const { | |
| 2097 id obj = [[m_cls alloc] init]; | |
| 2098 | |
| 2099 performOptionalSelector( obj, @selector(setUp) ); | |
| 2100 performOptionalSelector( obj, m_sel ); | |
| 2101 performOptionalSelector( obj, @selector(tearDown) ); | |
| 2102 | |
| 2103 arcSafeRelease( obj ); | |
| 2104 } | |
| 2105 | |
| 2106 virtual ITestCase* clone() const { | |
| 2107 return new OcMethod( m_cls, m_sel ); | |
| 2108 } | |
| 2109 | |
| 2110 virtual bool operator == ( const ITestCase& other ) const { | |
| 2111 const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other ); | |
| 2112 return ocmOther && ocmOther->m_sel == m_sel; | |
| 2113 } | |
| 2114 | |
| 2115 virtual bool operator < ( const ITestCase& other ) const { | |
| 2116 const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other ); | |
| 2117 return ocmOther && ocmOther->m_sel < m_sel; | |
| 2118 } | |
| 2119 | |
| 2120 private: | |
| 2121 Class m_cls; | |
| 2122 SEL m_sel; | |
| 2123 }; | |
| 2124 | |
| 2125 namespace Detail{ | |
| 2126 | |
| 2127 inline bool startsWith( const std::string& str, const std::string& sub ) { | |
| 2128 return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub; | |
| 2129 } | |
| 2130 | |
| 2131 inline std::string getAnnotation( Class cls, | |
| 2132 const std::string& annotationName, | |
| 2133 const std::string& testCaseName ) { | |
| 2134 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; | |
| 2135 SEL sel = NSSelectorFromString( selStr ); | |
| 2136 arcSafeRelease( selStr ); | |
| 2137 id value = performOptionalSelector( cls, sel ); | |
| 2138 if( value ) | |
| 2139 return [(NSString*)value UTF8String]; | |
| 2140 return ""; | |
| 2141 } | |
| 2142 } | |
| 2143 | |
| 2144 inline size_t registerTestMethods() { | |
| 2145 size_t noTestMethods = 0; | |
| 2146 int noClasses = objc_getClassList( NULL, 0 ); | |
| 2147 | |
| 2148 Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); | |
| 2149 objc_getClassList( classes, noClasses ); | |
| 2150 | |
| 2151 for( int c = 0; c < noClasses; c++ ) { | |
| 2152 Class cls = classes[c]; | |
| 2153 { | |
| 2154 u_int count; | |
| 2155 Method* methods = class_copyMethodList( cls, &count ); | |
| 2156 for( u_int m = 0; m < count ; m++ ) { | |
| 2157 SEL selector = method_getName(methods[m]); | |
| 2158 std::string methodName = sel_getName(selector); | |
| 2159 if( Detail::startsWith( methodName, "Catch_TestCase_" ) ) { | |
| 2160 std::string testCaseName = methodName.substr( 15 ); | |
| 2161 std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); | |
| 2162 std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); | |
| 2163 | |
| 2164 getCurrentContext().getTestCaseRegistry().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) ); | |
| 2165 noTestMethods++; | |
| 2166 } | |
| 2167 } | |
| 2168 free(methods); | |
| 2169 } | |
| 2170 } | |
| 2171 return noTestMethods; | |
| 2172 } | |
| 2173 | |
| 2174 inline std::string toString( NSString* const& nsstring ) { | |
| 2175 return std::string( "@\"" ) + [nsstring UTF8String] + "\""; | |
| 2176 } | |
| 2177 | |
| 2178 namespace Matchers { | |
| 2179 namespace Impl { | |
| 2180 namespace NSStringMatchers { | |
| 2181 | |
| 2182 struct StringHolder { | |
| 2183 StringHolder( NSString* substr ) : m_substr( [substr copy] ){} | |
| 2184 StringHolder() { | |
| 2185 arcSafeRelease( m_substr ); | |
| 2186 } | |
| 2187 | |
| 2188 NSString* m_substr; | |
| 2189 }; | |
| 2190 | |
| 2191 struct Equals : StringHolder { | |
| 2192 Equals( NSString* substr ) : StringHolder( substr ){} | |
| 2193 | |
| 2194 bool operator()( NSString* str ) const { | |
| 2195 return [str isEqualToString:m_substr]; | |
| 2196 } | |
| 2197 | |
| 2198 friend std::ostream& operator<<( std::ostream& os, const Equals& matcher ) { | |
| 2199 os << "equals string: " << Catch::toString( matcher.m_substr ); | |
| 2200 return os; | |
| 2201 } | |
| 2202 }; | |
| 2203 | |
| 2204 struct Contains : StringHolder { | |
| 2205 Contains( NSString* substr ) : StringHolder( substr ){} | |
| 2206 | |
| 2207 bool operator()( NSString* str ) const { | |
| 2208 return [str rangeOfString:m_substr].location != NSNotFound; | |
| 2209 } | |
| 2210 | |
| 2211 friend std::ostream& operator<<( std::ostream& os, const Contains& matcher ) { | |
| 2212 os << "contains: " << Catch::toString( matcher.m_substr ); | |
| 2213 return os; | |
| 2214 } | |
| 2215 }; | |
| 2216 | |
| 2217 struct StartsWith : StringHolder { | |
| 2218 StartsWith( NSString* substr ) : StringHolder( substr ){} | |
| 2219 | |
| 2220 bool operator()( NSString* str ) const { | |
| 2221 return [str rangeOfString:m_substr].location == 0; | |
| 2222 } | |
| 2223 | |
| 2224 friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher ) { | |
| 2225 os << "starts with: " << Catch::toString( matcher.m_substr ); | |
| 2226 return os; | |
| 2227 } | |
| 2228 }; | |
| 2229 struct EndsWith : StringHolder { | |
| 2230 EndsWith( NSString* substr ) : StringHolder( substr ){} | |
| 2231 | |
| 2232 bool operator()( NSString* str ) const { | |
| 2233 return [str rangeOfString:m_substr].location == [str length] - [m_substr length]; | |
| 2234 } | |
| 2235 | |
| 2236 friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher ) { | |
| 2237 os << "ends with: " << Catch::toString( matcher.m_substr ); | |
| 2238 return os; | |
| 2239 } | |
| 2240 }; | |
| 2241 | |
| 2242 } // namespace NSStringMatchers | |
| 2243 } // namespace Impl | |
| 2244 | |
| 2245 inline Impl::NSStringMatchers::Equals | |
| 2246 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } | |
| 2247 | |
| 2248 inline Impl::NSStringMatchers::Contains | |
| 2249 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } | |
| 2250 | |
| 2251 inline Impl::NSStringMatchers::StartsWith | |
| 2252 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } | |
| 2253 | |
| 2254 inline Impl::NSStringMatchers::EndsWith | |
| 2255 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } | |
| 2256 | |
| 2257 } // namespace Matchers | |
| 2258 | |
| 2259 using namespace Matchers; | |
| 2260 | |
| 2261 } // namespace Catch | |
| 2262 | |
| 2263 /////////////////////////////////////////////////////////////////////////////// | |
| 2264 #define OC_TEST_CASE( name, desc )\ | |
| 2265 +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ | |
| 2266 {\ | |
| 2267 return @ name; \ | |
| 2268 }\ | |
| 2269 +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ | |
| 2270 { \ | |
| 2271 return @ desc; \ | |
| 2272 } \ | |
| 2273 -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) | |
| 2274 | |
| 2275 #endif | |
| 2276 | |
| 2277 #if defined( CATCH_CONFIG_MAIN ) || defined( CATCH_CONFIG_RUNNER ) | |
| 2278 // #included from: catch_runner.hpp | |
| 2279 | |
| 2280 // #included from: internal/catch_context_impl.hpp | |
| 2281 // #included from: catch_test_case_registry_impl.hpp | |
| 2282 | |
| 2283 #include <vector> | |
| 2284 #include <set> | |
| 2285 #include <sstream> | |
| 2286 #include <iostream> | |
| 2287 | |
| 2288 namespace Catch { | |
| 2289 | |
| 2290 class TestRegistry : public ITestCaseRegistry { | |
| 2291 public: | |
| 2292 TestRegistry() : m_unnamedCount( 0 ) {} | |
| 2293 | |
| 2294 virtual void registerTest( const TestCaseInfo& testInfo ) { | |
| 2295 if( testInfo.getName() == "" ) { | |
| 2296 std::ostringstream oss; | |
| 2297 oss << testInfo.getName() << "unnamed/" << ++m_unnamedCount; | |
| 2298 return registerTest( TestCaseInfo( testInfo, oss.str() ) ); | |
| 2299 } | |
| 2300 | |
| 2301 if( m_functions.find( testInfo ) == m_functions.end() ) { | |
| 2302 m_functions.insert( testInfo ); | |
| 2303 m_functionsInOrder.push_back( testInfo ); | |
| 2304 } | |
| 2305 else { | |
| 2306 const TestCaseInfo& prev = *m_functions.find( testInfo ); | |
| 2307 std::cerr << "error: TEST_CASE( \"" << testInfo.getName() << "\" ) already defined.\n" | |
| 2308 << "\tFirst seen at " << SourceLineInfo( prev.getLineInfo() ) << "\n" | |
| 2309 << "\tRedefined at " << SourceLineInfo( testInfo.getLineInfo() ) << std::endl; | |
| 2310 exit(1); | |
| 2311 } | |
| 2312 } | |
| 2313 | |
| 2314 virtual const std::vector<TestCaseInfo>& getAllTests() const { | |
| 2315 return m_functionsInOrder; | |
| 2316 } | |
| 2317 | |
| 2318 virtual std::vector<TestCaseInfo> getMatchingTestCases( const std::string& rawTestSpec ) { | |
| 2319 TestSpec testSpec( rawTestSpec ); | |
| 2320 | |
| 2321 std::vector<TestCaseInfo> testList; | |
| 2322 std::vector<TestCaseInfo>::const_iterator it = m_functionsInOrder.begin(); | |
| 2323 std::vector<TestCaseInfo>::const_iterator itEnd = m_functionsInOrder.end(); | |
| 2324 for(; it != itEnd; ++it ) { | |
| 2325 if( testSpec.matches( it->getName() ) ) { | |
| 2326 testList.push_back( *it ); | |
| 2327 } | |
| 2328 } | |
| 2329 return testList; | |
| 2330 } | |
| 2331 | |
| 2332 private: | |
| 2333 | |
| 2334 std::set<TestCaseInfo> m_functions; | |
| 2335 std::vector<TestCaseInfo> m_functionsInOrder; | |
| 2336 size_t m_unnamedCount; | |
| 2337 }; | |
| 2338 | |
| 2339 /////////////////////////////////////////////////////////////////////////// | |
| 2340 | |
| 2341 class FreeFunctionTestCase : public ITestCase { | |
| 2342 public: | |
| 2343 | |
| 2344 FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} | |
| 2345 | |
| 2346 virtual void invoke() const { | |
| 2347 m_fun(); | |
| 2348 } | |
| 2349 | |
| 2350 virtual ITestCase* clone() const { | |
| 2351 return new FreeFunctionTestCase( m_fun ); | |
| 2352 } | |
| 2353 | |
| 2354 virtual bool operator == ( const ITestCase& other ) const { | |
| 2355 const FreeFunctionTestCase* ffOther = dynamic_cast<const FreeFunctionTestCase*> ( &other ); | |
| 2356 return ffOther && m_fun == ffOther->m_fun; | |
| 2357 } | |
| 2358 | |
| 2359 virtual bool operator < ( const ITestCase& other ) const { | |
| 2360 const FreeFunctionTestCase* ffOther = dynamic_cast<const FreeFunctionTestCase*> ( &other ); | |
| 2361 return ffOther && m_fun < ffOther->m_fun; | |
| 2362 } | |
| 2363 | |
| 2364 private: | |
| 2365 TestFunction m_fun; | |
| 2366 }; | |
| 2367 | |
| 2368 /////////////////////////////////////////////////////////////////////////// | |
| 2369 | |
| 2370 AutoReg::AutoReg( TestFunction function, | |
| 2371 const char* name, | |
| 2372 const char* description, | |
| 2373 const SourceLineInfo& lineInfo ) { | |
| 2374 registerTestCase( new FreeFunctionTestCase( function ), name, description, lineInfo ); | |
| 2375 } | |
| 2376 | |
| 2377 AutoReg::~AutoReg() {} | |
| 2378 | |
| 2379 void AutoReg::registerTestCase( ITestCase* testCase, | |
| 2380 const char* name, | |
| 2381 const char* description, | |
| 2382 const SourceLineInfo& lineInfo ) { | |
| 2383 getCurrentContext().getTestCaseRegistry().registerTest( TestCaseInfo( testCase, name, description, lineInfo ) ); | |
| 2384 } | |
| 2385 | |
| 2386 } // end namespace Catch | |
| 2387 | |
| 2388 // #included from: catch_runner_impl.hpp | |
| 2389 | |
| 2390 // #included from: catch_config.hpp | |
| 2391 | |
| 2392 #include <memory> | |
| 2393 #include <vector> | |
| 2394 #include <string> | |
| 2395 #include <iostream> | |
| 2396 | |
| 2397 namespace Catch { | |
| 2398 | |
| 2399 struct Include { enum WhichResults { | |
| 2400 FailedOnly, | |
| 2401 SuccessfulResults | |
| 2402 }; }; | |
| 2403 | |
| 2404 struct List{ enum What { | |
| 2405 None = 0, | |
| 2406 | |
| 2407 Reports = 1, | |
| 2408 Tests = 2, | |
| 2409 All = 3, | |
| 2410 | |
| 2411 WhatMask = 0xf, | |
| 2412 | |
| 2413 AsText = 0x10, | |
| 2414 AsXml = 0x11, | |
| 2415 | |
| 2416 AsMask = 0xf0 | |
| 2417 }; }; | |
| 2418 | |
| 2419 class Config : public IReporterConfig, public IConfig { | |
| 2420 private: | |
| 2421 Config( const Config& other ); | |
| 2422 Config& operator = ( const Config& other ); | |
| 2423 public: | |
| 2424 | |
| 2425 Config() | |
| 2426 : m_listSpec( List::None ), | |
| 2427 m_shouldDebugBreak( false ), | |
| 2428 m_showHelp( false ), | |
| 2429 m_streambuf( NULL ), | |
| 2430 m_os( std::cout.rdbuf() ), | |
| 2431 m_includeWhichResults( Include::FailedOnly ), | |
| 2432 m_cutoff( -1 ), | |
| 2433 m_allowThrows( true ) | |
| 2434 {} | |
| 2435 | |
| 2436 ~Config() { | |
| 2437 m_os.rdbuf( std::cout.rdbuf() ); | |
| 2438 delete m_streambuf; | |
| 2439 } | |
| 2440 | |
| 2441 void setReporter( const std::string& reporterName ) { | |
| 2442 if( m_reporter.get() ) | |
| 2443 return setError( "Only one reporter may be specified" ); | |
| 2444 setReporter( getCurrentContext().getReporterRegistry().create( reporterName, *this ) ); | |
| 2445 } | |
| 2446 | |
| 2447 void addTestSpec( const std::string& testSpec ) { | |
| 2448 m_testSpecs.push_back( testSpec ); | |
| 2449 } | |
| 2450 | |
| 2451 bool testsSpecified() const { | |
| 2452 return !m_testSpecs.empty(); | |
| 2453 } | |
| 2454 | |
| 2455 const std::vector<std::string>& getTestSpecs() const { | |
| 2456 return m_testSpecs; | |
| 2457 } | |
| 2458 | |
| 2459 List::What getListSpec( void ) const { | |
| 2460 return m_listSpec; | |
| 2461 } | |
| 2462 | |
| 2463 void setListSpec( List::What listSpec ) { | |
| 2464 m_listSpec = listSpec; | |
| 2465 } | |
| 2466 | |
| 2467 void setFilename( const std::string& filename ) { | |
| 2468 m_filename = filename; | |
| 2469 } | |
| 2470 | |
| 2471 const std::string& getFilename() const { | |
| 2472 return m_filename; | |
| 2473 } | |
| 2474 | |
| 2475 const std::string& getMessage() const { | |
| 2476 return m_message; | |
| 2477 } | |
| 2478 | |
| 2479 void setError( const std::string& errorMessage ) { | |
| 2480 m_message = errorMessage; | |
| 2481 } | |
| 2482 | |
| 2483 void setReporter( IReporter* reporter ) { | |
| 2484 m_reporter = reporter; | |
| 2485 } | |
| 2486 | |
| 2487 Ptr<IReporter> getReporter() { | |
| 2488 if( !m_reporter.get() ) | |
| 2489 const_cast<Config*>( this )->setReporter( getCurrentContext().getReporterRegistry().create( "basic", *this ) ); | |
| 2490 return m_reporter; | |
| 2491 } | |
| 2492 | |
| 2493 List::What listWhat() const { | |
| 2494 return static_cast<List::What>( m_listSpec & List::WhatMask ); | |
| 2495 } | |
| 2496 | |
| 2497 List::What listAs() const { | |
| 2498 return static_cast<List::What>( m_listSpec & List::AsMask ); | |
| 2499 } | |
| 2500 | |
| 2501 void setIncludeWhichResults( Include::WhichResults includeWhichResults ) { | |
| 2502 m_includeWhichResults = includeWhichResults; | |
| 2503 } | |
| 2504 | |
| 2505 void setShouldDebugBreak( bool shouldDebugBreakFlag ) { | |
| 2506 m_shouldDebugBreak = shouldDebugBreakFlag; | |
| 2507 } | |
| 2508 | |
| 2509 void setName( const std::string& name ) { | |
| 2510 m_name = name; | |
| 2511 } | |
| 2512 | |
| 2513 std::string getName() const { | |
| 2514 return m_name; | |
| 2515 } | |
| 2516 | |
| 2517 bool shouldDebugBreak() const { | |
| 2518 return m_shouldDebugBreak; | |
| 2519 } | |
| 2520 | |
| 2521 void setShowHelp( bool showHelpFlag ) { | |
| 2522 m_showHelp = showHelpFlag; | |
| 2523 } | |
| 2524 | |
| 2525 bool showHelp() const { | |
| 2526 return m_showHelp; | |
| 2527 } | |
| 2528 | |
| 2529 virtual std::ostream& stream() const { | |
| 2530 return m_os; | |
| 2531 } | |
| 2532 | |
| 2533 void setStreamBuf( std::streambuf* buf ) { | |
| 2534 m_os.rdbuf( buf ? buf : std::cout.rdbuf() ); | |
| 2535 } | |
| 2536 | |
| 2537 void useStream( const std::string& streamName ) { | |
| 2538 std::streambuf* newBuf = Context::createStreamBuf( streamName ); | |
| 2539 setStreamBuf( newBuf ); | |
| 2540 delete m_streambuf; | |
| 2541 m_streambuf = newBuf; | |
| 2542 } | |
| 2543 | |
| 2544 virtual bool includeSuccessfulResults() const { | |
| 2545 return m_includeWhichResults == Include::SuccessfulResults; | |
| 2546 } | |
| 2547 | |
| 2548 int getCutoff() const { | |
| 2549 return m_cutoff; | |
| 2550 } | |
| 2551 | |
| 2552 void setCutoff( int cutoff ) { | |
| 2553 m_cutoff = cutoff; | |
| 2554 } | |
| 2555 | |
| 2556 void setAllowThrows( bool allowThrows ) { | |
| 2557 m_allowThrows = allowThrows; | |
| 2558 } | |
| 2559 | |
| 2560 virtual bool allowThrows() const { | |
| 2561 return m_allowThrows; | |
| 2562 } | |
| 2563 | |
| 2564 private: | |
| 2565 Ptr<IReporter> m_reporter; | |
| 2566 std::string m_filename; | |
| 2567 std::string m_message; | |
| 2568 List::What m_listSpec; | |
| 2569 std::vector<std::string> m_testSpecs; | |
| 2570 bool m_shouldDebugBreak; | |
| 2571 bool m_showHelp; | |
| 2572 std::streambuf* m_streambuf; | |
| 2573 mutable std::ostream m_os; | |
| 2574 Include::WhichResults m_includeWhichResults; | |
| 2575 std::string m_name; | |
| 2576 int m_cutoff; | |
| 2577 bool m_allowThrows; | |
| 2578 }; | |
| 2579 | |
| 2580 struct NewConfig { | |
| 2581 std::string reporter; | |
| 2582 std::string outputFilename; | |
| 2583 List::What listSpec; | |
| 2584 std::vector<std::string> testSpecs; | |
| 2585 bool shouldDebugBreak; | |
| 2586 bool showHelp; | |
| 2587 Include::WhichResults includeWhichResults; | |
| 2588 std::string name; | |
| 2589 }; | |
| 2590 | |
| 2591 } // end namespace Catch | |
| 2592 | |
| 2593 // #included from: catch_running_test.hpp | |
| 2594 | |
| 2595 // #included from: catch_section_info.hpp | |
| 2596 | |
| 2597 #include <map> | |
| 2598 #include <string> | |
| 2599 | |
| 2600 namespace Catch { | |
| 2601 | |
| 2602 class SectionInfo { | |
| 2603 public: | |
| 2604 | |
| 2605 enum Status { | |
| 2606 Root, | |
| 2607 Unknown, | |
| 2608 Branch, | |
| 2609 TestedBranch, | |
| 2610 TestedLeaf | |
| 2611 }; | |
| 2612 | |
| 2613 SectionInfo( SectionInfo* parent ) | |
| 2614 : m_status( Unknown ), | |
| 2615 m_parent( parent ) | |
| 2616 {} | |
| 2617 | |
| 2618 SectionInfo() | |
| 2619 : m_status( Root ), | |
| 2620 m_parent( NULL ) | |
| 2621 {} | |
| 2622 | |
| 2623 ~SectionInfo() { | |
| 2624 deleteAllValues( m_subSections ); | |
| 2625 } | |
| 2626 | |
| 2627 bool shouldRun() const { | |
| 2628 return m_status < TestedBranch; | |
| 2629 } | |
| 2630 | |
| 2631 bool ran() { | |
| 2632 if( m_status < Branch ) { | |
| 2633 m_status = TestedLeaf; | |
| 2634 return true; | |
| 2635 } | |
| 2636 return false; | |
| 2637 } | |
| 2638 | |
| 2639 void ranToCompletion() { | |
| 2640 if( m_status == Branch && !hasUntestedSections() ) | |
| 2641 m_status = TestedBranch; | |
| 2642 } | |
| 2643 | |
| 2644 SectionInfo* findSubSection( const std::string& name ) { | |
| 2645 std::map<std::string, SectionInfo*>::const_iterator it = m_subSections.find( name ); | |
| 2646 return it != m_subSections.end() | |
| 2647 ? it->second | |
| 2648 : NULL; | |
| 2649 } | |
| 2650 | |
| 2651 SectionInfo* addSubSection( const std::string& name ) { | |
| 2652 SectionInfo* subSection = new SectionInfo( this ); | |
| 2653 m_subSections.insert( std::make_pair( name, subSection ) ); | |
| 2654 m_status = Branch; | |
| 2655 return subSection; | |
| 2656 } | |
| 2657 | |
| 2658 SectionInfo* getParent() { | |
| 2659 return m_parent; | |
| 2660 } | |
| 2661 | |
| 2662 bool hasUntestedSections() const { | |
| 2663 if( m_status == Unknown ) | |
| 2664 return true; | |
| 2665 | |
| 2666 std::map<std::string, SectionInfo*>::const_iterator it = m_subSections.begin(); | |
| 2667 std::map<std::string, SectionInfo*>::const_iterator itEnd = m_subSections.end(); | |
| 2668 for(; it != itEnd; ++it ) { | |
| 2669 if( it->second->hasUntestedSections() ) | |
| 2670 return true; | |
| 2671 } | |
| 2672 return false; | |
| 2673 } | |
| 2674 | |
| 2675 private: | |
| 2676 Status m_status; | |
| 2677 std::map<std::string, SectionInfo*> m_subSections; | |
| 2678 SectionInfo* m_parent; | |
| 2679 }; | |
| 2680 } | |
| 2681 | |
| 2682 namespace Catch { | |
| 2683 | |
| 2684 class RunningTest { | |
| 2685 | |
| 2686 enum RunStatus { | |
| 2687 NothingRun, | |
| 2688 EncounteredASection, | |
| 2689 RanAtLeastOneSection, | |
| 2690 RanToCompletionWithSections, | |
| 2691 RanToCompletionWithNoSections | |
| 2692 }; | |
| 2693 | |
| 2694 public: | |
| 2695 explicit RunningTest( const TestCaseInfo* info = NULL ) | |
| 2696 : m_info( info ), | |
| 2697 m_runStatus( RanAtLeastOneSection ), | |
| 2698 m_currentSection( &m_rootSection ), | |
| 2699 m_changed( false ) | |
| 2700 {} | |
| 2701 | |
| 2702 bool wasSectionSeen() const { | |
| 2703 return m_runStatus == RanAtLeastOneSection || | |
| 2704 m_runStatus == RanToCompletionWithSections; | |
| 2705 } | |
| 2706 | |
| 2707 void reset() { | |
| 2708 m_runStatus = NothingRun; | |
| 2709 m_changed = false; | |
| 2710 m_lastSectionToRun = NULL; | |
| 2711 } | |
| 2712 | |
| 2713 void ranToCompletion() { | |
| 2714 if( m_runStatus == RanAtLeastOneSection || | |
| 2715 m_runStatus == EncounteredASection ) { | |
| 2716 m_runStatus = RanToCompletionWithSections; | |
| 2717 if( m_lastSectionToRun ) { | |
| 2718 m_lastSectionToRun->ranToCompletion(); | |
| 2719 m_changed = true; | |
| 2720 } | |
| 2721 } | |
| 2722 else { | |
| 2723 m_runStatus = RanToCompletionWithNoSections; | |
| 2724 } | |
| 2725 } | |
| 2726 | |
| 2727 bool addSection( const std::string& name ) { | |
| 2728 if( m_runStatus == NothingRun ) | |
| 2729 m_runStatus = EncounteredASection; | |
| 2730 | |
| 2731 SectionInfo* thisSection = m_currentSection->findSubSection( name ); | |
| 2732 if( !thisSection ) { | |
| 2733 thisSection = m_currentSection->addSubSection( name ); | |
| 2734 m_changed = true; | |
| 2735 } | |
| 2736 | |
| 2737 if( !wasSectionSeen() && thisSection->shouldRun() ) { | |
| 2738 m_currentSection = thisSection; | |
| 2739 m_lastSectionToRun = NULL; | |
| 2740 return true; | |
| 2741 } | |
| 2742 return false; | |
| 2743 } | |
| 2744 | |
| 2745 void endSection( const std::string& ) { | |
| 2746 if( m_currentSection->ran() ) { | |
| 2747 m_runStatus = RanAtLeastOneSection; | |
| 2748 m_changed = true; | |
| 2749 } | |
| 2750 else if( m_runStatus == EncounteredASection ) { | |
| 2751 m_runStatus = RanAtLeastOneSection; | |
| 2752 m_lastSectionToRun = m_currentSection; | |
| 2753 } | |
| 2754 m_currentSection = m_currentSection->getParent(); | |
| 2755 } | |
| 2756 | |
| 2757 const TestCaseInfo& getTestCaseInfo() const { | |
| 2758 return *m_info; | |
| 2759 } | |
| 2760 | |
| 2761 bool hasUntestedSections() const { | |
| 2762 return m_runStatus == RanAtLeastOneSection || | |
| 2763 ( m_rootSection.hasUntestedSections() && m_changed ); | |
| 2764 } | |
| 2765 | |
| 2766 private: | |
| 2767 const TestCaseInfo* m_info; | |
| 2768 RunStatus m_runStatus; | |
| 2769 SectionInfo m_rootSection; | |
| 2770 SectionInfo* m_currentSection; | |
| 2771 SectionInfo* m_lastSectionToRun; | |
| 2772 bool m_changed; | |
| 2773 }; | |
| 2774 } | |
| 2775 | |
| 2776 #include <set> | |
| 2777 #include <string> | |
| 2778 | |
| 2779 namespace Catch { | |
| 2780 | |
| 2781 class StreamRedirect { | |
| 2782 | |
| 2783 public: | |
| 2784 StreamRedirect( std::ostream& stream, std::string& targetString ) | |
| 2785 : m_stream( stream ), | |
| 2786 m_prevBuf( stream.rdbuf() ), | |
| 2787 m_targetString( targetString ) | |
| 2788 { | |
| 2789 stream.rdbuf( m_oss.rdbuf() ); | |
| 2790 } | |
| 2791 | |
| 2792 ~StreamRedirect() { | |
| 2793 m_targetString += m_oss.str(); | |
| 2794 m_stream.rdbuf( m_prevBuf ); | |
| 2795 } | |
| 2796 | |
| 2797 private: | |
| 2798 std::ostream& m_stream; | |
| 2799 std::streambuf* m_prevBuf; | |
| 2800 std::ostringstream m_oss; | |
| 2801 std::string& m_targetString; | |
| 2802 }; | |
| 2803 | |
| 2804 /////////////////////////////////////////////////////////////////////////// | |
| 2805 | |
| 2806 class Runner : public IResultCapture, public IRunner { | |
| 2807 | |
| 2808 Runner( const Runner& ); | |
| 2809 void operator =( const Runner& ); | |
| 2810 | |
| 2811 public: | |
| 2812 | |
| 2813 explicit Runner( Config& config ) | |
| 2814 : m_context( getCurrentMutableContext() ), | |
| 2815 m_runningTest( NULL ), | |
| 2816 m_config( config ), | |
| 2817 m_reporter( config.getReporter() ), | |
| 2818 m_prevRunner( &m_context.getRunner() ), | |
| 2819 m_prevResultCapture( &m_context.getResultCapture() ) | |
| 2820 { | |
| 2821 m_context.setRunner( this ); | |
| 2822 m_context.setConfig( &m_config ); | |
| 2823 m_context.setResultCapture( this ); | |
| 2824 m_reporter->StartTesting(); | |
| 2825 } | |
| 2826 | |
| 2827 ~Runner() { | |
| 2828 m_reporter->EndTesting( m_totals ); | |
| 2829 m_context.setRunner( m_prevRunner ); | |
| 2830 m_context.setConfig( NULL ); | |
| 2831 m_context.setResultCapture( m_prevResultCapture ); | |
| 2832 } | |
| 2833 | |
| 2834 virtual void runAll( bool runHiddenTests = false ) { | |
| 2835 const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests(); | |
| 2836 for( std::size_t i=0; i < allTests.size(); ++i ) { | |
| 2837 if( runHiddenTests || !allTests[i].isHidden() ) | |
| 2838 { | |
| 2839 if( aborting() ) { | |
| 2840 m_reporter->Aborted(); | |
| 2841 break; | |
| 2842 } | |
| 2843 runTest( allTests[i] ); | |
| 2844 } | |
| 2845 } | |
| 2846 } | |
| 2847 | |
| 2848 virtual std::size_t runMatching( const std::string& rawTestSpec ) { | |
| 2849 TestSpec testSpec( rawTestSpec ); | |
| 2850 | |
| 2851 const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests(); | |
| 2852 std::size_t testsRun = 0; | |
| 2853 for( std::size_t i=0; i < allTests.size(); ++i ) { | |
| 2854 if( testSpec.matches( allTests[i].getName() ) ) { | |
| 2855 if( aborting() ) { | |
| 2856 m_reporter->Aborted(); | |
| 2857 break; | |
| 2858 } | |
| 2859 runTest( allTests[i] ); | |
| 2860 testsRun++; | |
| 2861 } | |
| 2862 } | |
| 2863 return testsRun; | |
| 2864 } | |
| 2865 | |
| 2866 void runTest( const TestCaseInfo& testInfo ) { | |
| 2867 Totals prevTotals = m_totals; | |
| 2868 | |
| 2869 std::string redirectedCout; | |
| 2870 std::string redirectedCerr; | |
| 2871 | |
| 2872 m_reporter->StartTestCase( testInfo ); | |
| 2873 | |
| 2874 m_runningTest = new RunningTest( &testInfo ); | |
| 2875 | |
| 2876 do { | |
| 2877 do { | |
| 2878 // m_reporter->StartGroup( "test case run" ); | |
| 2879 m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() ); | |
| 2880 runCurrentTest( redirectedCout, redirectedCerr ); | |
| 2881 // m_reporter->EndGroup( "test case run", m_totals.delta( prevTotals ) ); | |
| 2882 } | |
| 2883 while( m_runningTest->hasUntestedSections() && !aborting() ); | |
| 2884 } | |
| 2885 while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); | |
| 2886 | |
| 2887 delete m_runningTest; | |
| 2888 m_runningTest = NULL; | |
| 2889 | |
| 2890 Totals deltaTotals = m_totals.delta( prevTotals ); | |
| 2891 m_totals.testCases += deltaTotals.testCases; | |
| 2892 m_reporter->EndTestCase( testInfo, deltaTotals, redirectedCout, redirectedCerr ); | |
| 2893 } | |
| 2894 | |
| 2895 virtual Totals getTotals() const { | |
| 2896 return m_totals; | |
| 2897 } | |
| 2898 | |
| 2899 const Config& config() const { | |
| 2900 return m_config; | |
| 2901 } | |
| 2902 | |
| 2903 private: // IResultCapture | |
| 2904 | |
| 2905 virtual ResultAction::Value acceptResult( bool result ) { | |
| 2906 return acceptResult( result ? ResultWas::Ok : ResultWas::ExpressionFailed ); | |
| 2907 } | |
| 2908 | |
| 2909 virtual ResultAction::Value acceptResult( ResultWas::OfType result ) { | |
| 2910 m_currentResult.setResultType( result ); | |
| 2911 return actOnCurrentResult(); | |
| 2912 } | |
| 2913 | |
| 2914 virtual ResultAction::Value acceptExpression( const ResultInfoBuilder& resultInfo ) { | |
| 2915 m_currentResult = resultInfo; | |
| 2916 return actOnCurrentResult(); | |
| 2917 } | |
| 2918 | |
| 2919 virtual void acceptMessage( const std::string& msg ) { | |
| 2920 m_currentResult.setMessage( msg ); | |
| 2921 } | |
| 2922 | |
| 2923 virtual void testEnded( const ResultInfo& result ) { | |
| 2924 if( result.getResultType() == ResultWas::Ok ) { | |
| 2925 m_totals.assertions.passed++; | |
| 2926 } | |
| 2927 else if( !result.ok() ) { | |
| 2928 m_totals.assertions.failed++; | |
| 2929 | |
| 2930 std::vector<ResultInfo>::const_iterator it = m_info.begin(); | |
| 2931 std::vector<ResultInfo>::const_iterator itEnd = m_info.end(); | |
| 2932 for(; it != itEnd; ++it ) | |
| 2933 m_reporter->Result( *it ); | |
| 2934 m_info.clear(); | |
| 2935 } | |
| 2936 | |
| 2937 if( result.getResultType() == ResultWas::Info ) | |
| 2938 m_info.push_back( result ); | |
| 2939 else | |
| 2940 m_reporter->Result( result ); | |
| 2941 } | |
| 2942 | |
| 2943 virtual bool sectionStarted ( | |
| 2944 const std::string& name, | |
| 2945 const std::string& description, | |
| 2946 const SourceLineInfo& lineInfo, | |
| 2947 Counts& assertions | |
| 2948 ) | |
| 2949 { | |
| 2950 std::ostringstream oss; | |
| 2951 oss << name << "@" << lineInfo; | |
| 2952 | |
| 2953 if( !m_runningTest->addSection( oss.str() ) ) | |
| 2954 return false; | |
| 2955 | |
| 2956 m_currentResult.setLineInfo( lineInfo ); | |
| 2957 m_reporter->StartSection( name, description ); | |
| 2958 assertions = m_totals.assertions; | |
| 2959 | |
| 2960 return true; | |
| 2961 } | |
| 2962 | |
| 2963 virtual void sectionEnded( const std::string& name, const Counts& prevAssertions ) { | |
| 2964 m_runningTest->endSection( name ); | |
| 2965 m_reporter->EndSection( name, m_totals.assertions - prevAssertions ); | |
| 2966 } | |
| 2967 | |
| 2968 virtual void pushScopedInfo( ScopedInfo* scopedInfo ) { | |
| 2969 m_scopedInfos.push_back( scopedInfo ); | |
| 2970 } | |
| 2971 | |
| 2972 virtual void popScopedInfo( ScopedInfo* scopedInfo ) { | |
| 2973 if( m_scopedInfos.back() == scopedInfo ) | |
| 2974 m_scopedInfos.pop_back(); | |
| 2975 } | |
| 2976 | |
| 2977 virtual bool shouldDebugBreak() const { | |
| 2978 return m_config.shouldDebugBreak(); | |
| 2979 } | |
| 2980 | |
| 2981 virtual std::string getCurrentTestName() const { | |
| 2982 return m_runningTest | |
| 2983 ? m_runningTest->getTestCaseInfo().getName() | |
| 2984 : ""; | |
| 2985 } | |
| 2986 | |
| 2987 virtual const ResultInfo* getLastResult() const { | |
| 2988 return &m_lastResult; | |
| 2989 } | |
| 2990 | |
| 2991 private: | |
| 2992 | |
| 2993 bool aborting() const { | |
| 2994 return m_totals.assertions.failed == static_cast<std::size_t>( m_config.getCutoff() ); | |
| 2995 } | |
| 2996 | |
| 2997 ResultAction::Value actOnCurrentResult() { | |
| 2998 testEnded( m_currentResult ); | |
| 2999 m_lastResult = m_currentResult; | |
| 3000 | |
| 3001 m_currentResult = ResultInfoBuilder(); | |
| 3002 | |
| 3003 ResultAction::Value action = ResultAction::None; | |
| 3004 | |
| 3005 if( !m_lastResult.ok() ) { | |
| 3006 action = ResultAction::Failed; | |
| 3007 if( shouldDebugBreak() ) | |
| 3008 action = (ResultAction::Value)( action | ResultAction::Debug ); | |
| 3009 if( aborting() ) | |
| 3010 action = (ResultAction::Value)( action | ResultAction::Abort ); | |
| 3011 } | |
| 3012 return action; | |
| 3013 } | |
| 3014 | |
| 3015 void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { | |
| 3016 try { | |
| 3017 m_runningTest->reset(); | |
| 3018 if( m_reporter->shouldRedirectStdout() ) { | |
| 3019 StreamRedirect coutRedir( std::cout, redirectedCout ); | |
| 3020 StreamRedirect cerrRedir( std::cerr, redirectedCerr ); | |
| 3021 m_runningTest->getTestCaseInfo().invoke(); | |
| 3022 } | |
| 3023 else { | |
| 3024 m_runningTest->getTestCaseInfo().invoke(); | |
| 3025 } | |
| 3026 m_runningTest->ranToCompletion(); | |
| 3027 } | |
| 3028 catch( TestFailureException& ) { | |
| 3029 // This just means the test was aborted due to failure | |
| 3030 } | |
| 3031 catch(...) { | |
| 3032 acceptMessage( getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ); | |
| 3033 acceptResult( ResultWas::ThrewException ); | |
| 3034 } | |
| 3035 m_info.clear(); | |
| 3036 } | |
| 3037 | |
| 3038 private: | |
| 3039 IMutableContext& m_context; | |
| 3040 RunningTest* m_runningTest; | |
| 3041 ResultInfoBuilder m_currentResult; | |
| 3042 ResultInfo m_lastResult; | |
| 3043 | |
| 3044 const Config& m_config; | |
| 3045 Totals m_totals; | |
| 3046 Ptr<IReporter> m_reporter; | |
| 3047 std::vector<ScopedInfo*> m_scopedInfos; | |
| 3048 std::vector<ResultInfo> m_info; | |
| 3049 IRunner* m_prevRunner; | |
| 3050 IResultCapture* m_prevResultCapture; | |
| 3051 }; | |
| 3052 | |
| 3053 } // end namespace Catch | |
| 3054 | |
| 3055 // #included from: catch_generators_impl.hpp | |
| 3056 | |
| 3057 #include <vector> | |
| 3058 #include <string> | |
| 3059 #include <map> | |
| 3060 | |
| 3061 namespace Catch { | |
| 3062 | |
| 3063 struct GeneratorInfo { | |
| 3064 | |
| 3065 GeneratorInfo( std::size_t size ) | |
| 3066 : m_size( size ), | |
| 3067 m_currentIndex( 0 ) | |
| 3068 {} | |
| 3069 | |
| 3070 bool moveNext() { | |
| 3071 if( ++m_currentIndex == m_size ) { | |
| 3072 m_currentIndex = 0; | |
| 3073 return false; | |
| 3074 } | |
| 3075 return true; | |
| 3076 } | |
| 3077 | |
| 3078 std::size_t getCurrentIndex() const { | |
| 3079 return m_currentIndex; | |
| 3080 } | |
| 3081 | |
| 3082 std::size_t m_size; | |
| 3083 std::size_t m_currentIndex; | |
| 3084 }; | |
| 3085 | |
| 3086 /////////////////////////////////////////////////////////////////////////// | |
| 3087 | |
| 3088 class GeneratorsForTest { | |
| 3089 | |
| 3090 public: | |
| 3091 ~GeneratorsForTest() { | |
| 3092 deleteAll( m_generatorsInOrder ); | |
| 3093 } | |
| 3094 | |
| 3095 GeneratorInfo& getGeneratorInfo( const std::string& fileInfo, std::size_t size ) { | |
| 3096 std::map<std::string, GeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo ); | |
| 3097 if( it == m_generatorsByName.end() ) { | |
| 3098 GeneratorInfo* info = new GeneratorInfo( size ); | |
| 3099 m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); | |
| 3100 m_generatorsInOrder.push_back( info ); | |
| 3101 return *info; | |
| 3102 } | |
| 3103 return *it->second; | |
| 3104 } | |
| 3105 | |
| 3106 bool moveNext() { | |
| 3107 std::vector<GeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin(); | |
| 3108 std::vector<GeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end(); | |
| 3109 for(; it != itEnd; ++it ) { | |
| 3110 if( (*it)->moveNext() ) | |
| 3111 return true; | |
| 3112 } | |
| 3113 return false; | |
| 3114 } | |
| 3115 | |
| 3116 private: | |
| 3117 std::map<std::string, GeneratorInfo*> m_generatorsByName; | |
| 3118 std::vector<GeneratorInfo*> m_generatorsInOrder; | |
| 3119 }; | |
| 3120 | |
| 3121 } // end namespace Catch | |
| 3122 | |
| 3123 #define INTERNAL_CATCH_LINESTR2( line ) #line | |
| 3124 #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) | |
| 3125 | |
| 3126 #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) | |
| 3127 | |
| 3128 // #included from: catch_console_colour_impl.hpp | |
| 3129 | |
| 3130 // #included from: catch_console_colour.hpp | |
| 3131 | |
| 3132 namespace Catch { | |
| 3133 | |
| 3134 struct ConsoleColourImpl; | |
| 3135 | |
| 3136 class TextColour : NonCopyable { | |
| 3137 public: | |
| 3138 | |
| 3139 enum Colours { | |
| 3140 None, | |
| 3141 | |
| 3142 FileName, | |
| 3143 ResultError, | |
| 3144 ResultSuccess, | |
| 3145 | |
| 3146 Error, | |
| 3147 Success, | |
| 3148 | |
| 3149 OriginalExpression, | |
| 3150 ReconstructedExpression | |
| 3151 }; | |
| 3152 | |
| 3153 TextColour( Colours colour = None ); | |
| 3154 void set( Colours colour ); | |
| 3155 ~TextColour(); | |
| 3156 | |
| 3157 private: | |
| 3158 ConsoleColourImpl* m_impl; | |
| 3159 }; | |
| 3160 | |
| 3161 } // end namespace Catch | |
| 3162 | |
| 3163 #ifdef CATCH_PLATFORM_WINDOWS | |
| 3164 | |
| 3165 #include <windows.h> | |
| 3166 | |
| 3167 namespace Catch { | |
| 3168 | |
| 3169 namespace { | |
| 3170 | |
| 3171 WORD mapConsoleColour( TextColour::Colours colour ) { | |
| 3172 switch( colour ) { | |
| 3173 case TextColour::FileName: | |
| 3174 return FOREGROUND_INTENSITY; // greyed out | |
| 3175 case TextColour::ResultError: | |
| 3176 return FOREGROUND_RED | FOREGROUND_INTENSITY; // bright red | |
| 3177 case TextColour::ResultSuccess: | |
| 3178 return FOREGROUND_GREEN | FOREGROUND_INTENSITY; // bright green | |
| 3179 case TextColour::Error: | |
| 3180 return FOREGROUND_RED; // dark red | |
| 3181 case TextColour::Success: | |
| 3182 return FOREGROUND_GREEN; // dark green | |
| 3183 case TextColour::OriginalExpression: | |
| 3184 return FOREGROUND_BLUE | FOREGROUND_GREEN; // turquoise | |
| 3185 case TextColour::ReconstructedExpression: | |
| 3186 return FOREGROUND_RED | FOREGROUND_GREEN; // greeny-yellow | |
| 3187 default: return 0; | |
| 3188 } | |
| 3189 } | |
| 3190 } | |
| 3191 | |
| 3192 struct ConsoleColourImpl { | |
| 3193 | |
| 3194 ConsoleColourImpl() | |
| 3195 : hStdout( GetStdHandle(STD_OUTPUT_HANDLE) ), | |
| 3196 wOldColorAttrs( 0 ) | |
| 3197 { | |
| 3198 GetConsoleScreenBufferInfo( hStdout, &csbiInfo ); | |
| 3199 wOldColorAttrs = csbiInfo.wAttributes; | |
| 3200 } | |
| 3201 | |
| 3202 ~ConsoleColourImpl() { | |
| 3203 SetConsoleTextAttribute( hStdout, wOldColorAttrs ); | |
| 3204 } | |
| 3205 | |
| 3206 void set( TextColour::Colours colour ) { | |
| 3207 WORD consoleColour = mapConsoleColour( colour ); | |
| 3208 if( consoleColour > 0 ) | |
| 3209 SetConsoleTextAttribute( hStdout, consoleColour ); | |
| 3210 } | |
| 3211 | |
| 3212 HANDLE hStdout; | |
| 3213 CONSOLE_SCREEN_BUFFER_INFO csbiInfo; | |
| 3214 WORD wOldColorAttrs; | |
| 3215 }; | |
| 3216 | |
| 3217 TextColour::TextColour( Colours colour ) | |
| 3218 : m_impl( new ConsoleColourImpl() ) | |
| 3219 { | |
| 3220 if( colour ) | |
| 3221 m_impl->set( colour ); | |
| 3222 } | |
| 3223 | |
| 3224 TextColour::~TextColour() { | |
| 3225 delete m_impl; | |
| 3226 } | |
| 3227 | |
| 3228 void TextColour::set( Colours colour ) { | |
| 3229 m_impl->set( colour ); | |
| 3230 } | |
| 3231 | |
| 3232 } // end namespace Catch | |
| 3233 | |
| 3234 #else | |
| 3235 | |
| 3236 namespace Catch { | |
| 3237 TextColour::TextColour( Colours ){} | |
| 3238 TextColour::~TextColour(){} | |
| 3239 void TextColour::set( Colours ){} | |
| 3240 | |
| 3241 } // end namespace Catch | |
| 3242 | |
| 3243 #endif | |
| 3244 | |
| 3245 | |
| 3246 // #included from: catch_exception_translator_registry.hpp | |
| 3247 | |
| 3248 #ifdef __OBJC__ | |
| 3249 #import "Foundation/Foundation.h" | |
| 3250 #endif | |
| 3251 | |
| 3252 namespace Catch { | |
| 3253 | |
| 3254 class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { | |
| 3255 | |
| 3256 ~ExceptionTranslatorRegistry() { | |
| 3257 deleteAll( m_translators ); | |
| 3258 } | |
| 3259 | |
| 3260 virtual void registerTranslator( IExceptionTranslator* translator ) { | |
| 3261 m_translators.push_back( translator ); | |
| 3262 } | |
| 3263 | |
| 3264 virtual std::string translateActiveException() const { | |
| 3265 try { | |
| 3266 #ifdef __OBJC__ | |
| 3267 // In Objective-C try objective-c exceptions first | |
| 3268 @try { | |
| 3269 throw; | |
| 3270 } | |
| 3271 @catch (NSException *exception) { | |
| 3272 return toString( [exception description] ); | |
| 3273 } | |
| 3274 #else | |
| 3275 throw; | |
| 3276 #endif | |
| 3277 } | |
| 3278 catch( std::exception& ex ) { | |
| 3279 return ex.what(); | |
| 3280 } | |
| 3281 catch( std::string& msg ) { | |
| 3282 return msg; | |
| 3283 } | |
| 3284 catch( const char* msg ) { | |
| 3285 return msg; | |
| 3286 } | |
| 3287 catch(...) { | |
| 3288 return tryTranslators( m_translators.begin() ); | |
| 3289 } | |
| 3290 } | |
| 3291 | |
| 3292 std::string tryTranslators( std::vector<IExceptionTranslator*>::const_iterator it ) const { | |
| 3293 if( it == m_translators.end() ) | |
| 3294 return "Unknown exception"; | |
| 3295 | |
| 3296 try { | |
| 3297 return (*it)->translate(); | |
| 3298 } | |
| 3299 catch(...) { | |
| 3300 return tryTranslators( it+1 ); | |
| 3301 } | |
| 3302 } | |
| 3303 | |
| 3304 private: | |
| 3305 std::vector<IExceptionTranslator*> m_translators; | |
| 3306 }; | |
| 3307 } | |
| 3308 | |
| 3309 // #included from: catch_reporter_registry.hpp | |
| 3310 | |
| 3311 #include <map> | |
| 3312 | |
| 3313 namespace Catch { | |
| 3314 | |
| 3315 class ReporterRegistry : public IReporterRegistry { | |
| 3316 | |
| 3317 public: | |
| 3318 | |
| 3319 ~ReporterRegistry() { | |
| 3320 deleteAllValues( m_factories ); | |
| 3321 } | |
| 3322 | |
| 3323 virtual IReporter* create( const std::string& name, const IReporterConfig& config ) const { | |
| 3324 FactoryMap::const_iterator it = m_factories.find( name ); | |
| 3325 if( it == m_factories.end() ) | |
| 3326 return NULL; | |
| 3327 return it->second->create( config ); | |
| 3328 } | |
| 3329 | |
| 3330 void registerReporter( const std::string& name, IReporterFactory* factory ) { | |
| 3331 m_factories.insert( std::make_pair( name, factory ) ); | |
| 3332 } | |
| 3333 | |
| 3334 const FactoryMap& getFactories() const { | |
| 3335 return m_factories; | |
| 3336 } | |
| 3337 | |
| 3338 private: | |
| 3339 FactoryMap m_factories; | |
| 3340 }; | |
| 3341 } | |
| 3342 | |
| 3343 // #included from: catch_stream.hpp | |
| 3344 | |
| 3345 #include <stdexcept> | |
| 3346 #include <cstdio> | |
| 3347 | |
| 3348 namespace Catch { | |
| 3349 | |
| 3350 template<typename WriterF, size_t bufferSize=256> | |
| 3351 class StreamBufImpl : public StreamBufBase { | |
| 3352 char data[bufferSize]; | |
| 3353 WriterF m_writer; | |
| 3354 | |
| 3355 public: | |
| 3356 StreamBufImpl() { | |
| 3357 setp( data, data + sizeof(data) ); | |
| 3358 } | |
| 3359 | |
| 3360 ~StreamBufImpl() { | |
| 3361 sync(); | |
| 3362 } | |
| 3363 | |
| 3364 private: | |
| 3365 int overflow( int c ) { | |
| 3366 sync(); | |
| 3367 | |
| 3368 if( c != EOF ) { | |
| 3369 if( pbase() == epptr() ) | |
| 3370 m_writer( std::string( 1, static_cast<char>( c ) ) ); | |
| 3371 else | |
| 3372 sputc( static_cast<char>( c ) ); | |
| 3373 } | |
| 3374 return 0; | |
| 3375 } | |
| 3376 | |
| 3377 int sync() { | |
| 3378 if( pbase() != pptr() ) { | |
| 3379 m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); | |
| 3380 setp( pbase(), epptr() ); | |
| 3381 } | |
| 3382 return 0; | |
| 3383 } | |
| 3384 }; | |
| 3385 | |
| 3386 /////////////////////////////////////////////////////////////////////////// | |
| 3387 | |
| 3388 struct OutputDebugWriter { | |
| 3389 | |
| 3390 void operator()( const std::string &str ) { | |
| 3391 writeToDebugConsole( str ); | |
| 3392 } | |
| 3393 }; | |
| 3394 } | |
| 3395 | |
| 3396 namespace Catch { | |
| 3397 | |
| 3398 namespace { | |
| 3399 Context* currentContext = NULL; | |
| 3400 } | |
| 3401 IMutableContext& getCurrentMutableContext() { | |
| 3402 if( !currentContext ) | |
| 3403 currentContext = new Context(); | |
| 3404 return *currentContext; | |
| 3405 } | |
| 3406 IContext& getCurrentContext() { | |
| 3407 return getCurrentMutableContext(); | |
| 3408 } | |
| 3409 | |
| 3410 Context::Context() | |
| 3411 : m_reporterRegistry( new ReporterRegistry ), | |
| 3412 m_testCaseRegistry( new TestRegistry ), | |
| 3413 m_exceptionTranslatorRegistry( new ExceptionTranslatorRegistry ), | |
| 3414 m_config( NULL ) | |
| 3415 {} | |
| 3416 | |
| 3417 void Context::cleanUp() { | |
| 3418 delete currentContext; | |
| 3419 currentContext = NULL; | |
| 3420 } | |
| 3421 | |
| 3422 void Context::setRunner( IRunner* runner ) { | |
| 3423 m_runner = runner; | |
| 3424 } | |
| 3425 | |
| 3426 void Context::setResultCapture( IResultCapture* resultCapture ) { | |
| 3427 m_resultCapture = resultCapture; | |
| 3428 } | |
| 3429 | |
| 3430 const IConfig* Context::getConfig() const { | |
| 3431 return m_config; | |
| 3432 } | |
| 3433 void Context::setConfig( const IConfig* config ) { | |
| 3434 m_config = config; | |
| 3435 } | |
| 3436 | |
| 3437 IResultCapture& Context::getResultCapture() { | |
| 3438 return *m_resultCapture; | |
| 3439 } | |
| 3440 | |
| 3441 IRunner& Context::getRunner() { | |
| 3442 return *m_runner; | |
| 3443 } | |
| 3444 | |
| 3445 IReporterRegistry& Context::getReporterRegistry() { | |
| 3446 return *m_reporterRegistry.get(); | |
| 3447 } | |
| 3448 | |
| 3449 ITestCaseRegistry& Context::getTestCaseRegistry() { | |
| 3450 return *m_testCaseRegistry.get(); | |
| 3451 } | |
| 3452 | |
| 3453 IExceptionTranslatorRegistry& Context::getExceptionTranslatorRegistry() { | |
| 3454 return *m_exceptionTranslatorRegistry.get(); | |
| 3455 } | |
| 3456 | |
| 3457 std::streambuf* Context::createStreamBuf( const std::string& streamName ) { | |
| 3458 if( streamName == "stdout" ) return std::cout.rdbuf(); | |
| 3459 if( streamName == "stderr" ) return std::cerr.rdbuf(); | |
| 3460 if( streamName == "debug" ) return new StreamBufImpl<OutputDebugWriter>; | |
| 3461 | |
| 3462 throw std::domain_error( "Unknown stream: " + streamName ); | |
| 3463 } | |
| 3464 | |
| 3465 GeneratorsForTest* Context::findGeneratorsForCurrentTest() { | |
| 3466 std::string testName = getResultCapture().getCurrentTestName(); | |
| 3467 | |
| 3468 std::map<std::string, GeneratorsForTest*>::const_iterator it = | |
| 3469 m_generatorsByTestName.find( testName ); | |
| 3470 return it != m_generatorsByTestName.end() | |
| 3471 ? it->second | |
| 3472 : NULL; | |
| 3473 } | |
| 3474 | |
| 3475 GeneratorsForTest& Context::getGeneratorsForCurrentTest() { | |
| 3476 GeneratorsForTest* generators = findGeneratorsForCurrentTest(); | |
| 3477 if( !generators ) { | |
| 3478 std::string testName = getResultCapture().getCurrentTestName(); | |
| 3479 generators = new GeneratorsForTest(); | |
| 3480 m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); | |
| 3481 } | |
| 3482 return *generators; | |
| 3483 } | |
| 3484 | |
| 3485 size_t Context::getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) { | |
| 3486 return getGeneratorsForCurrentTest() | |
| 3487 .getGeneratorInfo( fileInfo, totalSize ) | |
| 3488 .getCurrentIndex(); | |
| 3489 } | |
| 3490 | |
| 3491 bool Context::advanceGeneratorsForCurrentTest() { | |
| 3492 GeneratorsForTest* generators = findGeneratorsForCurrentTest(); | |
| 3493 return generators && generators->moveNext(); | |
| 3494 } | |
| 3495 } | |
| 3496 // #included from: internal/catch_commandline.hpp | |
| 3497 | |
| 3498 namespace Catch { | |
| 3499 | |
| 3500 class Command { | |
| 3501 public: | |
| 3502 Command(){} | |
| 3503 | |
| 3504 explicit Command( const std::string& name ) : m_name( name ) {} | |
| 3505 | |
| 3506 Command& operator += ( const std::string& arg ) { | |
| 3507 m_args.push_back( arg ); | |
| 3508 return *this; | |
| 3509 } | |
| 3510 Command& operator += ( const Command& other ) { | |
| 3511 std::copy( other.m_args.begin(), other.m_args.end(), std::back_inserter( m_args ) ); | |
| 3512 if( m_name.empty() ) | |
| 3513 m_name = other.m_name; | |
| 3514 return *this; | |
| 3515 } | |
| 3516 Command operator + ( const Command& other ) { | |
| 3517 Command newCommand( *this ); | |
| 3518 newCommand += other; | |
| 3519 return newCommand; | |
| 3520 } | |
| 3521 | |
| 3522 operator SafeBool::type() const { | |
| 3523 return SafeBool::makeSafe( !m_name.empty() ); | |
| 3524 } | |
| 3525 | |
| 3526 std::string name() const { return m_name; } | |
| 3527 std::string operator[]( std::size_t i ) const { return m_args[i]; } | |
| 3528 std::size_t argsCount() const { return m_args.size(); } | |
| 3529 | |
| 3530 void raiseError( const std::string& message ) const { | |
| 3531 std::ostringstream oss; | |
| 3532 oss << "Error while parsing " << m_name << ". " << message << "."; | |
| 3533 if( m_args.size() > 0 ) | |
| 3534 oss << " Arguments where:"; | |
| 3535 for( std::size_t i = 0; i < m_args.size(); ++i ) | |
| 3536 oss << " " << m_args[i]; | |
| 3537 throw std::domain_error( oss.str() ); | |
| 3538 } | |
| 3539 | |
| 3540 private: | |
| 3541 | |
| 3542 std::string m_name; | |
| 3543 std::vector<std::string> m_args; | |
| 3544 }; | |
| 3545 | |
| 3546 class CommandParser { | |
| 3547 public: | |
| 3548 CommandParser( int argc, char const * const * argv ) : m_argc( static_cast<std::size_t>( argc ) ), m_argv( argv ) {} | |
| 3549 | |
| 3550 Command find( const std::string& arg1, const std::string& arg2, const std::string& arg3 ) const { | |
| 3551 return find( arg1 ) + find( arg2 ) + find( arg3 ); | |
| 3552 } | |
| 3553 | |
| 3554 Command find( const std::string& shortArg, const std::string& longArg ) const { | |
| 3555 return find( shortArg ) + find( longArg ); | |
| 3556 } | |
| 3557 Command find( const std::string& arg ) const { | |
| 3558 for( std::size_t i = 0; i < m_argc; ++i ) | |
| 3559 if( m_argv[i] == arg ) | |
| 3560 return getArgs( i ); | |
| 3561 return Command(); | |
| 3562 } | |
| 3563 | |
| 3564 private: | |
| 3565 Command getArgs( std::size_t from ) const { | |
| 3566 Command command( m_argv[from] ); | |
| 3567 for( std::size_t i = from+1; i < m_argc && m_argv[i][0] != '-'; ++i ) | |
| 3568 command += m_argv[i]; | |
| 3569 return command; | |
| 3570 } | |
| 3571 | |
| 3572 std::size_t m_argc; | |
| 3573 char const * const * m_argv; | |
| 3574 }; | |
| 3575 | |
| 3576 inline bool parseIntoConfig( const CommandParser& parser, Config& config ) { | |
| 3577 | |
| 3578 try { | |
| 3579 if( Command cmd = parser.find( "-l", "--list" ) ) { | |
| 3580 if( cmd.argsCount() > 2 ) | |
| 3581 cmd.raiseError( "Expected upto 2 arguments" ); | |
| 3582 | |
| 3583 List::What listSpec = List::All; | |
| 3584 if( cmd.argsCount() >= 1 ) { | |
| 3585 if( cmd[0] == "tests" ) | |
| 3586 listSpec = List::Tests; | |
| 3587 else if( cmd[0] == "reporters" ) | |
| 3588 listSpec = List::Reports; | |
| 3589 else | |
| 3590 cmd.raiseError( "Expected [tests] or [reporters]" ); | |
| 3591 } | |
| 3592 if( cmd.argsCount() >= 2 ) { | |
| 3593 if( cmd[1] == "xml" ) | |
| 3594 listSpec = static_cast<List::What>( listSpec | List::AsXml ); | |
| 3595 else if( cmd[1] == "text" ) | |
| 3596 listSpec = static_cast<List::What>( listSpec | List::AsText ); | |
| 3597 else | |
| 3598 cmd.raiseError( "Expected [xml] or [text]" ); | |
| 3599 } | |
| 3600 config.setListSpec( static_cast<List::What>( config.getListSpec() | listSpec ) ); | |
| 3601 } | |
| 3602 | |
| 3603 if( Command cmd = parser.find( "-t", "--test" ) ) { | |
| 3604 if( cmd.argsCount() == 0 ) | |
| 3605 cmd.raiseError( "Expected at least one argument" ); | |
| 3606 for( std::size_t i = 0; i < cmd.argsCount(); ++i ) | |
| 3607 config.addTestSpec( cmd[i] ); | |
| 3608 } | |
| 3609 | |
| 3610 if( Command cmd = parser.find( "-r", "--reporter" ) ) { | |
| 3611 if( cmd.argsCount() != 1 ) | |
| 3612 cmd.raiseError( "Expected one argument" ); | |
| 3613 config.setReporter( cmd[0] ); | |
| 3614 } | |
| 3615 | |
| 3616 if( Command cmd = parser.find( "-o", "--out" ) ) { | |
| 3617 if( cmd.argsCount() == 0 ) | |
| 3618 cmd.raiseError( "Expected filename" ); | |
| 3619 if( cmd[0][0] == '%' ) | |
| 3620 config.useStream( cmd[0].substr( 1 ) ); | |
| 3621 else | |
| 3622 config.setFilename( cmd[0] ); | |
| 3623 } | |
| 3624 | |
| 3625 if( Command cmd = parser.find( "-s", "--success" ) ) { | |
| 3626 if( cmd.argsCount() != 0 ) | |
| 3627 cmd.raiseError( "Does not accept arguments" ); | |
| 3628 config.setIncludeWhichResults( Include::SuccessfulResults ); | |
| 3629 } | |
| 3630 | |
| 3631 if( Command cmd = parser.find( "-b", "--break" ) ) { | |
| 3632 if( cmd.argsCount() != 0 ) | |
| 3633 cmd.raiseError( "Does not accept arguments" ); | |
| 3634 config.setShouldDebugBreak( true ); | |
| 3635 } | |
| 3636 | |
| 3637 if( Command cmd = parser.find( "-n", "--name" ) ) { | |
| 3638 if( cmd.argsCount() != 1 ) | |
| 3639 cmd.raiseError( "Expected a name" ); | |
| 3640 config.setName( cmd[0] ); | |
| 3641 } | |
| 3642 | |
| 3643 if( Command cmd = parser.find( "-h", "-?", "--help" ) ) { | |
| 3644 if( cmd.argsCount() != 0 ) | |
| 3645 cmd.raiseError( "Does not accept arguments" ); | |
| 3646 config.setShowHelp( true ); | |
| 3647 } | |
| 3648 | |
| 3649 if( Command cmd = parser.find( "-a", "--abort" ) ) { | |
| 3650 if( cmd.argsCount() > 1 ) | |
| 3651 cmd.raiseError( "Only accepts 0-1 arguments" ); | |
| 3652 int threshold = 1; | |
| 3653 if( cmd.argsCount() == 1 ) | |
| 3654 { | |
| 3655 std::stringstream ss; | |
| 3656 ss << cmd[0]; | |
| 3657 ss >> threshold; | |
| 3658 } | |
| 3659 config.setCutoff( threshold ); | |
| 3660 } | |
| 3661 | |
| 3662 if( Command cmd = parser.find( "-nt", "--nothrow" ) ) { | |
| 3663 if( cmd.argsCount() != 0 ) | |
| 3664 cmd.raiseError( "Does not accept arguments" ); | |
| 3665 config.setAllowThrows( false ); | |
| 3666 } | |
| 3667 | |
| 3668 } | |
| 3669 catch( std::exception& ex ) { | |
| 3670 config.setError( ex.what() ); | |
| 3671 return false; | |
| 3672 } | |
| 3673 return true; | |
| 3674 } | |
| 3675 | |
| 3676 } // end namespace Catch | |
| 3677 | |
| 3678 // #included from: internal/catch_list.hpp | |
| 3679 | |
| 3680 #include <limits> | |
| 3681 | |
| 3682 namespace Catch { | |
| 3683 inline int List( Config& config ) { | |
| 3684 | |
| 3685 IContext& context = getCurrentContext(); | |
| 3686 if( config.listWhat() & List::Reports ) { | |
| 3687 std::cout << "Available reports:\n"; | |
| 3688 IReporterRegistry::FactoryMap::const_iterator it = context.getReporterRegistry().getFactories().begin(); | |
| 3689 IReporterRegistry::FactoryMap::const_iterator itEnd = context.getReporterRegistry().getFactories().end(); | |
| 3690 for(; it != itEnd; ++it ) { | |
| 3691 // !TBD: consider listAs() | |
| 3692 std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n"; | |
| 3693 } | |
| 3694 std::cout << std::endl; | |
| 3695 } | |
| 3696 | |
| 3697 if( config.listWhat() & List::Tests ) { | |
| 3698 std::cout << "Available tests:\n"; | |
| 3699 std::vector<TestCaseInfo>::const_iterator it = context.getTestCaseRegistry().getAllTests().begin(); | |
| 3700 std::vector<TestCaseInfo>::const_iterator itEnd = context.getTestCaseRegistry().getAllTests().end(); | |
| 3701 for(; it != itEnd; ++it ) { | |
| 3702 // !TBD: consider listAs() | |
| 3703 std::cout << "\t" << it->getName() << "\n\t\t '" << it->getDescription() << "'\n"; | |
| 3704 } | |
| 3705 std::cout << std::endl; | |
| 3706 } | |
| 3707 | |
| 3708 if( ( config.listWhat() & List::All ) == 0 ) { | |
| 3709 std::cerr << "Unknown list type" << std::endl; | |
| 3710 return (std::numeric_limits<int>::max)(); | |
| 3711 } | |
| 3712 | |
| 3713 if( config.getReporter().get() ) | |
| 3714 std::cerr << "Reporters ignored when listing" << std::endl; | |
| 3715 if( !config.testsSpecified() ) | |
| 3716 std::cerr << "Test specs ignored when listing" << std::endl; | |
| 3717 return 0; | |
| 3718 } | |
| 3719 | |
| 3720 } // end namespace Catch | |
| 3721 | |
| 3722 // #included from: reporters/catch_reporter_basic.hpp | |
| 3723 | |
| 3724 // #included from: ../internal/catch_reporter_registrars.hpp | |
| 3725 | |
| 3726 namespace Catch { | |
| 3727 | |
| 3728 template<typename T> | |
| 3729 class ReporterRegistrar { | |
| 3730 | |
| 3731 class ReporterFactory : public IReporterFactory { | |
| 3732 | |
| 3733 virtual IReporter* create( const IReporterConfig& config ) const { | |
| 3734 return new T( config ); | |
| 3735 } | |
| 3736 | |
| 3737 virtual std::string getDescription() const { | |
| 3738 return T::getDescription(); | |
| 3739 } | |
| 3740 }; | |
| 3741 | |
| 3742 public: | |
| 3743 | |
| 3744 ReporterRegistrar( const std::string& name ) { | |
| 3745 getCurrentContext().getReporterRegistry().registerReporter( name, new ReporterFactory() ); | |
| 3746 } | |
| 3747 }; | |
| 3748 } | |
| 3749 | |
| 3750 #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ | |
| 3751 Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); | |
| 3752 | |
| 3753 namespace Catch { | |
| 3754 | |
| 3755 struct pluralise { | |
| 3756 pluralise( std::size_t count, const std::string& label ) | |
| 3757 : m_count( count ), | |
| 3758 m_label( label ) | |
| 3759 {} | |
| 3760 | |
| 3761 friend std::ostream& operator << ( std::ostream& os, const pluralise& pluraliser ) { | |
| 3762 os << pluraliser.m_count << " " << pluraliser.m_label; | |
| 3763 if( pluraliser.m_count != 1 ) | |
| 3764 os << "s"; | |
| 3765 return os; | |
| 3766 } | |
| 3767 | |
| 3768 std::size_t m_count; | |
| 3769 std::string m_label; | |
| 3770 }; | |
| 3771 | |
| 3772 class BasicReporter : public SharedImpl<IReporter> { | |
| 3773 | |
| 3774 struct SpanInfo { | |
| 3775 | |
| 3776 SpanInfo() | |
| 3777 : emitted( false ) | |
| 3778 {} | |
| 3779 | |
| 3780 SpanInfo( const std::string& spanName ) | |
| 3781 : name( spanName ), | |
| 3782 emitted( false ) | |
| 3783 {} | |
| 3784 | |
| 3785 SpanInfo( const SpanInfo& other ) | |
| 3786 : name( other.name ), | |
| 3787 emitted( other.emitted ) | |
| 3788 {} | |
| 3789 | |
| 3790 std::string name; | |
| 3791 bool emitted; | |
| 3792 }; | |
| 3793 | |
| 3794 public: | |
| 3795 BasicReporter( const IReporterConfig& config ) | |
| 3796 : m_config( config ), | |
| 3797 m_firstSectionInTestCase( true ), | |
| 3798 m_aborted( false ) | |
| 3799 {} | |
| 3800 | |
| 3801 static std::string getDescription() { | |
| 3802 return "Reports test results as lines of text"; | |
| 3803 } | |
| 3804 | |
| 3805 private: | |
| 3806 | |
| 3807 void ReportCounts( const std::string& label, const Counts& counts, const std::string& allPrefix = "All " ) { | |
| 3808 if( counts.passed ) | |
| 3809 m_config.stream() << counts.failed << " of " << counts.total() << " " << label << "s failed"; | |
| 3810 else | |
| 3811 m_config.stream() << ( counts.failed > 1 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed"; | |
| 3812 } | |
| 3813 | |
| 3814 void ReportCounts( const Totals& totals, const std::string& allPrefix = "All " ) { | |
| 3815 if( totals.assertions.total() == 0 ) { | |
| 3816 m_config.stream() << "No tests ran"; | |
| 3817 } | |
| 3818 else if( totals.assertions.failed ) { | |
| 3819 TextColour colour( TextColour::ResultError ); | |
| 3820 ReportCounts( "test case", totals.testCases, allPrefix ); | |
| 3821 if( totals.testCases.failed > 0 ) { | |
| 3822 m_config.stream() << " ("; | |
| 3823 ReportCounts( "assertion", totals.assertions, allPrefix ); | |
| 3824 m_config.stream() << ")"; | |
| 3825 } | |
| 3826 } | |
| 3827 else { | |
| 3828 TextColour colour( TextColour::ResultSuccess ); | |
| 3829 m_config.stream() << allPrefix << "tests passed (" | |
| 3830 << pluralise( totals.assertions.passed, "assertion" ) << " in " | |
| 3831 << pluralise( totals.testCases.passed, "test case" ) << ")"; | |
| 3832 } | |
| 3833 } | |
| 3834 | |
| 3835 private: // IReporter | |
| 3836 | |
| 3837 virtual bool shouldRedirectStdout() const { | |
| 3838 return false; | |
| 3839 } | |
| 3840 | |
| 3841 virtual void StartTesting() { | |
| 3842 m_testingSpan = SpanInfo(); | |
| 3843 } | |
| 3844 | |
| 3845 virtual void Aborted() { | |
| 3846 m_aborted = true; | |
| 3847 } | |
| 3848 | |
| 3849 virtual void EndTesting( const Totals& totals ) { | |
| 3850 // Output the overall test results even if "Started Testing" was not emitted | |
| 3851 if( m_aborted ) { | |
| 3852 m_config.stream() << "\n[Testing aborted. "; | |
| 3853 ReportCounts( totals, "The first " ); | |
| 3854 } | |
| 3855 else { | |
| 3856 m_config.stream() << "\n[Testing completed. "; | |
| 3857 ReportCounts( totals ); | |
| 3858 } | |
| 3859 m_config.stream() << "]\n" << std::endl; | |
| 3860 } | |
| 3861 | |
| 3862 virtual void StartGroup( const std::string& groupName ) { | |
| 3863 m_groupSpan = groupName; | |
| 3864 } | |
| 3865 | |
| 3866 virtual void EndGroup( const std::string& groupName, const Totals& totals ) { | |
| 3867 if( m_groupSpan.emitted && !groupName.empty() ) { | |
| 3868 m_config.stream() << "[End of group: '" << groupName << "'. "; | |
| 3869 ReportCounts( totals ); | |
| 3870 m_config.stream() << "]\n" << std::endl; | |
| 3871 m_groupSpan = SpanInfo(); | |
| 3872 } | |
| 3873 } | |
| 3874 | |
| 3875 virtual void StartTestCase( const TestCaseInfo& testInfo ) { | |
| 3876 m_testSpan = testInfo.getName(); | |
| 3877 } | |
| 3878 | |
| 3879 virtual void StartSection( const std::string& sectionName, const std::string& ) { | |
| 3880 m_sectionSpans.push_back( SpanInfo( sectionName ) ); | |
| 3881 } | |
| 3882 | |
| 3883 virtual void EndSection( const std::string& sectionName, const Counts& assertions ) { | |
| 3884 SpanInfo& sectionSpan = m_sectionSpans.back(); | |
| 3885 if( sectionSpan.emitted && !sectionSpan.name.empty() ) { | |
| 3886 m_config.stream() << "[End of section: '" << sectionName << "' "; | |
| 3887 | |
| 3888 if( assertions.failed ) { | |
| 3889 TextColour colour( TextColour::ResultError ); | |
| 3890 ReportCounts( "assertion", assertions); | |
| 3891 } | |
| 3892 else { | |
| 3893 TextColour colour( TextColour::ResultSuccess ); | |
| 3894 m_config.stream() << ( assertions.passed > 1 ? "All " : "" ) | |
| 3895 << pluralise( assertions.passed, "assertion" ) << "passed" ; | |
| 3896 } | |
| 3897 m_config.stream() << "]\n" << std::endl; | |
| 3898 } | |
| 3899 m_sectionSpans.pop_back(); | |
| 3900 } | |
| 3901 | |
| 3902 virtual void Result( const ResultInfo& resultInfo ) { | |
| 3903 if( !m_config.includeSuccessfulResults() && resultInfo.getResultType() == ResultWas::Ok ) | |
| 3904 return; | |
| 3905 | |
| 3906 StartSpansLazily(); | |
| 3907 | |
| 3908 if( !resultInfo.getFilename().empty() ) { | |
| 3909 TextColour colour( TextColour::FileName ); | |
| 3910 m_config.stream() << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() ); | |
| 3911 } | |
| 3912 | |
| 3913 if( resultInfo.hasExpression() ) { | |
| 3914 TextColour colour( TextColour::OriginalExpression ); | |
| 3915 m_config.stream() << resultInfo.getExpression(); | |
| 3916 if( resultInfo.ok() ) { | |
| 3917 TextColour successColour( TextColour::Success ); | |
| 3918 m_config.stream() << " succeeded"; | |
| 3919 } | |
| 3920 else { | |
| 3921 TextColour errorColour( TextColour::Error ); | |
| 3922 m_config.stream() << " failed"; | |
| 3923 } | |
| 3924 } | |
| 3925 switch( resultInfo.getResultType() ) { | |
| 3926 case ResultWas::ThrewException: | |
| 3927 { | |
| 3928 TextColour colour( TextColour::Error ); | |
| 3929 if( resultInfo.hasExpression() ) | |
| 3930 m_config.stream() << " with unexpected"; | |
| 3931 else | |
| 3932 m_config.stream() << "Unexpected"; | |
| 3933 m_config.stream() << " exception with message: '" << resultInfo.getMessage() << "'"; | |
| 3934 } | |
| 3935 break; | |
| 3936 case ResultWas::DidntThrowException: | |
| 3937 { | |
| 3938 TextColour colour( TextColour::Error ); | |
| 3939 if( resultInfo.hasExpression() ) | |
| 3940 m_config.stream() << " because no exception was thrown where one was expected"; | |
| 3941 else | |
| 3942 m_config.stream() << "No exception thrown where one was expected"; | |
| 3943 } | |
| 3944 break; | |
| 3945 case ResultWas::Info: | |
| 3946 streamVariableLengthText( "info", resultInfo.getMessage() ); | |
| 3947 break; | |
| 3948 case ResultWas::Warning: | |
| 3949 m_config.stream() << "warning:\n'" << resultInfo.getMessage() << "'"; | |
| 3950 break; | |
| 3951 case ResultWas::ExplicitFailure: | |
| 3952 { | |
| 3953 TextColour colour( TextColour::Error ); | |
| 3954 m_config.stream() << "failed with message: '" << resultInfo.getMessage() << "'"; | |
| 3955 } | |
| 3956 break; | |
| 3957 case ResultWas::Unknown: // These cases are here to prevent compiler warnings | |
| 3958 case ResultWas::Ok: | |
| 3959 case ResultWas::FailureBit: | |
| 3960 case ResultWas::ExpressionFailed: | |
| 3961 case ResultWas::Exception: | |
| 3962 default: | |
| 3963 if( !resultInfo.hasExpression() ) { | |
| 3964 if( resultInfo.ok() ) { | |
| 3965 TextColour colour( TextColour::Success ); | |
| 3966 m_config.stream() << " succeeded"; | |
| 3967 } | |
| 3968 else { | |
| 3969 TextColour colour( TextColour::Error ); | |
| 3970 m_config.stream() << " failed"; | |
| 3971 } | |
| 3972 } | |
| 3973 break; | |
| 3974 } | |
| 3975 | |
| 3976 if( resultInfo.hasExpandedExpression() ) { | |
| 3977 m_config.stream() << " for: "; | |
| 3978 TextColour colour( TextColour::ReconstructedExpression ); | |
| 3979 m_config.stream() << resultInfo.getExpandedExpression(); | |
| 3980 } | |
| 3981 m_config.stream() << std::endl; | |
| 3982 } | |
| 3983 | |
| 3984 virtual void EndTestCase( const TestCaseInfo& testInfo, | |
| 3985 const Totals& totals, | |
| 3986 const std::string& stdOut, | |
| 3987 const std::string& stdErr ) { | |
| 3988 if( !stdOut.empty() ) { | |
| 3989 StartSpansLazily(); | |
| 3990 streamVariableLengthText( "stdout", stdOut ); | |
| 3991 } | |
| 3992 | |
| 3993 if( !stdErr.empty() ) { | |
| 3994 StartSpansLazily(); | |
| 3995 streamVariableLengthText( "stderr", stdErr ); | |
| 3996 } | |
| 3997 | |
| 3998 if( m_testSpan.emitted ) { | |
| 3999 m_config.stream() << "[Finished: '" << testInfo.getName() << "' "; | |
| 4000 ReportCounts( totals ); | |
| 4001 m_config.stream() << "]" << std::endl; | |
| 4002 } | |
| 4003 } | |
| 4004 | |
| 4005 private: // helpers | |
| 4006 | |
| 4007 void StartSpansLazily() { | |
| 4008 if( !m_testingSpan.emitted ) { | |
| 4009 if( m_config.getName().empty() ) | |
| 4010 m_config.stream() << "[Started testing]" << std::endl; | |
| 4011 else | |
| 4012 m_config.stream() << "[Started testing: " << m_config.getName() << "]" << std::endl; | |
| 4013 m_testingSpan.emitted = true; | |
| 4014 } | |
| 4015 | |
| 4016 if( !m_groupSpan.emitted && !m_groupSpan.name.empty() ) { | |
| 4017 m_config.stream() << "[Started group: '" << m_groupSpan.name << "']" << std::endl; | |
| 4018 m_groupSpan.emitted = true; | |
| 4019 } | |
| 4020 | |
| 4021 if( !m_testSpan.emitted ) { | |
| 4022 m_config.stream() << std::endl << "[Running: " << m_testSpan.name << "]" << std::endl; | |
| 4023 m_testSpan.emitted = true; | |
| 4024 } | |
| 4025 | |
| 4026 if( !m_sectionSpans.empty() ) { | |
| 4027 SpanInfo& sectionSpan = m_sectionSpans.back(); | |
| 4028 if( !sectionSpan.emitted && !sectionSpan.name.empty() ) { | |
| 4029 if( m_firstSectionInTestCase ) { | |
| 4030 m_config.stream() << "\n"; | |
| 4031 m_firstSectionInTestCase = false; | |
| 4032 } | |
| 4033 std::vector<SpanInfo>::iterator it = m_sectionSpans.begin(); | |
| 4034 std::vector<SpanInfo>::iterator itEnd = m_sectionSpans.end(); | |
| 4035 for(; it != itEnd; ++it ) { | |
| 4036 SpanInfo& prevSpan = *it; | |
| 4037 if( !prevSpan.emitted && !prevSpan.name.empty() ) { | |
| 4038 m_config.stream() << "[Started section: '" << prevSpan.name << "']" << std::endl; | |
| 4039 prevSpan.emitted = true; | |
| 4040 } | |
| 4041 } | |
| 4042 } | |
| 4043 } | |
| 4044 } | |
| 4045 | |
| 4046 void streamVariableLengthText( const std::string& prefix, const std::string& text ) { | |
| 4047 std::string trimmed = trim( text ); | |
| 4048 if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) { | |
| 4049 m_config.stream() << "[" << prefix << ": " << trimmed << "]\n"; | |
| 4050 } | |
| 4051 else { | |
| 4052 m_config.stream() << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed | |
| 4053 << "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n"; | |
| 4054 } | |
| 4055 } | |
| 4056 | |
| 4057 private: | |
| 4058 const IReporterConfig& m_config; | |
| 4059 bool m_firstSectionInTestCase; | |
| 4060 | |
| 4061 SpanInfo m_testingSpan; | |
| 4062 SpanInfo m_groupSpan; | |
| 4063 SpanInfo m_testSpan; | |
| 4064 std::vector<SpanInfo> m_sectionSpans; | |
| 4065 bool m_aborted; | |
| 4066 }; | |
| 4067 | |
| 4068 } // end namespace Catch | |
| 4069 | |
| 4070 // #included from: reporters/catch_reporter_xml.hpp | |
| 4071 | |
| 4072 // #included from: ../internal/catch_xmlwriter.hpp | |
| 4073 | |
| 4074 #include <sstream> | |
| 4075 #include <string> | |
| 4076 #include <vector> | |
| 4077 | |
| 4078 namespace Catch { | |
| 4079 | |
| 4080 class XmlWriter { | |
| 4081 public: | |
| 4082 | |
| 4083 class ScopedElement { | |
| 4084 public: | |
| 4085 ScopedElement( XmlWriter* writer ) | |
| 4086 : m_writer( writer ) | |
| 4087 {} | |
| 4088 | |
| 4089 ScopedElement( const ScopedElement& other ) | |
| 4090 : m_writer( other.m_writer ){ | |
| 4091 other.m_writer = NULL; | |
| 4092 } | |
| 4093 | |
| 4094 ~ScopedElement() { | |
| 4095 if( m_writer ) | |
| 4096 m_writer->endElement(); | |
| 4097 } | |
| 4098 | |
| 4099 ScopedElement& writeText( const std::string& text ) { | |
| 4100 m_writer->writeText( text ); | |
| 4101 return *this; | |
| 4102 } | |
| 4103 | |
| 4104 template<typename T> | |
| 4105 ScopedElement& writeAttribute( const std::string& name, const T& attribute ) { | |
| 4106 m_writer->writeAttribute( name, attribute ); | |
| 4107 return *this; | |
| 4108 } | |
| 4109 | |
| 4110 private: | |
| 4111 mutable XmlWriter* m_writer; | |
| 4112 }; | |
| 4113 | |
| 4114 XmlWriter() | |
| 4115 : m_tagIsOpen( false ), | |
| 4116 m_needsNewline( false ), | |
| 4117 m_os( &std::cout ) | |
| 4118 {} | |
| 4119 | |
| 4120 XmlWriter( std::ostream& os ) | |
| 4121 : m_tagIsOpen( false ), | |
| 4122 m_needsNewline( false ), | |
| 4123 m_os( &os ) | |
| 4124 {} | |
| 4125 | |
| 4126 ~XmlWriter() { | |
| 4127 while( !m_tags.empty() ) | |
| 4128 endElement(); | |
| 4129 } | |
| 4130 | |
| 4131 XmlWriter& operator = ( const XmlWriter& other ) { | |
| 4132 XmlWriter temp( other ); | |
| 4133 swap( temp ); | |
| 4134 return *this; | |
| 4135 } | |
| 4136 | |
| 4137 void swap( XmlWriter& other ) { | |
| 4138 std::swap( m_tagIsOpen, other.m_tagIsOpen ); | |
| 4139 std::swap( m_needsNewline, other.m_needsNewline ); | |
| 4140 std::swap( m_tags, other.m_tags ); | |
| 4141 std::swap( m_indent, other.m_indent ); | |
| 4142 std::swap( m_os, other.m_os ); | |
| 4143 } | |
| 4144 | |
| 4145 XmlWriter& startElement( const std::string& name ) { | |
| 4146 ensureTagClosed(); | |
| 4147 newlineIfNecessary(); | |
| 4148 stream() << m_indent << "<" << name; | |
| 4149 m_tags.push_back( name ); | |
| 4150 m_indent += " "; | |
| 4151 m_tagIsOpen = true; | |
| 4152 return *this; | |
| 4153 } | |
| 4154 | |
| 4155 ScopedElement scopedElement( const std::string& name ) { | |
| 4156 ScopedElement scoped( this ); | |
| 4157 startElement( name ); | |
| 4158 return scoped; | |
| 4159 } | |
| 4160 | |
| 4161 XmlWriter& endElement() { | |
| 4162 newlineIfNecessary(); | |
| 4163 m_indent = m_indent.substr( 0, m_indent.size()-2 ); | |
| 4164 if( m_tagIsOpen ) { | |
| 4165 stream() << "/>\n"; | |
| 4166 m_tagIsOpen = false; | |
| 4167 } | |
| 4168 else { | |
| 4169 stream() << m_indent << "</" << m_tags.back() << ">\n"; | |
| 4170 } | |
| 4171 m_tags.pop_back(); | |
| 4172 return *this; | |
| 4173 } | |
| 4174 | |
| 4175 XmlWriter& writeAttribute( const std::string& name, const std::string& attribute ) { | |
| 4176 if( !name.empty() && !attribute.empty() ) { | |
| 4177 stream() << " " << name << "=\""; | |
| 4178 writeEncodedText( attribute ); | |
| 4179 stream() << "\""; | |
| 4180 } | |
| 4181 return *this; | |
| 4182 } | |
| 4183 | |
| 4184 XmlWriter& writeAttribute( const std::string& name, bool attribute ) { | |
| 4185 stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; | |
| 4186 return *this; | |
| 4187 } | |
| 4188 | |
| 4189 template<typename T> | |
| 4190 XmlWriter& writeAttribute( const std::string& name, const T& attribute ) { | |
| 4191 if( !name.empty() ) | |
| 4192 stream() << " " << name << "=\"" << attribute << "\""; | |
| 4193 return *this; | |
| 4194 } | |
| 4195 | |
| 4196 XmlWriter& writeText( const std::string& text ) { | |
| 4197 if( !text.empty() ){ | |
| 4198 bool tagWasOpen = m_tagIsOpen; | |
| 4199 ensureTagClosed(); | |
| 4200 if( tagWasOpen ) | |
| 4201 stream() << m_indent; | |
| 4202 writeEncodedText( text ); | |
| 4203 m_needsNewline = true; | |
| 4204 } | |
| 4205 return *this; | |
| 4206 } | |
| 4207 | |
| 4208 XmlWriter& writeComment( const std::string& text ) { | |
| 4209 ensureTagClosed(); | |
| 4210 stream() << m_indent << "<!--" << text << "-->"; | |
| 4211 m_needsNewline = true; | |
| 4212 return *this; | |
| 4213 } | |
| 4214 | |
| 4215 XmlWriter& writeBlankLine() { | |
| 4216 ensureTagClosed(); | |
| 4217 stream() << "\n"; | |
| 4218 return *this; | |
| 4219 } | |
| 4220 | |
| 4221 private: | |
| 4222 | |
| 4223 std::ostream& stream() { | |
| 4224 return *m_os; | |
| 4225 } | |
| 4226 | |
| 4227 void ensureTagClosed() { | |
| 4228 if( m_tagIsOpen ) { | |
| 4229 stream() << ">\n"; | |
| 4230 m_tagIsOpen = false; | |
| 4231 } | |
| 4232 } | |
| 4233 | |
| 4234 void newlineIfNecessary() { | |
| 4235 if( m_needsNewline ) { | |
| 4236 stream() << "\n"; | |
| 4237 m_needsNewline = false; | |
| 4238 } | |
| 4239 } | |
| 4240 | |
| 4241 void writeEncodedText( const std::string& text ) { | |
| 4242 static const char* charsToEncode = "<&\""; | |
| 4243 std::string mtext = text; | |
| 4244 std::string::size_type pos = mtext.find_first_of( charsToEncode ); | |
| 4245 while( pos != std::string::npos ) { | |
| 4246 stream() << mtext.substr( 0, pos ); | |
| 4247 | |
| 4248 switch( mtext[pos] ) { | |
| 4249 case '<': | |
| 4250 stream() << "<"; | |
| 4251 break; | |
| 4252 case '&': | |
| 4253 stream() << "&"; | |
| 4254 break; | |
| 4255 case '\"': | |
| 4256 stream() << """; | |
| 4257 break; | |
| 4258 } | |
| 4259 mtext = mtext.substr( pos+1 ); | |
| 4260 pos = mtext.find_first_of( charsToEncode ); | |
| 4261 } | |
| 4262 stream() << mtext; | |
| 4263 } | |
| 4264 | |
| 4265 bool m_tagIsOpen; | |
| 4266 bool m_needsNewline; | |
| 4267 std::vector<std::string> m_tags; | |
| 4268 std::string m_indent; | |
| 4269 std::ostream* m_os; | |
| 4270 }; | |
| 4271 | |
| 4272 } | |
| 4273 namespace Catch { | |
| 4274 class XmlReporter : public SharedImpl<IReporter> { | |
| 4275 public: | |
| 4276 XmlReporter( const IReporterConfig& config ) : m_config( config ) {} | |
| 4277 | |
| 4278 static std::string getDescription() { | |
| 4279 return "Reports test results as an XML document"; | |
| 4280 } | |
| 4281 | |
| 4282 private: // IReporter | |
| 4283 | |
| 4284 virtual bool shouldRedirectStdout() const { | |
| 4285 return true; | |
| 4286 } | |
| 4287 | |
| 4288 virtual void StartTesting() { | |
| 4289 m_xml = XmlWriter( m_config.stream() ); | |
| 4290 m_xml.startElement( "Catch" ); | |
| 4291 if( !m_config.getName().empty() ) | |
| 4292 m_xml.writeAttribute( "name", m_config.getName() ); | |
| 4293 } | |
| 4294 | |
| 4295 virtual void EndTesting( const Totals& totals ) { | |
| 4296 m_xml.scopedElement( "OverallResults" ) | |
| 4297 .writeAttribute( "successes", totals.assertions.passed ) | |
| 4298 .writeAttribute( "failures", totals.assertions.failed ); | |
| 4299 m_xml.endElement(); | |
| 4300 } | |
| 4301 | |
| 4302 virtual void StartGroup( const std::string& groupName ) { | |
| 4303 m_xml.startElement( "Group" ) | |
| 4304 .writeAttribute( "name", groupName ); | |
| 4305 } | |
| 4306 | |
| 4307 virtual void EndGroup( const std::string&, const Totals& totals ) { | |
| 4308 m_xml.scopedElement( "OverallResults" ) | |
| 4309 .writeAttribute( "successes", totals.assertions.passed ) | |
| 4310 .writeAttribute( "failures", totals.assertions.failed ); | |
| 4311 m_xml.endElement(); | |
| 4312 } | |
| 4313 | |
| 4314 virtual void StartSection( const std::string& sectionName, const std::string& description ) { | |
| 4315 m_xml.startElement( "Section" ) | |
| 4316 .writeAttribute( "name", sectionName ) | |
| 4317 .writeAttribute( "description", description ); | |
| 4318 } | |
| 4319 | |
| 4320 virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) { | |
| 4321 m_xml.scopedElement( "OverallResults" ) | |
| 4322 .writeAttribute( "successes", assertions.passed ) | |
| 4323 .writeAttribute( "failures", assertions.failed ); | |
| 4324 m_xml.endElement(); | |
| 4325 } | |
| 4326 | |
| 4327 virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) { | |
| 4328 m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.getName() ); | |
| 4329 m_currentTestSuccess = true; | |
| 4330 } | |
| 4331 | |
| 4332 virtual void Result( const Catch::ResultInfo& resultInfo ) { | |
| 4333 if( !m_config.includeSuccessfulResults() && resultInfo.getResultType() == ResultWas::Ok ) | |
| 4334 return; | |
| 4335 | |
| 4336 if( resultInfo.hasExpression() ) { | |
| 4337 m_xml.startElement( "Expression" ) | |
| 4338 .writeAttribute( "success", resultInfo.ok() ) | |
| 4339 .writeAttribute( "filename", resultInfo.getFilename() ) | |
| 4340 .writeAttribute( "line", resultInfo.getLine() ); | |
| 4341 | |
| 4342 m_xml.scopedElement( "Original" ) | |
| 4343 .writeText( resultInfo.getExpression() ); | |
| 4344 m_xml.scopedElement( "Expanded" ) | |
| 4345 .writeText( resultInfo.getExpandedExpression() ); | |
| 4346 m_currentTestSuccess &= resultInfo.ok(); | |
| 4347 } | |
| 4348 | |
| 4349 switch( resultInfo.getResultType() ) { | |
| 4350 case ResultWas::ThrewException: | |
| 4351 m_xml.scopedElement( "Exception" ) | |
| 4352 .writeAttribute( "filename", resultInfo.getFilename() ) | |
| 4353 .writeAttribute( "line", resultInfo.getLine() ) | |
| 4354 .writeText( resultInfo.getMessage() ); | |
| 4355 m_currentTestSuccess = false; | |
| 4356 break; | |
| 4357 case ResultWas::Info: | |
| 4358 m_xml.scopedElement( "Info" ) | |
| 4359 .writeText( resultInfo.getMessage() ); | |
| 4360 break; | |
| 4361 case ResultWas::Warning: | |
| 4362 m_xml.scopedElement( "Warning" ) | |
| 4363 .writeText( resultInfo.getMessage() ); | |
| 4364 break; | |
| 4365 case ResultWas::ExplicitFailure: | |
| 4366 m_xml.scopedElement( "Failure" ) | |
| 4367 .writeText( resultInfo.getMessage() ); | |
| 4368 m_currentTestSuccess = false; | |
| 4369 break; | |
| 4370 case ResultWas::Unknown: | |
| 4371 case ResultWas::Ok: | |
| 4372 case ResultWas::FailureBit: | |
| 4373 case ResultWas::ExpressionFailed: | |
| 4374 case ResultWas::Exception: | |
| 4375 case ResultWas::DidntThrowException: | |
| 4376 default: | |
| 4377 break; | |
| 4378 } | |
| 4379 if( resultInfo.hasExpression() ) | |
| 4380 m_xml.endElement(); | |
| 4381 } | |
| 4382 | |
| 4383 virtual void Aborted() { | |
| 4384 // !TBD | |
| 4385 } | |
| 4386 | |
| 4387 virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) { | |
| 4388 m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess ); | |
| 4389 m_xml.endElement(); | |
| 4390 } | |
| 4391 | |
| 4392 private: | |
| 4393 const IReporterConfig& m_config; | |
| 4394 bool m_currentTestSuccess; | |
| 4395 XmlWriter m_xml; | |
| 4396 }; | |
| 4397 | |
| 4398 } // end namespace Catch | |
| 4399 | |
| 4400 // #included from: reporters/catch_reporter_junit.hpp | |
| 4401 | |
| 4402 namespace Catch { | |
| 4403 | |
| 4404 class JunitReporter : public SharedImpl<IReporter> { | |
| 4405 | |
| 4406 struct TestStats { | |
| 4407 std::string m_element; | |
| 4408 std::string m_resultType; | |
| 4409 std::string m_message; | |
| 4410 std::string m_content; | |
| 4411 }; | |
| 4412 | |
| 4413 struct TestCaseStats { | |
| 4414 | |
| 4415 TestCaseStats( const std::string& name = std::string() ) :m_name( name ){} | |
| 4416 | |
| 4417 double m_timeInSeconds; | |
| 4418 std::string m_status; | |
| 4419 std::string m_className; | |
| 4420 std::string m_name; | |
| 4421 std::vector<TestStats> m_testStats; | |
| 4422 }; | |
| 4423 | |
| 4424 struct Stats { | |
| 4425 | |
| 4426 Stats( const std::string& name = std::string() ) | |
| 4427 : m_testsCount( 0 ), | |
| 4428 m_failuresCount( 0 ), | |
| 4429 m_disabledCount( 0 ), | |
| 4430 m_errorsCount( 0 ), | |
| 4431 m_timeInSeconds( 0 ), | |
| 4432 m_name( name ) | |
| 4433 {} | |
| 4434 | |
| 4435 std::size_t m_testsCount; | |
| 4436 std::size_t m_failuresCount; | |
| 4437 std::size_t m_disabledCount; | |
| 4438 std::size_t m_errorsCount; | |
| 4439 double m_timeInSeconds; | |
| 4440 std::string m_name; | |
| 4441 | |
| 4442 std::vector<TestCaseStats> m_testCaseStats; | |
| 4443 }; | |
| 4444 | |
| 4445 public: | |
| 4446 JunitReporter( const IReporterConfig& config ) | |
| 4447 : m_config( config ), | |
| 4448 m_testSuiteStats( "AllTests" ), | |
| 4449 m_currentStats( &m_testSuiteStats ) | |
| 4450 {} | |
| 4451 | |
| 4452 static std::string getDescription() { | |
| 4453 return "Reports test results in an XML format that looks like Ant's junitreport target"; | |
| 4454 } | |
| 4455 | |
| 4456 private: // IReporter | |
| 4457 | |
| 4458 virtual bool shouldRedirectStdout() const { | |
| 4459 return true; | |
| 4460 } | |
| 4461 | |
| 4462 virtual void StartTesting(){} | |
| 4463 | |
| 4464 virtual void StartGroup( const std::string& groupName ) { | |
| 4465 m_statsForSuites.push_back( Stats( groupName ) ); | |
| 4466 m_currentStats = &m_statsForSuites.back(); | |
| 4467 } | |
| 4468 | |
| 4469 virtual void EndGroup( const std::string&, const Totals& totals ) { | |
| 4470 m_currentStats->m_testsCount = totals.assertions.total(); | |
| 4471 m_currentStats = &m_testSuiteStats; | |
| 4472 } | |
| 4473 | |
| 4474 virtual void StartSection( const std::string&, const std::string& ){} | |
| 4475 | |
| 4476 virtual void EndSection( const std::string&, const Counts& ){} | |
| 4477 | |
| 4478 virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) { | |
| 4479 m_currentStats->m_testCaseStats.push_back( TestCaseStats( testInfo.getName() ) ); | |
| 4480 } | |
| 4481 | |
| 4482 virtual void Result( const Catch::ResultInfo& resultInfo ) { | |
| 4483 if( resultInfo.getResultType() != ResultWas::Ok || m_config.includeSuccessfulResults() ) { | |
| 4484 TestCaseStats& testCaseStats = m_currentStats->m_testCaseStats.back(); | |
| 4485 TestStats stats; | |
| 4486 std::ostringstream oss; | |
| 4487 if( !resultInfo.getMessage().empty() ) | |
| 4488 oss << resultInfo.getMessage() << " at "; | |
| 4489 oss << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() ); | |
| 4490 stats.m_content = oss.str(); | |
| 4491 stats.m_message = resultInfo.getExpandedExpression(); | |
| 4492 stats.m_resultType = resultInfo.getTestMacroName(); | |
| 4493 | |
| 4494 switch( resultInfo.getResultType() ) { | |
| 4495 case ResultWas::ThrewException: | |
| 4496 stats.m_element = "error"; | |
| 4497 m_currentStats->m_errorsCount++; | |
| 4498 break; | |
| 4499 case ResultWas::Info: | |
| 4500 stats.m_element = "info"; // !TBD ? | |
| 4501 break; | |
| 4502 case ResultWas::Warning: | |
| 4503 stats.m_element = "warning"; // !TBD ? | |
| 4504 break; | |
| 4505 case ResultWas::ExplicitFailure: | |
| 4506 stats.m_element = "failure"; | |
| 4507 m_currentStats->m_failuresCount++; | |
| 4508 break; | |
| 4509 case ResultWas::ExpressionFailed: | |
| 4510 stats.m_element = "failure"; | |
| 4511 m_currentStats->m_failuresCount++; | |
| 4512 break; | |
| 4513 case ResultWas::Ok: | |
| 4514 stats.m_element = "success"; | |
| 4515 break; | |
| 4516 case ResultWas::Unknown: | |
| 4517 case ResultWas::FailureBit: | |
| 4518 case ResultWas::Exception: | |
| 4519 case ResultWas::DidntThrowException: | |
| 4520 default: | |
| 4521 stats.m_element = "unknown"; | |
| 4522 break; | |
| 4523 } | |
| 4524 testCaseStats.m_testStats.push_back( stats ); | |
| 4525 } | |
| 4526 } | |
| 4527 | |
| 4528 virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string& stdOut, const std::string& stdErr ) { | |
| 4529 if( !stdOut.empty() ) | |
| 4530 m_stdOut << stdOut << "\n"; | |
| 4531 if( !stdErr.empty() ) | |
| 4532 m_stdErr << stdErr << "\n"; | |
| 4533 } | |
| 4534 | |
| 4535 virtual void Aborted() { | |
| 4536 // !TBD | |
| 4537 } | |
| 4538 | |
| 4539 virtual void EndTesting( const Totals& ) { | |
| 4540 std::ostream& str = m_config.stream(); | |
| 4541 { | |
| 4542 XmlWriter xml( str ); | |
| 4543 | |
| 4544 if( m_statsForSuites.size() > 0 ) | |
| 4545 xml.startElement( "testsuites" ); | |
| 4546 | |
| 4547 std::vector<Stats>::const_iterator it = m_statsForSuites.begin(); | |
| 4548 std::vector<Stats>::const_iterator itEnd = m_statsForSuites.end(); | |
| 4549 | |
| 4550 for(; it != itEnd; ++it ) { | |
| 4551 XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); | |
| 4552 xml.writeAttribute( "name", it->m_name ); | |
| 4553 xml.writeAttribute( "errors", it->m_errorsCount ); | |
| 4554 xml.writeAttribute( "failures", it->m_failuresCount ); | |
| 4555 xml.writeAttribute( "tests", it->m_testsCount ); | |
| 4556 xml.writeAttribute( "hostname", "tbd" ); | |
| 4557 xml.writeAttribute( "time", "tbd" ); | |
| 4558 xml.writeAttribute( "timestamp", "tbd" ); | |
| 4559 | |
| 4560 OutputTestCases( xml, *it ); | |
| 4561 } | |
| 4562 | |
| 4563 xml.scopedElement( "system-out" ).writeText( trim( m_stdOut.str() ) ); | |
| 4564 xml.scopedElement( "system-err" ).writeText( trim( m_stdErr.str() ) ); | |
| 4565 } | |
| 4566 } | |
| 4567 | |
| 4568 void OutputTestCases( XmlWriter& xml, const Stats& stats ) { | |
| 4569 std::vector<TestCaseStats>::const_iterator it = stats.m_testCaseStats.begin(); | |
| 4570 std::vector<TestCaseStats>::const_iterator itEnd = stats.m_testCaseStats.end(); | |
| 4571 for(; it != itEnd; ++it ) { | |
| 4572 xml.writeBlankLine(); | |
| 4573 xml.writeComment( "Test case" ); | |
| 4574 | |
| 4575 XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); | |
| 4576 xml.writeAttribute( "classname", it->m_className ); | |
| 4577 xml.writeAttribute( "name", it->m_name ); | |
| 4578 xml.writeAttribute( "time", "tbd" ); | |
| 4579 | |
| 4580 OutputTestResult( xml, *it ); | |
| 4581 } | |
| 4582 } | |
| 4583 | |
| 4584 void OutputTestResult( XmlWriter& xml, const TestCaseStats& stats ) { | |
| 4585 std::vector<TestStats>::const_iterator it = stats.m_testStats.begin(); | |
| 4586 std::vector<TestStats>::const_iterator itEnd = stats.m_testStats.end(); | |
| 4587 for(; it != itEnd; ++it ) { | |
| 4588 if( it->m_element != "success" ) { | |
| 4589 XmlWriter::ScopedElement e = xml.scopedElement( it->m_element ); | |
| 4590 | |
| 4591 xml.writeAttribute( "message", it->m_message ); | |
| 4592 xml.writeAttribute( "type", it->m_resultType ); | |
| 4593 if( !it->m_content.empty() ) | |
| 4594 xml.writeText( it->m_content ); | |
| 4595 } | |
| 4596 } | |
| 4597 } | |
| 4598 | |
| 4599 private: | |
| 4600 const IReporterConfig& m_config; | |
| 4601 bool m_currentTestSuccess; | |
| 4602 | |
| 4603 Stats m_testSuiteStats; | |
| 4604 Stats* m_currentStats; | |
| 4605 std::vector<Stats> m_statsForSuites; | |
| 4606 std::ostringstream m_stdOut; | |
| 4607 std::ostringstream m_stdErr; | |
| 4608 }; | |
| 4609 | |
| 4610 } // end namespace Catch | |
| 4611 | |
| 4612 #include <fstream> | |
| 4613 #include <stdlib.h> | |
| 4614 #include <limits> | |
| 4615 | |
| 4616 namespace Catch { | |
| 4617 | |
| 4618 INTERNAL_CATCH_REGISTER_REPORTER( "basic", BasicReporter ) | |
| 4619 INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) | |
| 4620 INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) | |
| 4621 | |
| 4622 inline int Main( Config& config ) { | |
| 4623 | |
| 4624 // Handle list request | |
| 4625 if( config.listWhat() != List::None ) | |
| 4626 return List( config ); | |
| 4627 | |
| 4628 // Open output file, if specified | |
| 4629 std::ofstream ofs; | |
| 4630 if( !config.getFilename().empty() ) { | |
| 4631 ofs.open( config.getFilename().c_str() ); | |
| 4632 if( ofs.fail() ) { | |
| 4633 std::cerr << "Unable to open file: '" << config.getFilename() << "'" << std::endl; | |
| 4634 return (std::numeric_limits<int>::max)(); | |
| 4635 } | |
| 4636 config.setStreamBuf( ofs.rdbuf() ); | |
| 4637 } | |
| 4638 | |
| 4639 int result = 0; | |
| 4640 | |
| 4641 // Scope here for the Runner so it can use the context before it is cleaned-up | |
| 4642 { | |
| 4643 Runner runner( config ); | |
| 4644 | |
| 4645 // Run test specs specified on the command line - or default to all | |
| 4646 if( !config.testsSpecified() ) { | |
| 4647 config.getReporter()->StartGroup( "" ); | |
| 4648 runner.runAll(); | |
| 4649 config.getReporter()->EndGroup( "", runner.getTotals() ); | |
| 4650 } | |
| 4651 else { | |
| 4652 // !TBD We should get all the testcases upfront, report any missing, | |
| 4653 // then just run them | |
| 4654 std::vector<std::string>::const_iterator it = config.getTestSpecs().begin(); | |
| 4655 std::vector<std::string>::const_iterator itEnd = config.getTestSpecs().end(); | |
| 4656 for(; it != itEnd; ++it ) { | |
| 4657 Totals prevTotals = runner.getTotals(); | |
| 4658 config.getReporter()->StartGroup( *it ); | |
| 4659 if( runner.runMatching( *it ) == 0 ) { | |
| 4660 // Use reporter? | |
| 4661 // std::cerr << "\n[Unable to match any test cases with: " << *it << "]" << std::endl; | |
| 4662 } | |
| 4663 config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals ); | |
| 4664 } | |
| 4665 } | |
| 4666 result = static_cast<int>( runner.getTotals().assertions.failed ); | |
| 4667 } | |
| 4668 Catch::Context::cleanUp(); | |
| 4669 return result; | |
| 4670 } | |
| 4671 | |
| 4672 inline void showUsage( std::ostream& os ) { | |
| 4673 os << "\t-l, --list <tests | reporters> [xml]\n" | |
| 4674 << "\t-t, --test <testspec> [<testspec>...]\n" | |
| 4675 << "\t-r, --reporter <reporter name>\n" | |
| 4676 << "\t-o, --out <file name>|<%stream name>\n" | |
| 4677 << "\t-s, --success\n" | |
| 4678 << "\t-b, --break\n" | |
| 4679 << "\t-n, --name <name>\n" | |
| 4680 << "\t-a, --abort [#]\n\n" | |
| 4681 << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; | |
| 4682 } | |
| 4683 inline void showHelp( std::string exeName ) { | |
| 4684 std::string::size_type pos = exeName.find_last_of( "/\\" ); | |
| 4685 if( pos != std::string::npos ) { | |
| 4686 exeName = exeName.substr( pos+1 ); | |
| 4687 } | |
| 4688 | |
| 4689 std::cout << exeName << " is a CATCH host application. Options are as follows:\n\n"; | |
| 4690 showUsage( std::cout ); | |
| 4691 } | |
| 4692 | |
| 4693 inline int Main( int argc, char* const argv[], Config& config ) { | |
| 4694 | |
| 4695 parseIntoConfig( CommandParser( argc, argv ), config ); | |
| 4696 | |
| 4697 if( !config.getMessage().empty() ) { | |
| 4698 std::cerr << config.getMessage() << + "\n\nUsage: ...\n\n"; | |
| 4699 showUsage( std::cerr ); | |
| 4700 Catch::Context::cleanUp(); | |
| 4701 return (std::numeric_limits<int>::max)(); | |
| 4702 } | |
| 4703 | |
| 4704 // Handle help | |
| 4705 if( config.showHelp() ) { | |
| 4706 showHelp( argv[0] ); | |
| 4707 Catch::Context::cleanUp(); | |
| 4708 return 0; | |
| 4709 } | |
| 4710 return Main( config ); | |
| 4711 } | |
| 4712 | |
| 4713 inline int Main( int argc, char* const argv[] ) { | |
| 4714 Config config; | |
| 4715 // !TBD: This doesn't always work, for some reason | |
| 4716 // if( isDebuggerActive() ) | |
| 4717 // config.useStream( "debug" ); | |
| 4718 return Main( argc, argv, config ); | |
| 4719 } | |
| 4720 | |
| 4721 } // end namespace Catch | |
| 4722 | |
| 4723 #endif | |
| 4724 | |
| 4725 #ifdef CATCH_CONFIG_MAIN | |
| 4726 // #included from: internal/catch_default_main.hpp | |
| 4727 | |
| 4728 #ifndef __OBJC__ | |
| 4729 | |
| 4730 // Standard C/C++ main entry point | |
| 4731 int main (int argc, char * const argv[]) { | |
| 4732 return Catch::Main( argc, argv ); | |
| 4733 } | |
| 4734 | |
| 4735 #else // __OBJC__ | |
| 4736 | |
| 4737 // Objective-C entry point | |
| 4738 int main (int argc, char * const argv[]) { | |
| 4739 #if !CATCH_ARC_ENABLED | |
| 4740 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
| 4741 #endif | |
| 4742 | |
| 4743 Catch::registerTestMethods(); | |
| 4744 int result = Catch::Main( argc, (char* const*)argv ); | |
| 4745 | |
| 4746 #if !CATCH_ARC_ENABLED | |
| 4747 [pool drain]; | |
| 4748 #endif | |
| 4749 | |
| 4750 return result; | |
| 4751 } | |
| 4752 | |
| 4753 #endif // __OBJC__ | |
| 4754 | |
| 4755 #endif | |
| 4756 | |
| 4757 ////// | |
| 4758 | |
| 4759 #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, false, true, "REQUIRE" ) | |
| 4760 #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, true, "REQUIRE_FALSE" ) | |
| 4761 | |
| 4762 #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., true, "REQUIRE_THROWS" ) | |
| 4763 #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, true, "REQUIRE_THROWS_AS" ) | |
| 4764 #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, true, "REQUIRE_NOTHROW" ) | |
| 4765 | |
| 4766 #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, false, false, "CHECK" ) | |
| 4767 #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, false, "CHECK_FALSE" ) | |
| 4768 #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, false, false, "CHECKED_IF" ) | |
| 4769 #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, false, false, "CHECKED_ELSE" ) | |
| 4770 | |
| 4771 #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., false, "CHECK_THROWS" ) | |
| 4772 #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, false, "CHECK_THROWS_AS" ) | |
| 4773 #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, false, "CHECK_NOTHROW" ) | |
| 4774 | |
| 4775 #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, false, "CHECK_THAT" ) | |
| 4776 #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, true, "REQUIRE_THAT" ) | |
| 4777 | |
| 4778 #define INFO( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Info, false, "INFO" ) | |
| 4779 #define WARN( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Warning, false, "WARN" ) | |
| 4780 #define FAIL( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::ExplicitFailure, true, "FAIL" ) | |
| 4781 #define SCOPED_INFO( msg ) INTERNAL_CATCH_SCOPED_INFO( msg ) | |
| 4782 #define CAPTURE( msg ) INTERNAL_CATCH_MSG( #msg " := " << msg, Catch::ResultWas::Info, false, "CAPTURE" ) | |
| 4783 | |
| 4784 #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) | |
| 4785 | |
| 4786 #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) | |
| 4787 #define TEST_CASE_NORETURN( name, description ) INTERNAL_CATCH_TESTCASE_NORETURN( name, description ) | |
| 4788 #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "Anonymous test case" ) | |
| 4789 #define METHOD_AS_TEST_CASE( method, name, description ) CATCH_METHOD_AS_TEST_CASE( method, name, description ) | |
| 4790 | |
| 4791 #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) | |
| 4792 #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) | |
| 4793 | |
| 4794 #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) | |
| 4795 | |
| 4796 /////////////// | |
| 4797 // Still to be implemented | |
| 4798 #define CHECK_NOFAIL( expr ) // !TBD - reports violation, but doesn't fail Test | |
| 4799 | |
| 4800 using Catch::Detail::Approx; | |
| 4801 | |
| 4802 #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED | |
| 4803 |
