From a976c07b8daa4b4310103841d14958af607b3621 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Sat, 5 May 2012 19:32:52 +0100 Subject: [PATCH] Fixed section ordering issue If a branch section completes without running any inner sections it will no run subsequent sections (until the next isolated run). --- include/internal/catch_runner_impl.hpp | 232 +----------------- include/internal/catch_running_test.hpp | 150 +++++++++++ include/internal/catch_section_info.hpp | 142 +++++++++++ .../catch_test_case_registry_impl.hpp | 1 - projects/SelfTest/MiscTests.cpp | 47 ++-- projects/SelfTest/catch_self_test.hpp | 44 +++- .../CatchSelfTest.xcodeproj/project.pbxproj | 4 + 7 files changed, 356 insertions(+), 264 deletions(-) create mode 100644 include/internal/catch_running_test.hpp create mode 100644 include/internal/catch_section_info.hpp diff --git a/include/internal/catch_runner_impl.hpp b/include/internal/catch_runner_impl.hpp index 7267f44a..86d01df7 100644 --- a/include/internal/catch_runner_impl.hpp +++ b/include/internal/catch_runner_impl.hpp @@ -19,6 +19,7 @@ #include "catch_test_case_info.hpp" #include "catch_capture.hpp" #include "catch_totals.hpp" +#include "catch_running_test.hpp" #include #include @@ -57,237 +58,6 @@ namespace Catch std::string& m_targetString; }; - - /////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - class SectionInfo - { - public: - enum Status - { - Root, - Unknown, - NonLeaf, - TestedLeaf - }; - - /////////////////////////////////////////////////////////////////////// - SectionInfo - ( - SectionInfo* parent - ) - : m_status( Unknown ), - m_parent( parent ) - { - } - - /////////////////////////////////////////////////////////////////////// - SectionInfo - () - : m_status( Root ), - m_parent( NULL ) - { - } - - /////////////////////////////////////////////////////////////////////// - ~SectionInfo - () - { - deleteAllValues( m_subSections ); - } - - /////////////////////////////////////////////////////////////////////// - bool shouldRun - () - const - { - return m_status != TestedLeaf; - } - - /////////////////////////////////////////////////////////////////////// - bool ran - () - { - if( m_status != NonLeaf ) - { - m_status = TestedLeaf; - return true; - } - return false; - } - - /////////////////////////////////////////////////////////////////////// - SectionInfo* findSubSection - ( - const std::string& name - ) - { - std::map::const_iterator it = m_subSections.find( name ); - return it != m_subSections.end() - ? it->second - : NULL; - } - - /////////////////////////////////////////////////////////////////////// - SectionInfo* addSubSection - ( - const std::string& name - ) - { - SectionInfo* subSection = new SectionInfo( this ); - m_subSections.insert( std::make_pair( name, subSection ) ); - m_status = NonLeaf; - return subSection; - } - - /////////////////////////////////////////////////////////////////////// - SectionInfo* getParent - () - { - return m_parent; - } - - /////////////////////////////////////////////////////////////////////// - bool hasUntestedSections - () - const - { - if( m_status == Unknown ) - return true; - - std::map::const_iterator it = m_subSections.begin(); - std::map::const_iterator itEnd = m_subSections.end(); - for(; it != itEnd; ++it ) - { - if( it->second->hasUntestedSections() ) - return true; - } - return false; - } - - private: - Status m_status; - std::map m_subSections; - SectionInfo* m_parent; - }; - - /////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - - class RunningTest - { - enum RunStatus - { - NothingRun, - EncounteredASection, - RanAtLeastOneSection, - RanToCompletionWithSections, - RanToCompletionWithNoSections - }; - - public: - /////////////////////////////////////////////////////////////////////// - explicit RunningTest - ( - const TestCaseInfo* info = NULL - ) - : m_info( info ), - m_runStatus( RanAtLeastOneSection ), - m_currentSection( &m_rootSection ), - m_changed( false ) - { - } - - /////////////////////////////////////////////////////////////////////// - bool wasSectionSeen - () - const - { - return m_runStatus == RanAtLeastOneSection || - m_runStatus == RanToCompletionWithSections; - } - - /////////////////////////////////////////////////////////////////////// - void reset - () - { - m_runStatus = NothingRun; - m_changed = false; - } - - /////////////////////////////////////////////////////////////////////// - void ranToCompletion - () - { - m_runStatus = m_runStatus == RanAtLeastOneSection || - m_runStatus == EncounteredASection - ? RanToCompletionWithSections - : RanToCompletionWithNoSections; - } - - /////////////////////////////////////////////////////////////////////// - bool addSection - ( - const std::string& name - ) - { - if( m_runStatus == NothingRun ) - m_runStatus = EncounteredASection; - - SectionInfo* thisSection = m_currentSection->findSubSection( name ); - if( !thisSection ) - { - thisSection = m_currentSection->addSubSection( name ); - m_changed = true; - } - - if( !wasSectionSeen() && thisSection->shouldRun() ) - { - m_currentSection = thisSection; - return true; - } - return false; - } - - /////////////////////////////////////////////////////////////////////// - void endSection - ( - const std::string& - ) - { - if( m_currentSection->ran() ) - { - m_runStatus = RanAtLeastOneSection; - m_changed = true; - } - m_currentSection = m_currentSection->getParent(); - } - - /////////////////////////////////////////////////////////////////////// - const TestCaseInfo& getTestCaseInfo - () - const - { - return *m_info; - } - - /////////////////////////////////////////////////////////////////////// - bool hasUntestedSections - () - const - { - return m_runStatus == RanAtLeastOneSection || - ( m_rootSection.hasUntestedSections() && m_changed ); - } - - private: - const TestCaseInfo* m_info; - RunStatus m_runStatus; - SectionInfo m_rootSection; - SectionInfo* m_currentSection; - bool m_changed; - }; - /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// class Runner : public IResultCapture, public IRunner diff --git a/include/internal/catch_running_test.hpp b/include/internal/catch_running_test.hpp new file mode 100644 index 00000000..1634d706 --- /dev/null +++ b/include/internal/catch_running_test.hpp @@ -0,0 +1,150 @@ +/* + * Created by Phil Nash on 4/5/2012 + * Copyright 2012 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_INTERNAL_CATCH_RUNNING_TEST_HPP_INCLUDED +#define TWOBLUECUBES_INTERNAL_CATCH_RUNNING_TEST_HPP_INCLUDED + +#include "catch_test_case_info.hpp" +#include "catch_section_info.hpp" + +namespace Catch +{ + class RunningTest + { + enum RunStatus + { + NothingRun, + EncounteredASection, + RanAtLeastOneSection, + RanToCompletionWithSections, + RanToCompletionWithNoSections + }; + + public: + /////////////////////////////////////////////////////////////////////// + explicit RunningTest + ( + const TestCaseInfo* info = NULL + ) + : m_info( info ), + m_runStatus( RanAtLeastOneSection ), + m_currentSection( &m_rootSection ), + m_changed( false ) + { + } + + /////////////////////////////////////////////////////////////////////// + bool wasSectionSeen + () + const + { + return m_runStatus == RanAtLeastOneSection || + m_runStatus == RanToCompletionWithSections; + } + + /////////////////////////////////////////////////////////////////////// + void reset + () + { + m_runStatus = NothingRun; + m_changed = false; + m_lastSectionToRun = NULL; + } + + /////////////////////////////////////////////////////////////////////// + void ranToCompletion + () + { + if( m_runStatus == RanAtLeastOneSection || + m_runStatus == EncounteredASection ) + { + m_runStatus = RanToCompletionWithSections; + if( m_lastSectionToRun ) + { + m_lastSectionToRun->ranToCompletion(); + m_changed = true; + } + } + else + { + m_runStatus = RanToCompletionWithNoSections; + } + } + + /////////////////////////////////////////////////////////////////////// + bool addSection + ( + const std::string& name + ) + { + if( m_runStatus == NothingRun ) + m_runStatus = EncounteredASection; + + SectionInfo* thisSection = m_currentSection->findSubSection( name ); + if( !thisSection ) + { + thisSection = m_currentSection->addSubSection( name ); + m_changed = true; + } + + if( !wasSectionSeen() && thisSection->shouldRun() ) + { + m_currentSection = thisSection; + m_lastSectionToRun = NULL; + return true; + } + return false; + } + + /////////////////////////////////////////////////////////////////////// + void endSection + ( + const std::string& + ) + { + if( m_currentSection->ran() ) + { + m_runStatus = RanAtLeastOneSection; + m_changed = true; + } + else if( m_runStatus == EncounteredASection ) + { + m_runStatus = RanAtLeastOneSection; + m_lastSectionToRun = m_currentSection; +// m_changed = true; + } + m_currentSection = m_currentSection->getParent(); + } + + /////////////////////////////////////////////////////////////////////// + const TestCaseInfo& getTestCaseInfo + () + const + { + return *m_info; + } + + /////////////////////////////////////////////////////////////////////// + bool hasUntestedSections + () + const + { + return m_runStatus == RanAtLeastOneSection || + ( m_rootSection.hasUntestedSections() && m_changed ); + } + + private: + const TestCaseInfo* m_info; + RunStatus m_runStatus; + SectionInfo m_rootSection; + SectionInfo* m_currentSection; + SectionInfo* m_lastSectionToRun; + bool m_changed; + }; +} + +#endif // TWOBLUECUBES_INTERNAL_CATCH_RUNNING_TEST_HPP_INCLUDED diff --git a/include/internal/catch_section_info.hpp b/include/internal/catch_section_info.hpp new file mode 100644 index 00000000..1f5fd491 --- /dev/null +++ b/include/internal/catch_section_info.hpp @@ -0,0 +1,142 @@ +/* + * Created by Phil Nash on 4/5/2012 + * Copyright 2012 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_INTERNAL_CATCH_SECTION_INFO_HPP_INCLUDED +#define TWOBLUECUBES_INTERNAL_CATCH_SECTION_INFO_HPP_INCLUDED + +#include "catch_common.h" + +#include +#include + +namespace Catch +{ + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + class SectionInfo + { + public: + enum Status + { + Root, + Unknown, + Branch, + TestedBranch, + TestedLeaf + }; + + /////////////////////////////////////////////////////////////////////// + SectionInfo + ( + SectionInfo* parent + ) + : m_status( Unknown ), + m_parent( parent ) + { + } + + /////////////////////////////////////////////////////////////////////// + SectionInfo + () + : m_status( Root ), + m_parent( NULL ) + { + } + + /////////////////////////////////////////////////////////////////////// + ~SectionInfo + () + { + deleteAllValues( m_subSections ); + } + + /////////////////////////////////////////////////////////////////////// + bool shouldRun + () + const + { + return m_status < TestedBranch; + } + + /////////////////////////////////////////////////////////////////////// + bool ran + () + { + if( m_status < Branch ) + { + m_status = TestedLeaf; + return true; + } + return false; + } + /////////////////////////////////////////////////////////////////////// + void ranToCompletion + () + { + if( m_status == Branch && !hasUntestedSections() ) + { + m_status = TestedBranch; + } + } + + /////////////////////////////////////////////////////////////////////// + SectionInfo* findSubSection + ( + const std::string& name + ) + { + std::map::const_iterator it = m_subSections.find( name ); + return it != m_subSections.end() + ? it->second + : NULL; + } + + /////////////////////////////////////////////////////////////////////// + SectionInfo* addSubSection + ( + const std::string& name + ) + { + SectionInfo* subSection = new SectionInfo( this ); + m_subSections.insert( std::make_pair( name, subSection ) ); + m_status = Branch; + return subSection; + } + + /////////////////////////////////////////////////////////////////////// + SectionInfo* getParent + () + { + return m_parent; + } + + /////////////////////////////////////////////////////////////////////// + bool hasUntestedSections + () + const + { + if( m_status == Unknown ) + return true; + + std::map::const_iterator it = m_subSections.begin(); + std::map::const_iterator itEnd = m_subSections.end(); + for(; it != itEnd; ++it ) + { + if( it->second->hasUntestedSections() ) + return true; + } + return false; + } + + private: + Status m_status; + std::map m_subSections; + SectionInfo* m_parent; + }; +} + +#endif // TWOBLUECUBES_INTERNAL_CATCH_SECTION_INFO_HPP_INCLUDED diff --git a/include/internal/catch_test_case_registry_impl.hpp b/include/internal/catch_test_case_registry_impl.hpp index 666e5963..5f3ba7b7 100644 --- a/include/internal/catch_test_case_registry_impl.hpp +++ b/include/internal/catch_test_case_registry_impl.hpp @@ -18,7 +18,6 @@ #include #include -#include // !TBD DBG namespace Catch { class TestRegistry : public ITestCaseRegistry diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index d7595140..95389f14 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -96,26 +96,33 @@ TEST_CASE( "Sections/nested3", "nested SECTION tests" ) runner.runMatching( "./Sections/nested/a/b", "mock" ); CHECK( runner.getLog() == - "[tc]( ./Sections/nested/a/b ){ " - - "[g]( test case run ){ " - "[s]( c ){ " - "[s]( d (leaf) ){ } [s]( d (leaf) ) " - "} [s]( c ) " - "} [g]( test case run )" - - "[g]( test case run ){ " - "[s]( c ){ " - "[s]( e (leaf) ){ } [s]( e (leaf) ) " - "} [s]( c ) " - "} [g]( test case run )" - - "[g]( test case run ){ " - "[s]( c ){ } [s]( c ) " - "[s]( f (leaf) ){ } [s]( f (leaf) ) " - "} [g]( test case run ) " - - "} [tc]( ./Sections/nested/a/b )" ); + "\\[tc] ./Sections/nested/a/b\n" + + " \\[g] test case run\n" + " \\ [s] c\n" + " \\ [s] d (leaf)\n" + " / [s] d (leaf)\n" + " / [s] c\n" + " /[g] test case run\n" + + " \\[g] test case run\n" + " \\ [s] c\n" + " \\ [s] e (leaf)\n" + " / [s] e (leaf)\n" + " / [s] c\n" + " /[g] test case run\n" + + " \\[g] test case run\n" + " \\ [s] c\n" + " / [s] c\n" + " /[g] test case run\n" + + " \\[g] test case run\n" + " \\ [s] f (leaf)\n" + " / [s] f (leaf)\n" + " /[g] test case run\n" + + "/[tc] ./Sections/nested/a/b\n" ); } diff --git a/projects/SelfTest/catch_self_test.hpp b/projects/SelfTest/catch_self_test.hpp index ca180772..e3f49538 100644 --- a/projects/SelfTest/catch_self_test.hpp +++ b/projects/SelfTest/catch_self_test.hpp @@ -95,8 +95,7 @@ namespace Catch const std::string& groupName ) { - if( shouldRecord( recordGroups ) ) - m_log << recordGroups << "( " << groupName << " ){ "; + openLabel( recordGroups, groupName ); } virtual void EndGroup @@ -105,8 +104,7 @@ namespace Catch const Totals& totals ) { - if( shouldRecord( recordGroups ) ) - m_log << " } " << recordGroups << "( " << groupName << " )"; + closeLabel( recordGroups, groupName ); } virtual void StartSection @@ -115,8 +113,7 @@ namespace Catch const std::string description ) { - if( shouldRecord( recordSections ) ) - m_log << recordSections << "( " << sectionName << " ){ "; + openLabel( recordSections, sectionName ); } virtual void EndSection @@ -125,8 +122,7 @@ namespace Catch const Counts& assertions ) { - if( shouldRecord( recordSections ) ) - m_log << " } " << recordSections << "( " << sectionName << " )"; + closeLabel( recordSections, sectionName ); } virtual void StartTestCase @@ -134,8 +130,7 @@ namespace Catch const TestCaseInfo& testInfo ) { - if( shouldRecord( recordTestCases ) ) - m_log << recordTestCases << "( " << testInfo.getName() << " ){ "; + openLabel( recordTestCases, testInfo.getName() ); } virtual void EndTestCase @@ -146,8 +141,7 @@ namespace Catch const std::string& stdErr ) { - if( shouldRecord( recordTestCases ) ) - m_log << " } " << recordTestCases << "( " << testInfo.getName() << " )"; + closeLabel( recordTestCases, testInfo.getName() ); } virtual void Result @@ -214,6 +208,32 @@ namespace Catch { return m_recorders.find( recorder ) != m_recorders.end(); } + + void openLabel( const std::string& label, const std::string& arg = "" ) + { + if( shouldRecord( label ) ) + { + m_log << m_indent << "\\" << label; + if( !arg.empty() ) + m_log << " " << arg; + m_log << "\n"; + m_indent += " "; + } + } + + void closeLabel( const std::string& label, const std::string& arg = "" ) + { + if( shouldRecord( label ) ) + { + m_indent = m_indent.substr( 0, m_indent.size()-1 ); + m_log << m_indent << "/" << label; + if( !arg.empty() ) + m_log << " " << arg; + m_log << "\n"; + } + } + + std::string m_indent; std::ostringstream m_log; std::set m_recorders; }; diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index 44613af2..4df06ec3 100644 --- a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -88,6 +88,8 @@ 4AB1C73514F97BDA00F31DF7 /* catch_console_colour_impl.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_console_colour_impl.hpp; sourceTree = ""; }; 4AB1C73714F97C1300F31DF7 /* catch_console_colour.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_console_colour.hpp; sourceTree = ""; }; 4AB77CB51551AEA200857BF0 /* catch_ptr.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_ptr.hpp; sourceTree = ""; }; + 4AB77CB71553B72B00857BF0 /* catch_section_info.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_section_info.hpp; sourceTree = ""; }; + 4AB77CB81553BB3800857BF0 /* catch_running_test.hpp */ = {isa = PBXFileReference; path = catch_running_test.hpp; sourceTree = ""; }; 4AE1840A14EE4F230066340D /* catch_self_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_self_test.cpp; path = ../../../SelfTest/catch_self_test.cpp; sourceTree = ""; }; /* End PBXFileReference section */ @@ -197,6 +199,8 @@ 4AB1C73714F97C1300F31DF7 /* catch_console_colour.hpp */, 4A3D7DD01503869D005F9203 /* catch_matchers.hpp */, 4AB77CB51551AEA200857BF0 /* catch_ptr.hpp */, + 4AB77CB71553B72B00857BF0 /* catch_section_info.hpp */, + 4AB77CB81553BB3800857BF0 /* catch_running_test.hpp */, ); name = internal; path = ../../../../include/internal;