mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Added IndexTracker and got it working with a single generator
- made some simplifications to state machine
This commit is contained in:
		| @@ -23,8 +23,10 @@ namespace Catch | ||||
|     struct IPartTracker : SharedImpl<> { | ||||
|         virtual ~IPartTracker() {} | ||||
|          | ||||
|         // queries | ||||
|         // static queries | ||||
|         virtual std::string name() const = 0; | ||||
|          | ||||
|         // dynamic queries | ||||
|         virtual bool hasStarted() const = 0; // true even if ended | ||||
|         virtual bool hasEnded() const = 0; | ||||
|         virtual bool isSuccessfullyCompleted() const = 0; | ||||
| @@ -35,12 +37,11 @@ namespace Catch | ||||
|         // actions | ||||
|         virtual void close() = 0; | ||||
|         virtual void fail() = 0; | ||||
|         virtual void markAsNeedingAnotherRun() =0; | ||||
|  | ||||
|         virtual void addChild( Ptr<IPartTracker> const& child ) = 0; | ||||
|         virtual IPartTracker* findChild( std::string const& name ) = 0; | ||||
|         virtual void openChild() = 0; | ||||
|         virtual void childFailed() = 0; | ||||
|      | ||||
|     }; | ||||
|      | ||||
|  | ||||
| @@ -103,13 +104,14 @@ namespace Catch | ||||
|     }; | ||||
|      | ||||
|     class PartTrackerBase : public IPartTracker { | ||||
|     protected: | ||||
|         enum RunState { | ||||
|             NotStarted, | ||||
|             Executing, | ||||
|             ExecutingChildren, | ||||
|             NeedsAnotherRun, | ||||
|             CompletedSuccessfully, | ||||
|             Failed, | ||||
|             ChildFailed | ||||
|             Failed | ||||
|         }; | ||||
|         class TrackerHasName { | ||||
|             std::string m_name; | ||||
| @@ -146,7 +148,7 @@ namespace Catch | ||||
|             return m_runState != NotStarted; | ||||
|         } | ||||
|         virtual bool isOpen() const CATCH_OVERRIDE { | ||||
|             return m_runState == Executing || m_runState == ExecutingChildren; | ||||
|             return hasStarted() && !hasEnded(); | ||||
|         } | ||||
|          | ||||
|          | ||||
| @@ -158,8 +160,8 @@ namespace Catch | ||||
|         virtual IPartTracker* findChild( std::string const& name ) CATCH_OVERRIDE { | ||||
|             Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); | ||||
|             return( it != m_children.end() ) | ||||
|             ? it->get() | ||||
|             : CATCH_NULL; | ||||
|                 ? it->get() | ||||
|                 : CATCH_NULL; | ||||
|         } | ||||
|         virtual IPartTracker& parent() CATCH_OVERRIDE { | ||||
|             assert( m_parent ); // Should always be non-null except for root | ||||
| @@ -173,12 +175,6 @@ namespace Catch | ||||
|                     m_parent->openChild(); | ||||
|             } | ||||
|         } | ||||
|         virtual void childFailed() CATCH_OVERRIDE { | ||||
|             assert( m_runState == ExecutingChildren ); | ||||
|             m_runState = ChildFailed; | ||||
|             if( m_parent ) | ||||
|                 m_parent->childFailed(); | ||||
|         } | ||||
|         void open() { | ||||
|             m_runState = Executing; | ||||
|             moveToThis(); | ||||
| @@ -187,16 +183,25 @@ namespace Catch | ||||
|         } | ||||
|          | ||||
|         virtual void close() CATCH_OVERRIDE { | ||||
|              | ||||
|             // Close any still open children (e.g. generators) | ||||
|             while( &m_ctx.currentPart() != this ) | ||||
|                 m_ctx.currentPart().close(); | ||||
|  | ||||
|             switch( m_runState ) { | ||||
|                 case CompletedSuccessfully: | ||||
|                 case Failed: | ||||
|                     return; | ||||
|  | ||||
|                 case Executing: | ||||
|                     m_runState = CompletedSuccessfully; | ||||
|                     break; | ||||
|                 case ExecutingChildren: | ||||
|                     if( !hasUnstartedChildren() ) | ||||
|                     if( m_children.empty() || m_children.back()->hasEnded() ) | ||||
|                         m_runState = CompletedSuccessfully; | ||||
|                     break; | ||||
|                 case ChildFailed: | ||||
|                     m_runState = ExecutingChildren; | ||||
|                 case NeedsAnotherRun: | ||||
|                     m_runState = Executing; | ||||
|                     break; | ||||
|                 default: | ||||
|                     throw std::logic_error( "Unexpected state" ); | ||||
| @@ -207,21 +212,21 @@ namespace Catch | ||||
|         virtual void fail() CATCH_OVERRIDE { | ||||
|             m_runState = Failed; | ||||
|             if( m_parent ) | ||||
|                 m_parent->childFailed(); | ||||
|                 m_parent->markAsNeedingAnotherRun(); | ||||
|             moveToParent(); | ||||
|             m_ctx.completeCycle(); | ||||
|         } | ||||
|         virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { | ||||
|             m_runState = NeedsAnotherRun; | ||||
|         } | ||||
|     private: | ||||
|         void moveToParent() { | ||||
|             assert( m_parent ); | ||||
|             m_ctx.setCurrentPart( m_parent ); | ||||
|         } | ||||
|         void moveToThis() { | ||||
|             m_ctx.setCurrentPart( this ); | ||||
|         } | ||||
|  | ||||
|         bool hasUnstartedChildren() const { | ||||
|             return !m_children.empty() && !m_children.back()->hasStarted(); | ||||
|         } | ||||
|     }; | ||||
|      | ||||
|  | ||||
| @@ -245,12 +250,60 @@ namespace Catch | ||||
|                 currentPart.addChild( section ); | ||||
|             } | ||||
|             if( !ctx.completedCycle() && !section->hasEnded() ) { | ||||
|                  | ||||
|                 section->open(); | ||||
|             } | ||||
|             return *section; | ||||
|         } | ||||
|     }; | ||||
|      | ||||
|     class IndexTracker : public PartTrackerBase { | ||||
|         int m_size; | ||||
|         int m_index; | ||||
|     public: | ||||
|         IndexTracker( std::string const& name, TrackerContext& ctx, IPartTracker* parent, int size ) | ||||
|         :   PartTrackerBase( name, ctx, parent ), | ||||
|             m_size( size ), | ||||
|             m_index( -1 ) | ||||
|         {} | ||||
|          | ||||
|         static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { | ||||
|             IndexTracker* tracker = CATCH_NULL; | ||||
|              | ||||
|             IPartTracker& currentPart = ctx.currentPart(); | ||||
|             if( IPartTracker* part = currentPart.findChild( name ) ) { | ||||
|                 tracker = dynamic_cast<IndexTracker*>( part ); | ||||
|                 assert( tracker ); | ||||
|             } | ||||
|             else { | ||||
|                 tracker = new IndexTracker( name, ctx, ¤tPart, size ); | ||||
|                 currentPart.addChild( tracker ); | ||||
|             } | ||||
|              | ||||
|             if( !ctx.completedCycle() && !tracker->hasEnded() ) { | ||||
|                 if( tracker->m_runState != ExecutingChildren ) | ||||
|                     tracker->moveNext(); | ||||
|                 tracker->open(); | ||||
|             } | ||||
|              | ||||
|             return *tracker; | ||||
|         } | ||||
|          | ||||
|         int index() const { return m_index; } | ||||
|          | ||||
|         void moveNext() { | ||||
|             m_index++; | ||||
|             m_children.clear(); | ||||
|         } | ||||
|          | ||||
|         virtual void close() CATCH_OVERRIDE { | ||||
|             PartTrackerBase::close(); | ||||
|             if( m_runState == CompletedSuccessfully ) | ||||
|                 if( m_index < m_size-1 ) | ||||
|                     m_runState = Executing; | ||||
|         } | ||||
|     }; | ||||
|      | ||||
|     IPartTracker& TrackerContext::startRun() { | ||||
|         m_rootPart = new SectionTracker( "{root}", *this, CATCH_NULL ); | ||||
|         m_currentPart = CATCH_NULL; | ||||
| @@ -302,9 +355,8 @@ TEST_CASE( "PartTracker" ) { | ||||
|         REQUIRE( testCase.hasEnded() == false ); | ||||
|  | ||||
|         testCase.close(); | ||||
|         REQUIRE( testCase.isSuccessfullyCompleted() == true ); | ||||
|          | ||||
|         REQUIRE( ctx.completedCycle() == true ); | ||||
|         REQUIRE( testCase.isSuccessfullyCompleted() == true ); | ||||
|     } | ||||
|      | ||||
|     SECTION( "fail one section" ) { | ||||
| @@ -324,8 +376,8 @@ TEST_CASE( "PartTracker" ) { | ||||
|             REQUIRE( testCase2.isSuccessfullyCompleted() == false ); | ||||
|              | ||||
|             IPartTracker& s1b = SectionTracker::acquire( ctx, "S1" ); | ||||
|             REQUIRE( s1b.isSuccessfullyCompleted() == false ); | ||||
|  | ||||
|             REQUIRE( s1b.isOpen() == false ); | ||||
|              | ||||
|             testCase2.close(); | ||||
|             REQUIRE( ctx.completedCycle() == true ); | ||||
|             REQUIRE( testCase.isSuccessfullyCompleted() == true ); | ||||
| @@ -414,7 +466,88 @@ TEST_CASE( "PartTracker" ) { | ||||
|          | ||||
|         testCase.close(); | ||||
|         REQUIRE( testCase.isSuccessfullyCompleted() == true ); | ||||
|          | ||||
|     } | ||||
|      | ||||
|     SECTION( "start a generator" ) { | ||||
|         IndexTracker& g1 = IndexTracker::acquire( ctx, "G1", 2 ); | ||||
|         REQUIRE( g1.isOpen() == true ); | ||||
|         REQUIRE( g1.index() == 0 ); | ||||
|  | ||||
|         REQUIRE( g1.isSuccessfullyCompleted() == false ); | ||||
|         REQUIRE( s1.isSuccessfullyCompleted() == false ); | ||||
|  | ||||
|         SECTION( "close outer section" ) | ||||
|         { | ||||
|             s1.close(); | ||||
|             REQUIRE( s1.isSuccessfullyCompleted() == false ); | ||||
|             testCase.close(); | ||||
|             REQUIRE( testCase.isSuccessfullyCompleted() == false ); | ||||
|  | ||||
|             SECTION( "Re-enter for second generation" ) { | ||||
|                 ctx.startCycle(); | ||||
|                 IPartTracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" ); | ||||
|                 REQUIRE( testCase2.isOpen() == true ); | ||||
|                  | ||||
|                 IPartTracker& s1b = SectionTracker::acquire( ctx, "S1" ); | ||||
|                 REQUIRE( s1b.isOpen() == true ); | ||||
|                  | ||||
|                  | ||||
|                 IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 ); | ||||
|                 REQUIRE( g1b.isOpen() == true ); | ||||
|                 REQUIRE( g1b.index() == 1 ); | ||||
|                  | ||||
|                 REQUIRE( s1.isSuccessfullyCompleted() == false ); | ||||
|                  | ||||
|                 s1b.close(); | ||||
|                 REQUIRE( s1b.isSuccessfullyCompleted() == true ); | ||||
|                 REQUIRE( g1b.isSuccessfullyCompleted() == true ); | ||||
|                 testCase2.close(); | ||||
|                 REQUIRE( testCase2.isSuccessfullyCompleted() == true ); | ||||
|             } | ||||
|         } | ||||
|         SECTION( "Start a new inner section" ) { | ||||
|             IPartTracker& s2 = SectionTracker::acquire( ctx, "S2" ); | ||||
|             REQUIRE( s2.isOpen() == true ); | ||||
|  | ||||
|             s2.close(); | ||||
|             REQUIRE( s2.isSuccessfullyCompleted() == true ); | ||||
|  | ||||
|             s1.close(); | ||||
|             REQUIRE( s1.isSuccessfullyCompleted() == false ); | ||||
|  | ||||
|             testCase.close(); | ||||
|             REQUIRE( testCase.isSuccessfullyCompleted() == false ); | ||||
|              | ||||
|             SECTION( "Re-enter for second generation" ) { | ||||
|                 ctx.startCycle(); | ||||
|                 IPartTracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" ); | ||||
|                 REQUIRE( testCase2.isSuccessfullyCompleted() == false ); | ||||
|                  | ||||
|                 IPartTracker& s1b = SectionTracker::acquire( ctx, "S1" ); | ||||
|                 REQUIRE( s1b.isSuccessfullyCompleted() == false ); | ||||
|                  | ||||
|                 // generator - next value | ||||
|                 IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 ); | ||||
|                 REQUIRE( g1b.isOpen() == true ); | ||||
|                 REQUIRE( g1b.index() == 1 ); | ||||
|                  | ||||
|                 // inner section again | ||||
|                 IPartTracker& s2b = SectionTracker::acquire( ctx, "S2" ); | ||||
|                 REQUIRE( s2b.isOpen() == true ); | ||||
|                  | ||||
|                 s2b.close(); | ||||
|                 REQUIRE( s2b.isSuccessfullyCompleted() == true ); | ||||
|                  | ||||
|                 s1b.close(); | ||||
|                 REQUIRE( s1b.isSuccessfullyCompleted() == true ); | ||||
|                 REQUIRE( g1b.isSuccessfullyCompleted() == true ); | ||||
|                  | ||||
|                 testCase2.close(); | ||||
|                 REQUIRE( testCase2.isSuccessfullyCompleted() == true ); | ||||
|             } | ||||
|         } | ||||
|         // !TBD" | ||||
|         //   nested generator | ||||
|         //   two sections within a generator | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash