diff --git a/README.md b/README.md index 884b7644..6caea101 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![catch logo](catch-logo-small.png) -*v1.0 build 35 (master branch)* +*v1.0 build 36 (master branch)* Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch) diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index 57e5aa99..97a65b2e 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -50,29 +50,29 @@ namespace Catch { } return totals; } - - Totals runTestsForGroup( RunContext& context, const TestCaseFilters& filterGroup ) { + Totals runTestsForGroup( RunContext& context, TestCaseFilters const& filterGroup ) { Totals totals; - std::vector::const_iterator it = getRegistryHub().getTestCaseRegistry().getAllTests().begin(); - std::vector::const_iterator itEnd = getRegistryHub().getTestCaseRegistry().getAllTests().end(); + + std::vector testCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( filterGroup, *m_config, testCases ); + int testsRunForGroup = 0; - for(; it != itEnd; ++it ) { - if( filterGroup.shouldInclude( *it ) ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) { + testsRunForGroup++; + if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { - if( context.aborting() ) - break; + if( context.aborting() ) + break; - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } + totals += context.runTest( *it ); + m_testsAlreadyRun.insert( *it ); } } if( testsRunForGroup == 0 && !filterGroup.getName().empty() ) m_reporter->noMatchingTestCases( filterGroup.getName() ); return totals; - } private: diff --git a/include/internal/catch_console_colour.hpp b/include/internal/catch_console_colour.hpp index 3fc2e38b..3ea81788 100644 --- a/include/internal/catch_console_colour.hpp +++ b/include/internal/catch_console_colour.hpp @@ -58,7 +58,7 @@ namespace Catch { static void use( Code _colourCode ); private: - static Detail::IColourImpl* impl; + static Detail::IColourImpl* impl(); }; } // end namespace Catch diff --git a/include/internal/catch_console_colour_impl.hpp b/include/internal/catch_console_colour_impl.hpp index b20762f3..c159dc95 100644 --- a/include/internal/catch_console_colour_impl.hpp +++ b/include/internal/catch_console_colour_impl.hpp @@ -73,7 +73,10 @@ namespace { return true; } - Win32ColourImpl platformColourImpl; + static Detail::IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + return &s_instance; + } } // end anon namespace } // end namespace Catch @@ -120,7 +123,10 @@ namespace { return isatty(STDOUT_FILENO); } - PosixColourImpl platformColourImpl; + static Detail::IColourImpl* platformColourInstance() { + static PosixColourImpl s_instance; + return &s_instance; + } } // end anon namespace } // end namespace Catch @@ -132,21 +138,28 @@ namespace Catch { namespace { struct NoColourImpl : Detail::IColourImpl { void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } }; - NoColourImpl noColourImpl; - static const bool shouldUseColour = shouldUseColourForPlatform() && - !isDebuggerActive(); + static bool shouldUseColour() { + return shouldUseColourForPlatform() && !isDebuggerActive(); + } } Colour::Colour( Code _colourCode ){ use( _colourCode ); } Colour::~Colour(){ use( None ); } void Colour::use( Code _colourCode ) { - impl->use( _colourCode ); + impl()->use( _colourCode ); } - Detail::IColourImpl* Colour::impl = shouldUseColour - ? static_cast( &platformColourImpl ) - : static_cast( &noColourImpl ); + Detail::IColourImpl* Colour::impl() { + return shouldUseColour() + ? platformColourInstance() + : NoColourImpl::instance(); + } } // end namespace Catch diff --git a/include/internal/catch_interfaces_config.h b/include/internal/catch_interfaces_config.h index 79cfa97b..0c7c3b28 100644 --- a/include/internal/catch_interfaces_config.h +++ b/include/internal/catch_interfaces_config.h @@ -10,6 +10,7 @@ #include #include +#include #include "catch_ptr.hpp" @@ -32,6 +33,8 @@ namespace Catch { Never }; }; + class TestCaseFilters; + struct IConfig : IShared { virtual ~IConfig(); @@ -44,6 +47,7 @@ namespace Catch { virtual bool warnAboutMissingAssertions() const = 0; virtual int abortAfter() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; + virtual std::vector const& filters() const = 0; }; } diff --git a/include/internal/catch_interfaces_testcase.h b/include/internal/catch_interfaces_testcase.h index 03ef94ec..47f15204 100644 --- a/include/internal/catch_interfaces_testcase.h +++ b/include/internal/catch_interfaces_testcase.h @@ -23,11 +23,14 @@ namespace Catch { }; class TestCase; + struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual std::vector getMatchingTestCases( std::string const& rawTestSpec ) const = 0; + virtual void getFilteredTests( TestCaseFilters const& filters, IConfig const& config, std::vector& matchingTestCases ) const = 0; + virtual void getFilteredTests( IConfig const& config, std::vector& matchingTestCases ) const = 0; + }; } diff --git a/include/internal/catch_list.hpp b/include/internal/catch_list.hpp index 1ee3d1f5..76a963f0 100644 --- a/include/internal/catch_list.hpp +++ b/include/internal/catch_list.hpp @@ -17,14 +17,6 @@ #include namespace Catch { - inline bool matchesFilters( std::vector const& filters, TestCase const& testCase ) { - std::vector::const_iterator it = filters.begin(); - std::vector::const_iterator itEnd = filters.end(); - for(; it != itEnd; ++it ) - if( !it->shouldInclude( testCase ) ) - return false; - return true; - } inline std::size_t listTests( Config const& config ) { if( config.filters().empty() ) @@ -37,22 +29,22 @@ namespace Catch { nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); - std::vector const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); - for( std::vector::const_iterator it = allTests.begin(), itEnd = allTests.end(); + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; - ++it ) - if( matchesFilters( config.filters(), *it ) ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Colour::Code colour = testCaseInfo.isHidden - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); - std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl; - if( !testCaseInfo.tags.empty() ) - std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; - } + std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } if( config.filters().empty() ) std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl; @@ -63,15 +55,15 @@ namespace Catch { inline std::size_t listTestsNamesOnly( Config const& config ) { std::size_t matchedTests = 0; - std::vector const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); - for( std::vector::const_iterator it = allTests.begin(), itEnd = allTests.end(); + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; - ++it ) - if( matchesFilters( config.filters(), *it ) ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - std::cout << testCaseInfo.name << std::endl; - } + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + std::cout << testCaseInfo.name << std::endl; + } return matchedTests; } @@ -83,23 +75,21 @@ namespace Catch { std::map tagCounts; - std::vector const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); - for( std::vector::const_iterator it = allTests.begin(), - itEnd = allTests.end(); + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { - if( matchesFilters( config.filters(), *it ) ) { - for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), - tagItEnd = it->getTestCaseInfo().tags.end(); - tagIt != tagItEnd; - ++tagIt ) { - std::string tagName = *tagIt; - std::map::iterator countIt = tagCounts.find( tagName ); - if( countIt == tagCounts.end() ) - tagCounts.insert( std::make_pair( tagName, 1 ) ); - else - countIt->second++; - } + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::map::iterator countIt = tagCounts.find( tagName ); + if( countIt == tagCounts.end() ) + tagCounts.insert( std::make_pair( tagName, 1 ) ); + else + countIt->second++; } } diff --git a/include/internal/catch_runner_impl.hpp b/include/internal/catch_runner_impl.hpp index 4b34f1e9..8ca65934 100644 --- a/include/internal/catch_runner_impl.hpp +++ b/include/internal/catch_runner_impl.hpp @@ -88,23 +88,6 @@ namespace Catch { m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); } - Totals runMatching( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { - - std::vector matchingTests = getRegistryHub().getTestCaseRegistry().getMatchingTestCases( testSpec ); - - Totals totals; - - testGroupStarting( testSpec, groupIndex, groupsCount ); - - std::vector::const_iterator it = matchingTests.begin(); - std::vector::const_iterator itEnd = matchingTests.end(); - for(; it != itEnd; ++it ) - totals += runTest( *it ); - - testGroupEnded( testSpec, totals, groupIndex, groupsCount ); - return totals; - } - Totals runTest( TestCase const& testCase ) { Totals prevTotals = m_totals; diff --git a/include/internal/catch_test_case_info.h b/include/internal/catch_test_case_info.h index 2977d945..aa9dc867 100644 --- a/include/internal/catch_test_case_info.h +++ b/include/internal/catch_test_case_info.h @@ -40,6 +40,7 @@ namespace Catch { std::string tagsAsString; SourceLineInfo lineInfo; bool isHidden; + bool throws; }; class TestCase : protected TestCaseInfo { @@ -55,6 +56,7 @@ namespace Catch { TestCaseInfo const& getTestCaseInfo() const; bool isHidden() const; + bool throws() const; bool hasTag( std::string const& tag ) const; bool matchesTags( std::string const& tagPattern ) const; std::set const& getTags() const; diff --git a/include/internal/catch_test_case_info.hpp b/include/internal/catch_test_case_info.hpp index 75cd9323..84bf6a33 100644 --- a/include/internal/catch_test_case_info.hpp +++ b/include/internal/catch_test_case_info.hpp @@ -15,6 +15,16 @@ namespace Catch { + inline bool isSpecialTag( std::string const& tag ) { + return tag == "." || + tag == "hide" || + tag == "!hide" || + tag == "!throws"; + } + inline bool isReservedTag( std::string const& tag ) { + return !isSpecialTag( tag ) && tag.size() > 0 && !isalnum( tag[0] ); + } + TestCase makeTestCase( ITestCase* _testCase, std::string const& _className, std::string const& _name, @@ -25,6 +35,23 @@ namespace Catch { bool isHidden( startsWith( _name, "./" ) ); // Legacy support std::set tags; TagExtracter( tags ).parse( desc ); + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); + it != itEnd; + ++it ) + if( isReservedTag( *it ) ) { + { + Colour colourGuard( Colour::Red ); + std::cerr + << "Tag name [" << *it << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + std::cerr << _lineInfo << std::endl; + } + exit(1); + } + if( tags.find( "hide" ) != tags.end() || tags.find( "." ) != tags.end() ) isHidden = true; @@ -47,11 +74,15 @@ namespace Catch { description( _description ), tags( _tags ), lineInfo( _lineInfo ), - isHidden( _isHidden ) + isHidden( _isHidden ), + throws( false ) { std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) + for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { oss << "[" << *it << "]"; + if( *it == "!throws" ) + throws = true; + } tagsAsString = oss.str(); } @@ -62,7 +93,8 @@ namespace Catch { tags( other.tags ), tagsAsString( other.tagsAsString ), lineInfo( other.lineInfo ), - isHidden( other.isHidden ) + isHidden( other.isHidden ), + throws( other.throws ) {} TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} @@ -85,6 +117,9 @@ namespace Catch { bool TestCase::isHidden() const { return TestCaseInfo::isHidden; } + bool TestCase::throws() const { + return TestCaseInfo::throws; + } bool TestCase::hasTag( std::string const& tag ) const { return tags.find( toLower( tag ) ) != tags.end(); diff --git a/include/internal/catch_test_case_registry_impl.hpp b/include/internal/catch_test_case_registry_impl.hpp index af1ee29f..25f210ef 100644 --- a/include/internal/catch_test_case_registry_impl.hpp +++ b/include/internal/catch_test_case_registry_impl.hpp @@ -41,9 +41,12 @@ namespace Catch { } else { TestCase const& prev = *m_functions.find( testCase ); - std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; + { + Colour colourGuard( Colour::Red ); + std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; + } exit(1); } } @@ -56,32 +59,24 @@ namespace Catch { return m_nonHiddenFunctions; } - // !TBD deprecated - virtual std::vector getMatchingTestCases( std::string const& rawTestSpec ) const { - std::vector matchingTests; - getMatchingTestCases( rawTestSpec, matchingTests ); - return matchingTests; - } - - // !TBD deprecated - virtual void getMatchingTestCases( std::string const& rawTestSpec, std::vector& matchingTestsOut ) const { - TestCaseFilter filter( rawTestSpec ); - - std::vector::const_iterator it = m_functionsInOrder.begin(); - std::vector::const_iterator itEnd = m_functionsInOrder.end(); - for(; it != itEnd; ++it ) { - if( filter.shouldInclude( *it ) ) { - matchingTestsOut.push_back( *it ); - } + virtual void getFilteredTests( TestCaseFilters const& filters, IConfig const& config, std::vector& matchingTestCases ) const { + for( std::vector::const_iterator it = m_functionsInOrder.begin(), + itEnd = m_functionsInOrder.end(); + it != itEnd; + ++it ) { + if( filters.shouldInclude( *it ) && ( config.allowThrows() || !it->throws() ) ) + matchingTestCases.push_back( *it ); } } - virtual void getMatchingTestCases( TestCaseFilters const& filters, std::vector& matchingTestsOut ) const { - std::vector::const_iterator it = m_functionsInOrder.begin(); - std::vector::const_iterator itEnd = m_functionsInOrder.end(); - // !TBD: replace with algorithm - for(; it != itEnd; ++it ) - if( filters.shouldInclude( *it ) ) - matchingTestsOut.push_back( *it ); + virtual void getFilteredTests( IConfig const& config, std::vector& matchingTestCases ) const { + if( config.filters().empty() ) + return getFilteredTests( TestCaseFilters( "empty" ), config, matchingTestCases ); + + for( std::vector::const_iterator it = config.filters().begin(), + itEnd = config.filters().end(); + it != itEnd; + ++it ) + getFilteredTests( *it, config, matchingTestCases ); } private: diff --git a/include/internal/catch_version.hpp b/include/internal/catch_version.hpp index 237e260f..81b4f176 100644 --- a/include/internal/catch_version.hpp +++ b/include/internal/catch_version.hpp @@ -13,7 +13,7 @@ namespace Catch { // These numbers are maintained by a script - Version libraryVersion( 1, 0, 35, "master" ); + Version libraryVersion( 1, 0, 36, "master" ); } #endif // TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 5f23df59..83d2a153 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -774,5 +774,5 @@ with expansion: "first" == "second" =============================================================================== -124 test cases - 38 failed (660 assertions - 93 failed) +125 test cases - 38 failed (660 assertions - 93 failed) diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 12f74797..2160b17a 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -3650,6 +3650,15 @@ MiscTests.cpp:: FAILED: explicitly with message: to infinity and beyond +------------------------------------------------------------------------------- +not allowed +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + + +No assertions in test case 'not allowed' + ------------------------------------------------------------------------------- Process can be configured on command line default - no arguments @@ -6982,5 +6991,5 @@ with expansion: true =============================================================================== -124 test cases - 53 failed (679 assertions - 112 failed) +125 test cases - 54 failed (680 assertions - 113 failed) diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 90b2c6c3..071b7838 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,5 +1,5 @@ - + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index ada68ac3..4f8835b5 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -3723,6 +3723,9 @@ + + +
@@ -7242,7 +7245,7 @@ there"
- + - + diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index efcd4582..7c028ffa 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -333,3 +333,9 @@ TEST_CASE("A couple of nested sections followed by a failure", "[failing][.]") FAIL("to infinity and beyond"); } + +TEST_CASE("not allowed", "[!throws]") +{ + // This test case should not be included if you run with -e on the command line + SUCCEED(); +} diff --git a/single_include/catch.hpp b/single_include/catch.hpp index 45724df9..c1c820d4 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* - * CATCH v1.0 build 35 (master branch) - * Generated: 2014-04-12 19:20:39.856403 + * CATCH v1.0 build 36 (master branch) + * Generated: 2014-04-15 18:42:33.686099 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -420,11 +420,14 @@ namespace Catch { }; class TestCase; + struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual std::vector getMatchingTestCases( std::string const& rawTestSpec ) const = 0; + virtual void getFilteredTests( TestCaseFilters const& filters, IConfig const& config, std::vector& matchingTestCases ) const = 0; + virtual void getFilteredTests( IConfig const& config, std::vector& matchingTestCases ) const = 0; + }; } @@ -1497,6 +1500,7 @@ namespace Catch { #include #include +#include namespace Catch { @@ -1517,6 +1521,8 @@ namespace Catch { Never }; }; + class TestCaseFilters; + struct IConfig : IShared { virtual ~IConfig(); @@ -1529,6 +1535,7 @@ namespace Catch { virtual bool warnAboutMissingAssertions() const = 0; virtual int abortAfter() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; + virtual std::vector const& filters() const = 0; }; } @@ -2411,6 +2418,7 @@ namespace Catch { std::string tagsAsString; SourceLineInfo lineInfo; bool isHidden; + bool throws; }; class TestCase : protected TestCaseInfo { @@ -2426,6 +2434,7 @@ namespace Catch { TestCaseInfo const& getTestCaseInfo() const; bool isHidden() const; + bool throws() const; bool hasTag( std::string const& tag ) const; bool matchesTags( std::string const& tagPattern ) const; std::set const& getTags() const; @@ -4221,7 +4230,7 @@ namespace Catch { static void use( Code _colourCode ); private: - static Detail::IColourImpl* impl; + static Detail::IColourImpl* impl(); }; } // end namespace Catch @@ -4505,14 +4514,6 @@ namespace Catch #include namespace Catch { - inline bool matchesFilters( std::vector const& filters, TestCase const& testCase ) { - std::vector::const_iterator it = filters.begin(); - std::vector::const_iterator itEnd = filters.end(); - for(; it != itEnd; ++it ) - if( !it->shouldInclude( testCase ) ) - return false; - return true; - } inline std::size_t listTests( Config const& config ) { if( config.filters().empty() ) @@ -4525,22 +4526,22 @@ namespace Catch { nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); - std::vector const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); - for( std::vector::const_iterator it = allTests.begin(), itEnd = allTests.end(); + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; - ++it ) - if( matchesFilters( config.filters(), *it ) ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Colour::Code colour = testCaseInfo.isHidden - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); - std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl; - if( !testCaseInfo.tags.empty() ) - std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; - } + std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } if( config.filters().empty() ) std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl; @@ -4551,15 +4552,15 @@ namespace Catch { inline std::size_t listTestsNamesOnly( Config const& config ) { std::size_t matchedTests = 0; - std::vector const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); - for( std::vector::const_iterator it = allTests.begin(), itEnd = allTests.end(); + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; - ++it ) - if( matchesFilters( config.filters(), *it ) ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - std::cout << testCaseInfo.name << std::endl; - } + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + std::cout << testCaseInfo.name << std::endl; + } return matchedTests; } @@ -4571,23 +4572,21 @@ namespace Catch { std::map tagCounts; - std::vector const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); - for( std::vector::const_iterator it = allTests.begin(), - itEnd = allTests.end(); + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { - if( matchesFilters( config.filters(), *it ) ) { - for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), - tagItEnd = it->getTestCaseInfo().tags.end(); - tagIt != tagItEnd; - ++tagIt ) { - std::string tagName = *tagIt; - std::map::iterator countIt = tagCounts.find( tagName ); - if( countIt == tagCounts.end() ) - tagCounts.insert( std::make_pair( tagName, 1 ) ); - else - countIt->second++; - } + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::map::iterator countIt = tagCounts.find( tagName ); + if( countIt == tagCounts.end() ) + tagCounts.insert( std::make_pair( tagName, 1 ) ); + else + countIt->second++; } } @@ -4856,23 +4855,6 @@ namespace Catch { m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); } - Totals runMatching( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { - - std::vector matchingTests = getRegistryHub().getTestCaseRegistry().getMatchingTestCases( testSpec ); - - Totals totals; - - testGroupStarting( testSpec, groupIndex, groupsCount ); - - std::vector::const_iterator it = matchingTests.begin(); - std::vector::const_iterator itEnd = matchingTests.end(); - for(; it != itEnd; ++it ) - totals += runTest( *it ); - - testGroupEnded( testSpec, totals, groupIndex, groupsCount ); - return totals; - } - Totals runTest( TestCase const& testCase ) { Totals prevTotals = m_totals; @@ -5165,29 +5147,29 @@ namespace Catch { } return totals; } - - Totals runTestsForGroup( RunContext& context, const TestCaseFilters& filterGroup ) { + Totals runTestsForGroup( RunContext& context, TestCaseFilters const& filterGroup ) { Totals totals; - std::vector::const_iterator it = getRegistryHub().getTestCaseRegistry().getAllTests().begin(); - std::vector::const_iterator itEnd = getRegistryHub().getTestCaseRegistry().getAllTests().end(); + + std::vector testCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( filterGroup, *m_config, testCases ); + int testsRunForGroup = 0; - for(; it != itEnd; ++it ) { - if( filterGroup.shouldInclude( *it ) ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) { + testsRunForGroup++; + if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { - if( context.aborting() ) - break; + if( context.aborting() ) + break; - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } + totals += context.runTest( *it ); + m_testsAlreadyRun.insert( *it ); } } if( testsRunForGroup == 0 && !filterGroup.getName().empty() ) m_reporter->noMatchingTestCases( filterGroup.getName() ); return totals; - } private: @@ -5370,9 +5352,12 @@ namespace Catch { } else { TestCase const& prev = *m_functions.find( testCase ); - std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; + { + Colour colourGuard( Colour::Red ); + std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; + } exit(1); } } @@ -5385,32 +5370,24 @@ namespace Catch { return m_nonHiddenFunctions; } - // !TBD deprecated - virtual std::vector getMatchingTestCases( std::string const& rawTestSpec ) const { - std::vector matchingTests; - getMatchingTestCases( rawTestSpec, matchingTests ); - return matchingTests; - } - - // !TBD deprecated - virtual void getMatchingTestCases( std::string const& rawTestSpec, std::vector& matchingTestsOut ) const { - TestCaseFilter filter( rawTestSpec ); - - std::vector::const_iterator it = m_functionsInOrder.begin(); - std::vector::const_iterator itEnd = m_functionsInOrder.end(); - for(; it != itEnd; ++it ) { - if( filter.shouldInclude( *it ) ) { - matchingTestsOut.push_back( *it ); - } + virtual void getFilteredTests( TestCaseFilters const& filters, IConfig const& config, std::vector& matchingTestCases ) const { + for( std::vector::const_iterator it = m_functionsInOrder.begin(), + itEnd = m_functionsInOrder.end(); + it != itEnd; + ++it ) { + if( filters.shouldInclude( *it ) && ( config.allowThrows() || !it->throws() ) ) + matchingTestCases.push_back( *it ); } } - virtual void getMatchingTestCases( TestCaseFilters const& filters, std::vector& matchingTestsOut ) const { - std::vector::const_iterator it = m_functionsInOrder.begin(); - std::vector::const_iterator itEnd = m_functionsInOrder.end(); - // !TBD: replace with algorithm - for(; it != itEnd; ++it ) - if( filters.shouldInclude( *it ) ) - matchingTestsOut.push_back( *it ); + virtual void getFilteredTests( IConfig const& config, std::vector& matchingTestCases ) const { + if( config.filters().empty() ) + return getFilteredTests( TestCaseFilters( "empty" ), config, matchingTestCases ); + + for( std::vector::const_iterator it = config.filters().begin(), + itEnd = config.filters().end(); + it != itEnd; + ++it ) + getFilteredTests( *it, config, matchingTestCases ); } private: @@ -5909,7 +5886,10 @@ namespace { return true; } - Win32ColourImpl platformColourImpl; + static Detail::IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + return &s_instance; + } } // end anon namespace } // end namespace Catch @@ -5956,7 +5936,10 @@ namespace { return isatty(STDOUT_FILENO); } - PosixColourImpl platformColourImpl; + static Detail::IColourImpl* platformColourInstance() { + static PosixColourImpl s_instance; + return &s_instance; + } } // end anon namespace } // end namespace Catch @@ -5968,21 +5951,28 @@ namespace Catch { namespace { struct NoColourImpl : Detail::IColourImpl { void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } }; - NoColourImpl noColourImpl; - static const bool shouldUseColour = shouldUseColourForPlatform() && - !isDebuggerActive(); + static bool shouldUseColour() { + return shouldUseColourForPlatform() && !isDebuggerActive(); + } } Colour::Colour( Code _colourCode ){ use( _colourCode ); } Colour::~Colour(){ use( None ); } void Colour::use( Code _colourCode ) { - impl->use( _colourCode ); + impl()->use( _colourCode ); } - Detail::IColourImpl* Colour::impl = shouldUseColour - ? static_cast( &platformColourImpl ) - : static_cast( &noColourImpl ); + Detail::IColourImpl* Colour::impl() { + return shouldUseColour() + ? platformColourInstance() + : NoColourImpl::instance(); + } } // end namespace Catch @@ -6233,6 +6223,16 @@ namespace Catch { namespace Catch { + inline bool isSpecialTag( std::string const& tag ) { + return tag == "." || + tag == "hide" || + tag == "!hide" || + tag == "!throws"; + } + inline bool isReservedTag( std::string const& tag ) { + return !isSpecialTag( tag ) && tag.size() > 0 && !isalnum( tag[0] ); + } + TestCase makeTestCase( ITestCase* _testCase, std::string const& _className, std::string const& _name, @@ -6243,6 +6243,23 @@ namespace Catch { bool isHidden( startsWith( _name, "./" ) ); // Legacy support std::set tags; TagExtracter( tags ).parse( desc ); + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); + it != itEnd; + ++it ) + if( isReservedTag( *it ) ) { + { + Colour colourGuard( Colour::Red ); + std::cerr + << "Tag name [" << *it << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + std::cerr << _lineInfo << std::endl; + } + exit(1); + } + if( tags.find( "hide" ) != tags.end() || tags.find( "." ) != tags.end() ) isHidden = true; @@ -6265,11 +6282,15 @@ namespace Catch { description( _description ), tags( _tags ), lineInfo( _lineInfo ), - isHidden( _isHidden ) + isHidden( _isHidden ), + throws( false ) { std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) + for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { oss << "[" << *it << "]"; + if( *it == "!throws" ) + throws = true; + } tagsAsString = oss.str(); } @@ -6280,7 +6301,8 @@ namespace Catch { tags( other.tags ), tagsAsString( other.tagsAsString ), lineInfo( other.lineInfo ), - isHidden( other.isHidden ) + isHidden( other.isHidden ), + throws( other.throws ) {} TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} @@ -6303,6 +6325,9 @@ namespace Catch { bool TestCase::isHidden() const { return TestCaseInfo::isHidden; } + bool TestCase::throws() const { + return TestCaseInfo::throws; + } bool TestCase::hasTag( std::string const& tag ) const { return tags.find( toLower( tag ) ) != tags.end(); @@ -6598,7 +6623,7 @@ namespace Catch { namespace Catch { // These numbers are maintained by a script - Version libraryVersion( 1, 0, 35, "master" ); + Version libraryVersion( 1, 0, 36, "master" ); } // #included from: catch_message.hpp