From 372a6c6fedf688341d24211f8284643c9019d8e5 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 23 Jul 2013 08:15:34 +0100 Subject: [PATCH] Small fixes and started new section tracking code --- include/internal/catch_context_impl.hpp | 4 +- include/internal/catch_objc.hpp | 12 +- include/internal/catch_runner_impl.hpp | 2 + projects/SelfTest/CmdLineTests.cpp | 1 + projects/SelfTest/SectionTrackerTests.cpp | 265 ++++++++++++++++++ .../CatchSelfTest.xcodeproj/project.pbxproj | 6 +- .../XCode4/OCTest/OCTest/CatchOCTestCase.mm | 3 +- single_include/catch.hpp | 14 +- 8 files changed, 294 insertions(+), 13 deletions(-) create mode 100644 projects/SelfTest/SectionTrackerTests.cpp diff --git a/include/internal/catch_context_impl.hpp b/include/internal/catch_context_impl.hpp index 3821fdc3..11ef98e1 100644 --- a/include/internal/catch_context_impl.hpp +++ b/include/internal/catch_context_impl.hpp @@ -62,8 +62,8 @@ namespace Catch { std::map::const_iterator it = m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() - ? it->second - : NULL; + ? it->second + : NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { diff --git a/include/internal/catch_objc.hpp b/include/internal/catch_objc.hpp index c5e021d3..45d64ba9 100644 --- a/include/internal/catch_objc.hpp +++ b/include/internal/catch_objc.hpp @@ -123,7 +123,8 @@ namespace Catch { Equals( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { - return [str isEqualToString:m_substr]; + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; } virtual std::string toString() const { @@ -135,7 +136,8 @@ namespace Catch { Contains( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { - return [str rangeOfString:m_substr].location != NSNotFound; + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; } virtual std::string toString() const { @@ -147,7 +149,8 @@ namespace Catch { StartsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { - return [str rangeOfString:m_substr].location == 0; + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; } virtual std::string toString() const { @@ -158,7 +161,8 @@ namespace Catch { EndsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { - return [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } virtual std::string toString() const { diff --git a/include/internal/catch_runner_impl.hpp b/include/internal/catch_runner_impl.hpp index 38315f2f..cf587e8f 100644 --- a/include/internal/catch_runner_impl.hpp +++ b/include/internal/catch_runner_impl.hpp @@ -286,6 +286,8 @@ namespace Catch { exResult << translateActiveException(); actOnCurrentResult( exResult.buildResult( m_lastAssertionInfo ) ); } + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. for( std::vector::const_iterator it = m_unfinishedSections.begin(), itEnd = m_unfinishedSections.end(); it != itEnd; diff --git a/projects/SelfTest/CmdLineTests.cpp b/projects/SelfTest/CmdLineTests.cpp index dba17f54..173b6412 100644 --- a/projects/SelfTest/CmdLineTests.cpp +++ b/projects/SelfTest/CmdLineTests.cpp @@ -188,4 +188,5 @@ TEST_CASE( "cmdline" ) { } } + #endif diff --git a/projects/SelfTest/SectionTrackerTests.cpp b/projects/SelfTest/SectionTrackerTests.cpp new file mode 100644 index 00000000..e949fc04 --- /dev/null +++ b/projects/SelfTest/SectionTrackerTests.cpp @@ -0,0 +1,265 @@ +/* + * Created by Phil on 20/07/2013. + * Copyright 2013 Two Blue Cubes Ltd + * + * 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) + */ + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wpadded" +#endif + +#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" ) { + + using namespace Catch; + SectionTracker sectionTracker( "test case" ); + + const std::string section1Name = "section 1"; + const std::string section2Name = "section 2"; + + CHECK_FALSE( sectionTracker.isCompleted() ); + + SECTION( "test case with no sections" ) { + + sectionTracker.enter(); + CHECK_FALSE( sectionTracker.isCompleted() ); + + sectionTracker.leave(); + CHECK( sectionTracker.isCompleted() ); + } + + SECTION( "test case with one section" ) { + + // Enter test case + sectionTracker.enter(); + + // Enter section? - no, not yet + CHECK_FALSE( sectionTracker.enterSection( section1Name ) ); + CHECK_FALSE( sectionTracker.isCompleted() ); + + // Leave test case - incomplete (still need to visit section) + sectionTracker.leave(); + CHECK_FALSE( sectionTracker.isCompleted() ); + + // ... + + // Enter test case again + sectionTracker.enter(); + + // Enter section? - yes + CHECK( sectionTracker.enterSection( section1Name ) ); + + // Leave section and test case - now complete + sectionTracker.leaveSection(); + sectionTracker.leave(); + CHECK( sectionTracker.isCompleted() ); + } + + SECTION( "test case with two consecutive sections" ) { + + // Enter test case + sectionTracker.enter(); + + // Enter section 1? - no, not yet + CHECK_FALSE( sectionTracker.enterSection( section1Name ) ); + + // Enter section 2? - no, not yet + CHECK_FALSE( sectionTracker.enterSection( section2Name ) ); + + // Leave test case - incomplete (still need to visit sections) + sectionTracker.leave(); + CHECK_FALSE( sectionTracker.isCompleted() ); + + // ... + + // Enter test case again + sectionTracker.enter(); + + // Enter section 1? - yes + CHECK( sectionTracker.enterSection( section1Name ) ); + sectionTracker.leaveSection(); + + // Enter section 2? - no, not yet + CHECK_FALSE( sectionTracker.enterSection( section2Name ) ); + + // Leave test case - incomplete (still need to visit section 2) + sectionTracker.leave(); + CHECK_FALSE( sectionTracker.isCompleted() ); + + // ... + + // Enter test case again + sectionTracker.enter(); + + // Enter section 1? - no, already done now + CHECK_FALSE( sectionTracker.enterSection( section1Name ) ); + + // Enter section 2? - yes - finally + CHECK( sectionTracker.enterSection( section2Name ) ); + sectionTracker.leaveSection(); + + // Leave test case - now complete + sectionTracker.leave(); + CHECK( sectionTracker.isCompleted() ); + } + + SECTION( "test case with one section within another" ) { + + // Enter test case + sectionTracker.enter(); + + // Enter section 1? - no, not yet + CHECK_FALSE( sectionTracker.enterSection( section1Name ) ); + + // Leave test case - incomplete (still need to visit sections) + sectionTracker.leave(); + CHECK_FALSE( sectionTracker.isCompleted() ); + + // ... + + // Enter test case again + sectionTracker.enter(); + + // Enter section 1? - yes + CHECK( sectionTracker.enterSection( section1Name ) ); + + // Enter section 2? - no, not yet + CHECK_FALSE( sectionTracker.enterSection( section2Name ) ); + + sectionTracker.leaveSection(); // section 1 - incomplete (section 2) + + // Leave test case - incomplete + sectionTracker.leave(); + CHECK_FALSE( sectionTracker.isCompleted() ); + + // ... + + // Enter test case again + sectionTracker.enter(); + + // Enter section 1? - yes - so we can execute section 2 + CHECK( sectionTracker.enterSection( section1Name ) ); + + // Enter section 2? - yes - finally + CHECK( sectionTracker.enterSection( section2Name ) ); + sectionTracker.leaveSection(); // section 2 + sectionTracker.leaveSection(); // section 1 + + // Leave test case - now complete + sectionTracker.leave(); + CHECK( sectionTracker.isCompleted() ); + } +} diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index 3e99d94c..b58de3bb 100644 --- a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 266E9AD617290E8E0061DAB2 /* CmdLineTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266E9AD417290E8E0061DAB2 /* CmdLineTests.cpp */; }; 266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266ECD73170F3C620030D735 /* BDDTests.cpp */; }; 26847E5F16BBADB40043B9C1 /* catch_message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26847E5D16BBADB40043B9C1 /* catch_message.cpp */; }; + 26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */; }; 2694A1FD16A0000E004816E3 /* catch_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2694A1FB16A0000E004816E3 /* catch_text.cpp */; }; 4A45DA2416161EF9004F8D6B /* catch_console_colour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A45DA2316161EF9004F8D6B /* catch_console_colour.cpp */; }; 4A45DA2716161F1F004F8D6B /* catch_ptr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A45DA2616161F1F004F8D6B /* catch_ptr.cpp */; }; @@ -67,6 +68,7 @@ 26847E5B16BBAB790043B9C1 /* catch_message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_message.h; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; @@ -142,7 +144,7 @@ 4A90B59B15D0F61A00EF71BC /* catch_interfaces_generators.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_interfaces_generators.h; sourceTree = ""; }; 4A90B59D15D24FE900EF71BC /* catch_assertionresult.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_assertionresult.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 4A90B59E15D2521E00EF71BC /* catch_expressionresult_builder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_expressionresult_builder.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - 4A9D84B11558FC0400FBB209 /* catch_tostring.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_tostring.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + 4A9D84B11558FC0400FBB209 /* catch_tostring.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_tostring.hpp; sourceTree = ""; }; 4A9D84B315599AC900FBB209 /* catch_expressionresult_builder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = catch_expressionresult_builder.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 4AA7B8B4165428BA003155F6 /* catch_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = catch_version.hpp; path = ../../../../include/internal/catch_version.hpp; sourceTree = ""; }; 4AB1C73514F97BDA00F31DF7 /* catch_console_colour_impl.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_console_colour_impl.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -183,6 +185,7 @@ isa = PBXGroup; children = ( 266E9AD417290E8E0061DAB2 /* CmdLineTests.cpp */, + 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */, ); name = "Introspective Tests"; sourceTree = ""; @@ -515,6 +518,7 @@ 266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */, 266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */, 266E9AD617290E8E0061DAB2 /* CmdLineTests.cpp in Sources */, + 26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/projects/XCode4/OCTest/OCTest/CatchOCTestCase.mm b/projects/XCode4/OCTest/OCTest/CatchOCTestCase.mm index 1ed7aa5f..fb20287b 100644 --- a/projects/XCode4/OCTest/OCTest/CatchOCTestCase.mm +++ b/projects/XCode4/OCTest/OCTest/CatchOCTestCase.mm @@ -76,7 +76,8 @@ OC_TEST_CASE( "OCTest/matchers", "Matches work with OC types (NSString so far)" OC_TEST_CASE( "OCTest/matchers/nil", "nil NSString should not crash the test" ) { - REQUIRE_THAT( (NSString*)nil, Equals( @"This should fail, but not crash" ) ); + CHECK_THAT( (NSString*)nil, Equals( @"This should fail, but not crash" ) ); + CHECK_THAT( (NSString*)nil, StartsWith( @"anything" ) ); } @end diff --git a/single_include/catch.hpp b/single_include/catch.hpp index af845fdb..d25a0d8c 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* * CATCH v1.0 build 5 (master branch) - * Generated: 2013-07-03 08:24:00.747039 + * Generated: 2013-07-05 08:38:07.926803 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -3498,7 +3498,8 @@ namespace Catch { Equals( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { - return [str isEqualToString:m_substr]; + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; } virtual std::string toString() const { @@ -3510,7 +3511,8 @@ namespace Catch { Contains( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { - return [str rangeOfString:m_substr].location != NSNotFound; + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; } virtual std::string toString() const { @@ -3522,7 +3524,8 @@ namespace Catch { StartsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { - return [str rangeOfString:m_substr].location == 0; + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; } virtual std::string toString() const { @@ -3533,7 +3536,8 @@ namespace Catch { EndsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { - return [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } virtual std::string toString() const {