comparison include/catch.hpp @ 220:f0f800b95765

switched to Catch for the tests
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 21 Jun 2012 23:50:51 -0400
parents
children c6f497291fd8
comparison
equal deleted inserted replaced
219:841a1714f702 220:f0f800b95765
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() << "&lt;";
4251 break;
4252 case '&':
4253 stream() << "&amp;";
4254 break;
4255 case '\"':
4256 stream() << "&quot;";
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