mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 04:07:10 +01:00 
			
		
		
		
	Reworked SectionTracker and moved into own header
This commit is contained in:
		
							
								
								
									
										145
									
								
								include/internal/catch_test_case_tracker.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								include/internal/catch_test_case_tracker.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | ||||
| /* | ||||
|  *  Created by Phil Nash on 23/7/2013 | ||||
|  *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED | ||||
|  | ||||
| #include <map> | ||||
| #include <string> | ||||
| #include <assert.h> | ||||
|  | ||||
| namespace Catch { | ||||
| namespace SectionTracking { | ||||
|  | ||||
|     class TrackedSection { | ||||
|  | ||||
|         typedef std::map<std::string, TrackedSection> TrackedSections; | ||||
|  | ||||
|     public: | ||||
|         enum RunState { | ||||
|             NotStarted, | ||||
|             Executing, | ||||
|             ExecutingChildren, | ||||
|             Completed | ||||
|         }; | ||||
|  | ||||
|         TrackedSection( std::string const& name, TrackedSection* parent ) | ||||
|         :   m_name( name ), m_runState( NotStarted ), m_parent( parent ) | ||||
|         {} | ||||
|  | ||||
|         RunState runState() const { return m_runState; } | ||||
|  | ||||
|         void addChild( std::string const& childName ) { | ||||
|             m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); | ||||
|         } | ||||
|         TrackedSection* getChild( std::string const& childName ) { | ||||
|             return &m_children.find( childName )->second; | ||||
|         } | ||||
|  | ||||
|         void enter() { | ||||
|             if( m_runState == NotStarted ) | ||||
|                 m_runState = Executing; | ||||
|         } | ||||
|         void leave() { | ||||
|             for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); | ||||
|                     it != itEnd; | ||||
|                     ++it ) | ||||
|                 if( it->second.runState() != Completed ) { | ||||
|                     m_runState = ExecutingChildren; | ||||
|                     return; | ||||
|                 } | ||||
|             m_runState = Completed; | ||||
|         } | ||||
|         TrackedSection* getParent() { | ||||
|             return m_parent; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         std::string m_name; | ||||
|         RunState m_runState; | ||||
|         TrackedSections m_children; | ||||
|         TrackedSection* m_parent; | ||||
|          | ||||
|     }; | ||||
|  | ||||
|     class SectionTracker { | ||||
|     public: | ||||
|         SectionTracker( TrackedSection& testCase ) | ||||
|         :   m_currentSection( &testCase ), | ||||
|             m_completedASectionThisRun( false ) | ||||
|         {} | ||||
|          | ||||
|         bool enterSection( std::string const& name ) { | ||||
|             if( m_completedASectionThisRun ) | ||||
|                 return false; | ||||
|             if( m_currentSection->runState() == TrackedSection::Executing ) { | ||||
|                 m_currentSection->addChild( name ); | ||||
|                 return false; | ||||
|             } | ||||
|             else { | ||||
|                 TrackedSection* child = m_currentSection->getChild( name ); | ||||
|                 if( child->runState() != TrackedSection::Completed ) { | ||||
|                     m_currentSection = child; | ||||
|                     m_currentSection->enter(); | ||||
|                     return true; | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void leaveSection() { | ||||
|             m_currentSection->leave(); | ||||
|             m_currentSection = m_currentSection->getParent(); | ||||
|             assert( m_currentSection != NULL ); | ||||
|             m_completedASectionThisRun = true; | ||||
|         } | ||||
|  | ||||
|  | ||||
|     private: | ||||
|         TrackedSection* m_currentSection; | ||||
|         bool m_completedASectionThisRun; | ||||
|     }; | ||||
|  | ||||
|     class TestCaseTracker { | ||||
|     public: | ||||
|  | ||||
|         TestCaseTracker( std::string const& testCaseName ) | ||||
|         :   m_testCase( testCaseName, NULL ), | ||||
|             sections( m_testCase ) | ||||
|         {} | ||||
|  | ||||
|         void enter() { | ||||
|             sections = SectionTracker( m_testCase ); | ||||
|             m_testCase.enter(); | ||||
|         } | ||||
|         void leave() { | ||||
|             m_testCase.leave(); | ||||
|         } | ||||
|  | ||||
|         bool enterSection( std::string const& name ) { | ||||
|             return sections.enterSection( name ); | ||||
|         } | ||||
|         void leaveSection() { | ||||
|             sections.leaveSection(); | ||||
|         } | ||||
|          | ||||
|         bool isCompleted() const { | ||||
|             return m_testCase.runState() == TrackedSection::Completed; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         TrackedSection m_testCase; | ||||
|         SectionTracker sections; | ||||
|     }; | ||||
|  | ||||
| } // namespace SectionTracking | ||||
|  | ||||
| using SectionTracking::TestCaseTracker; | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED | ||||
| @@ -10,256 +10,148 @@ | ||||
| #pragma clang diagnostic ignored "-Wpadded" | ||||
| #endif | ||||
|  | ||||
| #include "internal/catch_test_case_tracker.hpp" | ||||
|  | ||||
| #include "catch.hpp" | ||||
|  | ||||
| using namespace Catch; | ||||
|  | ||||
| class TrackedSection; | ||||
|  | ||||
| typedef std::map<std::string, TrackedSection> TrackedSections; | ||||
|  | ||||
| class TrackedSection { | ||||
| public: | ||||
|     enum RunState { | ||||
|         NotStarted, | ||||
|         Executing, | ||||
|         ExecutingChildren, | ||||
|         Completed | ||||
|     }; | ||||
|  | ||||
|     TrackedSection( std::string const& name, TrackedSection* parent ) | ||||
|     :   m_name( name ), m_runState( NotStarted ), m_parent( parent ) | ||||
|     {} | ||||
|  | ||||
|     RunState runState() const { return m_runState; } | ||||
|  | ||||
|     void addChild( std::string const& childName ) { | ||||
|         m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); | ||||
|     } | ||||
|     TrackedSection* getChild( std::string const& childName ) { | ||||
|         return &m_children.find( childName )->second; | ||||
|     } | ||||
|  | ||||
|     void enter() { | ||||
|         if( m_runState == NotStarted ) | ||||
|             m_runState = Executing; | ||||
|     } | ||||
|     void leave() { | ||||
|         for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); | ||||
|                 it != itEnd; | ||||
|                 ++it ) | ||||
|             if( it->second.runState() != Completed ) { | ||||
|                 m_runState = ExecutingChildren; | ||||
|                 return; | ||||
|             } | ||||
|         m_runState = Completed; | ||||
|     } | ||||
|     TrackedSection* getParent() { | ||||
|         return m_parent; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     std::string m_name; | ||||
|     RunState m_runState; | ||||
|     TrackedSections m_children; | ||||
|     TrackedSection* m_parent; | ||||
|      | ||||
| }; | ||||
|  | ||||
| class SectionTracker { | ||||
| public: | ||||
|     SectionTracker( std::string const& testCaseName ) | ||||
|     :   m_testCase( testCaseName, NULL ), | ||||
|         m_currentSection( NULL ), | ||||
|         m_completedASectionThisRun( false ) | ||||
|     {} | ||||
|      | ||||
|     void enter() { | ||||
|         m_completedASectionThisRun = false; | ||||
|         m_currentSection = &m_testCase; | ||||
|         m_testCase.enter(); | ||||
|     } | ||||
|     void leave() { | ||||
|         m_testCase.leave(); | ||||
|     } | ||||
|  | ||||
|     bool enterSection( std::string const& name ) { | ||||
|         if( m_completedASectionThisRun ) | ||||
|             return false; | ||||
|         if( m_currentSection->runState() == TrackedSection::Executing ) { | ||||
|             m_currentSection->addChild( name ); | ||||
|             return false; | ||||
|         } | ||||
|         else { | ||||
|             TrackedSection* child = m_currentSection->getChild( name ); | ||||
|             if( child->runState() != TrackedSection::Completed ) { | ||||
|                 m_currentSection = child; | ||||
|                 m_currentSection->enter(); | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void leaveSection() { | ||||
|         m_currentSection->leave(); | ||||
|         m_currentSection = m_currentSection->getParent(); | ||||
|         assert( m_currentSection != NULL ); | ||||
|         m_completedASectionThisRun = true; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     bool isCompleted() const { | ||||
|         return m_testCase.runState() == TrackedSection::Completed; | ||||
|     } | ||||
|     bool hasCompletedASectionThisRun() const { | ||||
|         return m_completedASectionThisRun; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     TrackedSection m_testCase; | ||||
|     TrackedSection* m_currentSection; | ||||
|     bool m_completedASectionThisRun; | ||||
| }; | ||||
|  | ||||
| TEST_CASE( "sections" ) { | ||||
| TEST_CASE( "section tracking" ) { | ||||
|  | ||||
|     using namespace Catch; | ||||
|     SectionTracker sectionTracker( "test case" ); | ||||
|     TestCaseTracker testCaseTracker( "test case" ); | ||||
|  | ||||
|     const std::string section1Name = "section 1"; | ||||
|     const std::string section2Name = "section 2"; | ||||
|  | ||||
|     CHECK_FALSE( sectionTracker.isCompleted() ); | ||||
|     CHECK_FALSE( testCaseTracker.isCompleted() ); | ||||
|  | ||||
|     SECTION( "test case with no sections" ) { | ||||
|  | ||||
|         sectionTracker.enter(); | ||||
|         CHECK_FALSE( sectionTracker.isCompleted() ); | ||||
|         testCaseTracker.enter(); | ||||
|         CHECK_FALSE( testCaseTracker.isCompleted() ); | ||||
|  | ||||
|         sectionTracker.leave(); | ||||
|         CHECK( sectionTracker.isCompleted() ); | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK( testCaseTracker.isCompleted() ); | ||||
|     } | ||||
|  | ||||
|     SECTION( "test case with one section" ) { | ||||
|  | ||||
|         // Enter test case | ||||
|         sectionTracker.enter(); | ||||
|         testCaseTracker.enter(); | ||||
|  | ||||
|         // Enter section? - no, not yet | ||||
|         CHECK_FALSE( sectionTracker.enterSection( section1Name ) ); | ||||
|         CHECK_FALSE( sectionTracker.isCompleted() ); | ||||
|         CHECK_FALSE( testCaseTracker.enterSection( section1Name ) ); | ||||
|         CHECK_FALSE( testCaseTracker.isCompleted() ); | ||||
|  | ||||
|         // Leave test case - incomplete (still need to visit section) | ||||
|         sectionTracker.leave(); | ||||
|         CHECK_FALSE( sectionTracker.isCompleted() ); | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK_FALSE( testCaseTracker.isCompleted() ); | ||||
|  | ||||
|         // ... | ||||
|  | ||||
|         // Enter test case again | ||||
|         sectionTracker.enter(); | ||||
|         testCaseTracker.enter(); | ||||
|  | ||||
|         // Enter section? - yes | ||||
|         CHECK( sectionTracker.enterSection( section1Name ) ); | ||||
|         CHECK( testCaseTracker.enterSection( section1Name ) ); | ||||
|  | ||||
|         // Leave section and test case - now complete | ||||
|         sectionTracker.leaveSection(); | ||||
|         sectionTracker.leave(); | ||||
|         CHECK( sectionTracker.isCompleted() ); | ||||
|         testCaseTracker.leaveSection(); | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK( testCaseTracker.isCompleted() ); | ||||
|     } | ||||
|  | ||||
|     SECTION( "test case with two consecutive sections" ) { | ||||
|  | ||||
|         // Enter test case | ||||
|         sectionTracker.enter(); | ||||
|         testCaseTracker.enter(); | ||||
|  | ||||
|         // Enter section 1? - no, not yet | ||||
|         CHECK_FALSE( sectionTracker.enterSection( section1Name ) ); | ||||
|         CHECK_FALSE( testCaseTracker.enterSection( section1Name ) ); | ||||
|  | ||||
|         // Enter section 2? - no, not yet | ||||
|         CHECK_FALSE( sectionTracker.enterSection( section2Name ) ); | ||||
|         CHECK_FALSE( testCaseTracker.enterSection( section2Name ) ); | ||||
|  | ||||
|         // Leave test case - incomplete (still need to visit sections) | ||||
|         sectionTracker.leave(); | ||||
|         CHECK_FALSE( sectionTracker.isCompleted() ); | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK_FALSE( testCaseTracker.isCompleted() ); | ||||
|  | ||||
|         // ... | ||||
|  | ||||
|         // Enter test case again | ||||
|         sectionTracker.enter(); | ||||
|         testCaseTracker.enter(); | ||||
|  | ||||
|         // Enter section 1? - yes | ||||
|         CHECK( sectionTracker.enterSection( section1Name ) ); | ||||
|         sectionTracker.leaveSection(); | ||||
|         CHECK( testCaseTracker.enterSection( section1Name ) ); | ||||
|         testCaseTracker.leaveSection(); | ||||
|  | ||||
|         // Enter section 2? - no, not yet | ||||
|         CHECK_FALSE( sectionTracker.enterSection( section2Name ) ); | ||||
|         CHECK_FALSE( testCaseTracker.enterSection( section2Name ) ); | ||||
|  | ||||
|         // Leave test case - incomplete (still need to visit section 2) | ||||
|         sectionTracker.leave(); | ||||
|         CHECK_FALSE( sectionTracker.isCompleted() ); | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK_FALSE( testCaseTracker.isCompleted() ); | ||||
|  | ||||
|         // ... | ||||
|  | ||||
|         // Enter test case again | ||||
|         sectionTracker.enter(); | ||||
|         testCaseTracker.enter(); | ||||
|  | ||||
|         // Enter section 1? - no, already done now | ||||
|         CHECK_FALSE( sectionTracker.enterSection( section1Name ) ); | ||||
|         CHECK_FALSE( testCaseTracker.enterSection( section1Name ) ); | ||||
|  | ||||
|         // Enter section 2? - yes - finally | ||||
|         CHECK( sectionTracker.enterSection( section2Name ) ); | ||||
|         sectionTracker.leaveSection(); | ||||
|         CHECK( testCaseTracker.enterSection( section2Name ) ); | ||||
|         testCaseTracker.leaveSection(); | ||||
|  | ||||
|         // Leave test case - now complete | ||||
|         sectionTracker.leave(); | ||||
|         CHECK( sectionTracker.isCompleted() );         | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK( testCaseTracker.isCompleted() );         | ||||
|     } | ||||
|  | ||||
|     SECTION( "test case with one section within another" ) { | ||||
|  | ||||
|         // Enter test case | ||||
|         sectionTracker.enter(); | ||||
|         testCaseTracker.enter(); | ||||
|  | ||||
|         // Enter section 1? - no, not yet | ||||
|         CHECK_FALSE( sectionTracker.enterSection( section1Name ) ); | ||||
|         CHECK_FALSE( testCaseTracker.enterSection( section1Name ) ); | ||||
|  | ||||
|         // Leave test case - incomplete (still need to visit sections) | ||||
|         sectionTracker.leave(); | ||||
|         CHECK_FALSE( sectionTracker.isCompleted() ); | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK_FALSE( testCaseTracker.isCompleted() ); | ||||
|  | ||||
|         // ... | ||||
|  | ||||
|         // Enter test case again | ||||
|         sectionTracker.enter(); | ||||
|         testCaseTracker.enter(); | ||||
|  | ||||
|         // Enter section 1? - yes | ||||
|         CHECK( sectionTracker.enterSection( section1Name ) ); | ||||
|         CHECK( testCaseTracker.enterSection( section1Name ) ); | ||||
|  | ||||
|         // Enter section 2? - no, not yet | ||||
|         CHECK_FALSE( sectionTracker.enterSection( section2Name ) ); | ||||
|         CHECK_FALSE( testCaseTracker.enterSection( section2Name ) ); | ||||
|  | ||||
|         sectionTracker.leaveSection(); // section 1 - incomplete (section 2) | ||||
|         testCaseTracker.leaveSection(); // section 1 - incomplete (section 2) | ||||
|  | ||||
|         // Leave test case - incomplete | ||||
|         sectionTracker.leave(); | ||||
|         CHECK_FALSE( sectionTracker.isCompleted() ); | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK_FALSE( testCaseTracker.isCompleted() ); | ||||
|  | ||||
|         // ... | ||||
|  | ||||
|         // Enter test case again | ||||
|         sectionTracker.enter(); | ||||
|         testCaseTracker.enter(); | ||||
|  | ||||
|         // Enter section 1? - yes - so we can execute section 2 | ||||
|         CHECK( sectionTracker.enterSection( section1Name ) ); | ||||
|         CHECK( testCaseTracker.enterSection( section1Name ) ); | ||||
|  | ||||
|         // Enter section 2? - yes - finally | ||||
|         CHECK( sectionTracker.enterSection( section2Name ) ); | ||||
|         sectionTracker.leaveSection(); // section 2 | ||||
|         sectionTracker.leaveSection(); // section 1 | ||||
|         CHECK( testCaseTracker.enterSection( section2Name ) ); | ||||
|         testCaseTracker.leaveSection(); // section 2 | ||||
|         testCaseTracker.leaveSection(); // section 1 | ||||
|  | ||||
|         // Leave test case - now complete | ||||
|         sectionTracker.leave(); | ||||
|         CHECK( sectionTracker.isCompleted() );         | ||||
|         testCaseTracker.leave(); | ||||
|         CHECK( testCaseTracker.isCompleted() );         | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -69,6 +69,7 @@ | ||||
| 		26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = "<group>"; }; | ||||
| 		26847E5D16BBADB40043B9C1 /* catch_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_message.cpp; path = ../../../SelfTest/SurrogateCpps/catch_message.cpp; sourceTree = "<group>"; }; | ||||
| 		26948284179A9AB900ED166E /* SectionTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SectionTrackerTests.cpp; path = ../../../SelfTest/SectionTrackerTests.cpp; sourceTree = "<group>"; }; | ||||
| 		26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_tracker.hpp; sourceTree = "<group>"; }; | ||||
| 		2694A1FB16A0000E004816E3 /* catch_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catch_text.cpp; sourceTree = "<group>"; }; | ||||
| 		26C5F3EC17514B970056FB3C /* clara.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = clara.h; path = ../../../../include/internal/clara.h; sourceTree = "<group>"; }; | ||||
| 		26DACF2F17206D3400A21326 /* catch_text.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_text.h; sourceTree = "<group>"; }; | ||||
| @@ -378,6 +379,7 @@ | ||||
| 				4AB77CB81553BB3800857BF0 /* catch_running_test.hpp */, | ||||
| 				4A084F1D15DAD15F0027E631 /* catch_test_spec.h */, | ||||
| 				4A8E4DCC160A344100194CBD /* catch_tags.hpp */, | ||||
| 				26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */, | ||||
| 			); | ||||
| 			name = "Test execution"; | ||||
| 			sourceTree = "<group>"; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash