From 6a484fdb028fec77e54c657dfe08a5007ecca91e Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 23 Jul 2013 18:48:36 +0100 Subject: [PATCH] Reworked SectionTracker and moved into own header --- include/internal/catch_test_case_tracker.hpp | 145 ++++++++++++ projects/SelfTest/SectionTrackerTests.cpp | 214 +++++------------- .../CatchSelfTest.xcodeproj/project.pbxproj | 2 + 3 files changed, 200 insertions(+), 161 deletions(-) create mode 100644 include/internal/catch_test_case_tracker.hpp diff --git a/include/internal/catch_test_case_tracker.hpp b/include/internal/catch_test_case_tracker.hpp new file mode 100644 index 00000000..4ca49950 --- /dev/null +++ b/include/internal/catch_test_case_tracker.hpp @@ -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 +#include +#include + +namespace Catch { +namespace SectionTracking { + + class TrackedSection { + + typedef std::map 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 diff --git a/projects/SelfTest/SectionTrackerTests.cpp b/projects/SelfTest/SectionTrackerTests.cpp index e949fc04..15e5f5d5 100644 --- a/projects/SelfTest/SectionTrackerTests.cpp +++ b/projects/SelfTest/SectionTrackerTests.cpp @@ -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 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() ); } } diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index b58de3bb..791c2cea 100644 --- a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -69,6 +69,7 @@ 26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = ""; }; 26847E5D16BBADB40043B9C1 /* catch_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_message.cpp; path = ../../../SelfTest/SurrogateCpps/catch_message.cpp; sourceTree = ""; }; 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SectionTrackerTests.cpp; path = ../../../SelfTest/SectionTrackerTests.cpp; sourceTree = ""; }; + 26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_tracker.hpp; sourceTree = ""; }; 2694A1FB16A0000E004816E3 /* catch_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catch_text.cpp; sourceTree = ""; }; 26C5F3EC17514B970056FB3C /* clara.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = clara.h; path = ../../../../include/internal/clara.h; sourceTree = ""; }; 26DACF2F17206D3400A21326 /* catch_text.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_text.h; sourceTree = ""; }; @@ -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 = "";