mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Tags beginning with a non alpha-numeric character are now disallowed.
Added !throws special tag which denotes a test case to be skipped when run with -e (the idea being that the test case is expected to throw an exception which is not caught within a XXX_THROWS assertion).
This commit is contained in:
		| @@ -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<TestCase>::const_iterator it = getRegistryHub().getTestCaseRegistry().getAllTests().begin(); | ||||
|             std::vector<TestCase>::const_iterator itEnd = getRegistryHub().getTestCaseRegistry().getAllTests().end(); | ||||
|  | ||||
|             std::vector<TestCase> 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<TestCase>::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: | ||||
|   | ||||
| @@ -58,7 +58,7 @@ namespace Catch { | ||||
|         static void use( Code _colourCode ); | ||||
|  | ||||
|     private: | ||||
|         static Detail::IColourImpl* impl; | ||||
|         static Detail::IColourImpl* impl(); | ||||
|     }; | ||||
|  | ||||
| } // end namespace Catch | ||||
|   | ||||
| @@ -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<Detail::IColourImpl*>( &platformColourImpl ) | ||||
|             : static_cast<Detail::IColourImpl*>( &noColourImpl ); | ||||
|     Detail::IColourImpl* Colour::impl() { | ||||
|         return shouldUseColour() | ||||
|             ? platformColourInstance() | ||||
|             : NoColourImpl::instance(); | ||||
|     } | ||||
|  | ||||
| } // end namespace Catch | ||||
|  | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| #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<TestCaseFilters> const& filters() const = 0; | ||||
|     }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -23,11 +23,14 @@ namespace Catch { | ||||
|     }; | ||||
|  | ||||
|     class TestCase; | ||||
|     struct IConfig; | ||||
|  | ||||
|     struct ITestCaseRegistry { | ||||
|         virtual ~ITestCaseRegistry(); | ||||
|         virtual std::vector<TestCase> const& getAllTests() const = 0; | ||||
|         virtual std::vector<TestCase> getMatchingTestCases( std::string const& rawTestSpec ) const = 0; | ||||
|         virtual void getFilteredTests( TestCaseFilters const& filters, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const = 0; | ||||
|         virtual void getFilteredTests( IConfig const& config, std::vector<TestCase>& matchingTestCases ) const = 0; | ||||
|  | ||||
|     }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -17,14 +17,6 @@ | ||||
| #include <algorithm> | ||||
|  | ||||
| namespace Catch { | ||||
|     inline bool matchesFilters( std::vector<TestCaseFilters> const& filters, TestCase const& testCase ) { | ||||
|         std::vector<TestCaseFilters>::const_iterator it = filters.begin(); | ||||
|         std::vector<TestCaseFilters>::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<TestCase> const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); | ||||
|         for( std::vector<TestCase>::const_iterator it = allTests.begin(), itEnd = allTests.end(); | ||||
|         std::vector<TestCase> matchedTestCases; | ||||
|         getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); | ||||
|         for( std::vector<TestCase>::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<TestCase> const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); | ||||
|         for( std::vector<TestCase>::const_iterator it = allTests.begin(), itEnd = allTests.end(); | ||||
|         std::vector<TestCase> matchedTestCases; | ||||
|         getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); | ||||
|         for( std::vector<TestCase>::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<std::string, int> tagCounts; | ||||
|  | ||||
|         std::vector<TestCase> const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests(); | ||||
|         for( std::vector<TestCase>::const_iterator  it = allTests.begin(), | ||||
|                                                     itEnd = allTests.end(); | ||||
|         std::vector<TestCase> matchedTestCases; | ||||
|         getRegistryHub().getTestCaseRegistry().getFilteredTests( config, matchedTestCases ); | ||||
|         for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); | ||||
|                 it != itEnd; | ||||
|                 ++it ) { | ||||
|             if( matchesFilters( config.filters(), *it ) ) { | ||||
|                 for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(), | ||||
|                                                             tagItEnd = it->getTestCaseInfo().tags.end(); | ||||
|                         tagIt != tagItEnd; | ||||
|                         ++tagIt ) { | ||||
|                     std::string tagName = *tagIt; | ||||
|                     std::map<std::string, int>::iterator countIt = tagCounts.find( tagName ); | ||||
|                     if( countIt == tagCounts.end() ) | ||||
|                         tagCounts.insert( std::make_pair( tagName, 1 ) ); | ||||
|                     else | ||||
|                         countIt->second++; | ||||
|                 } | ||||
|             for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(), | ||||
|                                                         tagItEnd = it->getTestCaseInfo().tags.end(); | ||||
|                     tagIt != tagItEnd; | ||||
|                     ++tagIt ) { | ||||
|                 std::string tagName = *tagIt; | ||||
|                 std::map<std::string, int>::iterator countIt = tagCounts.find( tagName ); | ||||
|                 if( countIt == tagCounts.end() ) | ||||
|                     tagCounts.insert( std::make_pair( tagName, 1 ) ); | ||||
|                 else | ||||
|                     countIt->second++; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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<TestCase> matchingTests = getRegistryHub().getTestCaseRegistry().getMatchingTestCases( testSpec ); | ||||
|  | ||||
|             Totals totals; | ||||
|  | ||||
|             testGroupStarting( testSpec, groupIndex, groupsCount ); | ||||
|  | ||||
|             std::vector<TestCase>::const_iterator it = matchingTests.begin(); | ||||
|             std::vector<TestCase>::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; | ||||
|  | ||||
|   | ||||
| @@ -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<std::string> const& getTags() const; | ||||
|   | ||||
| @@ -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<std::string> tags; | ||||
|         TagExtracter( tags ).parse( desc ); | ||||
|         for( std::set<std::string>::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<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) | ||||
|         for( std::set<std::string>::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(); | ||||
|   | ||||
| @@ -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<TestCase> getMatchingTestCases( std::string const& rawTestSpec ) const { | ||||
|             std::vector<TestCase> matchingTests; | ||||
|             getMatchingTestCases( rawTestSpec, matchingTests ); | ||||
|             return matchingTests; | ||||
|         } | ||||
|  | ||||
|         // !TBD deprecated | ||||
|         virtual void getMatchingTestCases( std::string const& rawTestSpec, std::vector<TestCase>& matchingTestsOut ) const { | ||||
|             TestCaseFilter filter( rawTestSpec ); | ||||
|  | ||||
|             std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(); | ||||
|             std::vector<TestCase>::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<TestCase>& matchingTestCases ) const { | ||||
|             for( std::vector<TestCase>::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<TestCase>& matchingTestsOut ) const { | ||||
|             std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(); | ||||
|             std::vector<TestCase>::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<TestCase>& matchingTestCases ) const { | ||||
|             if( config.filters().empty() ) | ||||
|                 return getFilteredTests( TestCaseFilters( "empty" ), config, matchingTestCases ); | ||||
|  | ||||
|             for( std::vector<TestCaseFilters>::const_iterator   it = config.filters().begin(), | ||||
|                                                                 itEnd = config.filters().end(); | ||||
|                     it != itEnd; | ||||
|                     ++it ) | ||||
|                 getFilteredTests( *it, config, matchingTestCases ); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash