From fc1baac7f591e7d161fb7f2f30db33da51f94cb6 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Sat, 15 Sep 2012 17:53:27 +0100 Subject: [PATCH] First cut of tags support --- include/catch_runner.hpp | 1 - include/internal/catch_test_case_info.h | 4 ++ include/internal/catch_test_case_info.hpp | 45 +++++++++++++- include/internal/catch_test_spec.h | 4 ++ projects/SelfTest/MiscTests.cpp | 5 ++ projects/SelfTest/TestMain.cpp | 51 +++++++++++++++- single_include/catch.hpp | 71 ++++++++++++++++++++--- 7 files changed, 168 insertions(+), 13 deletions(-) diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index e0c7b34e..c849ccb2 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -35,7 +35,6 @@ namespace Catch { std::vector filterGroups = m_config.filters; if( filterGroups.empty() ) { TestCaseFilters filterGroup( "" ); - filterGroup.addFilter( TestCaseFilter( "./*", IfFilterMatches::ExcludeTests ) ); filterGroups.push_back( filterGroup ); } diff --git a/include/internal/catch_test_case_info.h b/include/internal/catch_test_case_info.h index 4fbfaa65..1aebf0cf 100644 --- a/include/internal/catch_test_case_info.h +++ b/include/internal/catch_test_case_info.h @@ -11,6 +11,7 @@ #include "catch_common.h" #include +#include namespace Catch { @@ -34,6 +35,8 @@ namespace Catch { const std::string& getDescription() const; const SourceLineInfo& getLineInfo() const; bool isHidden() const; + bool hasTag( const std::string& tag ) const; + const std::set& tags() const; void swap( TestCaseInfo& other ); bool operator == ( const TestCaseInfo& other ) const; @@ -44,6 +47,7 @@ namespace Catch { Ptr m_test; std::string m_name; std::string m_description; + std::set m_tags; SourceLineInfo m_lineInfo; bool m_isHidden; }; diff --git a/include/internal/catch_test_case_info.hpp b/include/internal/catch_test_case_info.hpp index fa8bd40f..be4db842 100644 --- a/include/internal/catch_test_case_info.hpp +++ b/include/internal/catch_test_case_info.hpp @@ -13,6 +13,36 @@ namespace Catch { + namespace { + void extractTags( std::string& str, std::set& tags ) { + std::string remainder; + std::size_t last = 0; + std::size_t begin = str.find_first_of( '[' ); + while( begin != std::string::npos ) { + std::size_t end = str.find_first_of( ']', begin ); + if( end != std::string::npos ) { + std::string tag = str.substr( begin+1, end-begin-1 ); + tags.insert( tag ); + if( begin - last > 0 ) + remainder += str.substr( last, begin-last ); + last = end+1; + } + else if( begin != str.size()-1 ) { + end = begin+1; + } + else { + break; + } + begin = str.find_first_of( '[', end ); + } + if( !tags.empty() ) { + if( last < str.size() ) + str = remainder + str.substr( last ); + else + str = remainder; + } + } + } TestCaseInfo::TestCaseInfo( ITestCase* testCase, const char* name, const char* description, @@ -22,7 +52,11 @@ namespace Catch { m_description( description ), m_lineInfo( lineInfo ), m_isHidden( startsWith( name, "./" ) ) - {} + { + extractTags( m_description, m_tags ); + if( hasTag( "hide" ) ) + m_isHidden = true; + } TestCaseInfo::TestCaseInfo() : m_test( NULL ), @@ -35,6 +69,7 @@ namespace Catch { : m_test( other.m_test ), m_name( name ), m_description( other.m_description ), + m_tags( other.m_tags ), m_lineInfo( other.m_lineInfo ), m_isHidden( other.m_isHidden ) {} @@ -43,6 +78,7 @@ namespace Catch { : m_test( other.m_test ), m_name( other.m_name ), m_description( other.m_description ), + m_tags( other.m_tags ), m_lineInfo( other.m_lineInfo ), m_isHidden( other.m_isHidden ) {} @@ -67,6 +103,13 @@ namespace Catch { return m_isHidden; } + bool TestCaseInfo::hasTag( const std::string& tag ) const { + return m_tags.find( tag ) != m_tags.end(); + } + const std::set& TestCaseInfo::tags() const { + return m_tags; + } + void TestCaseInfo::swap( TestCaseInfo& other ) { m_test.swap( other.m_test ); m_name.swap( other.m_name ); diff --git a/include/internal/catch_test_spec.h b/include/internal/catch_test_spec.h index aed36b85..3a1daeec 100644 --- a/include/internal/catch_test_spec.h +++ b/include/internal/catch_test_spec.h @@ -123,6 +123,10 @@ namespace Catch { if( it == itEnd ) return false; } + else if( m_exclusionFilters.empty() ) { + return !testCase.isHidden(); + } + std::vector::const_iterator it = m_exclusionFilters.begin(); std::vector::const_iterator itEnd = m_exclusionFilters.end(); for(; it != itEnd; ++it ) diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index 7ec1f017..a60428ee 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -293,3 +293,8 @@ TEST_CASE( "example/factorial", "The Factorial function should return the factor TEST_CASE( "empty", "An empty test with no assertions" ) { } + +TEST_CASE( "Nice descriptive name", "[tag1][tag2][hide]" ) +{ + WARN( "This one ran" ); +} diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index 9575cfa1..f745f69b 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -330,7 +330,52 @@ TEST_CASE( "selftest/option parsers", "" ) REQUIRE( config.filters.size() == 1 ); REQUIRE( config.filters[0].shouldInclude( makeTestCase( "notIncluded" ) ) == false ); REQUIRE( config.filters[0].shouldInclude( makeTestCase( "test1" ) ) ); - - - +} + +TEST_CASE( "selftest/tags", "" ) { + + SECTION( "one tag", "" ) { + Catch::TestCaseInfo oneTag( NULL, "test", "[one]", CATCH_INTERNAL_LINEINFO ); + + CHECK( oneTag.getDescription() == "" ); + CHECK( oneTag.hasTag( "one" ) ); + CHECK( oneTag.tags().size() == 1 ); + } + + SECTION( "two tags", "" ) { + Catch::TestCaseInfo twoTags( NULL, "test", "[one][two]", CATCH_INTERNAL_LINEINFO ); + + CHECK( twoTags.getDescription() == "" ); + CHECK( twoTags.hasTag( "one" ) ); + CHECK( twoTags.hasTag( "two" ) ); + CHECK( twoTags.hasTag( "three" ) == false ); + CHECK( twoTags.tags().size() == 2 ); + } + + SECTION( "one tag with characters either side", "" ) { + + Catch::TestCaseInfo oneTagWithExtras( NULL, "test", "12[one]34", CATCH_INTERNAL_LINEINFO ); + CHECK( oneTagWithExtras.getDescription() == "1234" ); + CHECK( oneTagWithExtras.hasTag( "one" ) ); + CHECK( oneTagWithExtras.hasTag( "two" ) == false ); + CHECK( oneTagWithExtras.tags().size() == 1 ); + } + + SECTION( "start of a tag, but not closed", "" ) { + + Catch::TestCaseInfo oneTagOpen( NULL, "test", "[one", CATCH_INTERNAL_LINEINFO ); + + CHECK( oneTagOpen.getDescription() == "[one" ); + CHECK( oneTagOpen.hasTag( "one" ) == false ); + CHECK( oneTagOpen.tags().size() == 0 ); + } + + SECTION( "hidden", "" ) { + Catch::TestCaseInfo oneTag( NULL, "test", "[hide]", CATCH_INTERNAL_LINEINFO ); + + CHECK( oneTag.getDescription() == "" ); + CHECK( oneTag.hasTag( "hide" ) ); + CHECK( oneTag.isHidden() ); + } + } diff --git a/single_include/catch.hpp b/single_include/catch.hpp index e9574f98..ba9a0797 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,5 +1,5 @@ /* - * Generated: 2012-09-09 11:44:01.394438 + * Generated: 2012-09-15 17:50:31.695760 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -1644,6 +1644,7 @@ using namespace Generators; #define TWOBLUECUBES_CATCH_TESTCASEINFO_H_INCLUDED #include +#include namespace Catch { @@ -1666,6 +1667,8 @@ namespace Catch { const std::string& getDescription() const; const SourceLineInfo& getLineInfo() const; bool isHidden() const; + bool hasTag( const std::string& tag ) const; + const std::set& tags() const; void swap( TestCaseInfo& other ); bool operator == ( const TestCaseInfo& other ) const; @@ -1676,7 +1679,9 @@ namespace Catch { Ptr m_test; std::string m_name; std::string m_description; + std::set m_tags; SourceLineInfo m_lineInfo; + bool m_isHidden; }; } @@ -1793,6 +1798,10 @@ namespace Catch { if( it == itEnd ) return false; } + else if( m_exclusionFilters.empty() ) { + return !testCase.isHidden(); + } + std::vector::const_iterator it = m_exclusionFilters.begin(); std::vector::const_iterator itEnd = m_exclusionFilters.end(); for(; it != itEnd; ++it ) @@ -3697,7 +3706,6 @@ namespace Catch { std::vector filterGroups = m_config.filters; if( filterGroups.empty() ) { TestCaseFilters filterGroup( "" ); - filterGroup.addFilter( TestCaseFilter( "./*", IfFilterMatches::ExcludeTests ) ); filterGroups.push_back( filterGroup ); } @@ -4738,6 +4746,36 @@ namespace Catch { namespace Catch { + namespace { + void extractTags( std::string& str, std::set& tags ) { + std::string remainder; + std::size_t last = 0; + std::size_t begin = str.find_first_of( '[' ); + while( begin != std::string::npos ) { + std::size_t end = str.find_first_of( ']', begin ); + if( end != std::string::npos ) { + std::string tag = str.substr( begin+1, end-begin-1 ); + tags.insert( tag ); + if( begin - last > 0 ) + remainder += str.substr( last, begin-last ); + last = end+1; + } + else if( begin != str.size()-1 ) { + end = begin+1; + } + else { + break; + } + begin = str.find_first_of( '[', end ); + } + if( !tags.empty() ) { + if( last < str.size() ) + str = remainder + str.substr( last ); + else + str = remainder; + } + } + } TestCaseInfo::TestCaseInfo( ITestCase* testCase, const char* name, const char* description, @@ -4745,27 +4783,37 @@ namespace Catch { : m_test( testCase ), m_name( name ), m_description( description ), - m_lineInfo( lineInfo ) - {} + m_lineInfo( lineInfo ), + m_isHidden( startsWith( name, "./" ) ) + { + extractTags( m_description, m_tags ); + if( hasTag( "hide" ) ) + m_isHidden = true; + } TestCaseInfo::TestCaseInfo() : m_test( NULL ), m_name(), - m_description() + m_description(), + m_isHidden( false ) {} TestCaseInfo::TestCaseInfo( const TestCaseInfo& other, const std::string& name ) : m_test( other.m_test ), m_name( name ), m_description( other.m_description ), - m_lineInfo( other.m_lineInfo ) + m_tags( other.m_tags ), + m_lineInfo( other.m_lineInfo ), + m_isHidden( other.m_isHidden ) {} TestCaseInfo::TestCaseInfo( const TestCaseInfo& other ) : m_test( other.m_test ), m_name( other.m_name ), m_description( other.m_description ), - m_lineInfo( other.m_lineInfo ) + m_tags( other.m_tags ), + m_lineInfo( other.m_lineInfo ), + m_isHidden( other.m_isHidden ) {} void TestCaseInfo::invoke() const { @@ -4785,7 +4833,14 @@ namespace Catch { } bool TestCaseInfo::isHidden() const { - return m_name.size() >= 2 && m_name[0] == '.' && m_name[1] == '/'; + return m_isHidden; + } + + bool TestCaseInfo::hasTag( const std::string& tag ) const { + return m_tags.find( tag ) != m_tags.end(); + } + const std::set& TestCaseInfo::tags() const { + return m_tags; } void TestCaseInfo::swap( TestCaseInfo& other ) {