From 930f49a641aa6a495d264d7b5e7c007734da0b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Tue, 5 Nov 2019 23:28:47 +0100 Subject: [PATCH] Split [.foo] into [.][foo] when parsing test specs b77cec05c0 fixed this problem for tagging tests, so that a test case tagged with `[.foo]` would be parsed as tagged with `[.][foo]`. This does the same for the test spec parsing. Fixes #1798 --- include/internal/catch_test_spec_parser.cpp | 72 ++++++++++++++++--- include/internal/catch_test_spec_parser.h | 33 +++------ .../Baselines/compact.sw.approved.txt | 6 ++ .../Baselines/console.std.approved.txt | 2 +- .../Baselines/console.sw.approved.txt | 46 +++++++++++- .../SelfTest/Baselines/junit.sw.approved.txt | 4 +- .../Baselines/sonarqube.sw.approved.txt | 2 + .../SelfTest/Baselines/xml.sw.approved.txt | 60 +++++++++++++++- .../IntrospectiveTests/CmdLine.tests.cpp | 18 +++-- 9 files changed, 201 insertions(+), 42 deletions(-) diff --git a/include/internal/catch_test_spec_parser.cpp b/include/internal/catch_test_spec_parser.cpp index b872b191..dad15c01 100644 --- a/include/internal/catch_test_spec_parser.cpp +++ b/include/internal/catch_test_spec_parser.cpp @@ -20,10 +20,10 @@ namespace Catch { m_substring.reserve(m_arg.size()); m_patternName.reserve(m_arg.size()); m_realPatternPos = 0; - + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) //if visitChar fails - if( !visitChar( m_arg[m_pos] ) ){ + if( !visitChar( m_arg[m_pos] ) ){ m_testSpec.m_invalidArgs.push_back(arg); break; } @@ -113,9 +113,9 @@ namespace Catch { switch( m_mode ) { case Name: case QuotedName: - return addPattern(); + return addNamePattern(); case Tag: - return addPattern(); + return addTagPattern(); case EscapedName: revertBackToLastMode(); return; @@ -156,12 +156,12 @@ namespace Catch { void TestSpecParser::saveLastMode() { lastMode = m_mode; } - + void TestSpecParser::revertBackToLastMode() { m_mode = lastMode; } - - bool TestSpecParser::separate() { + + bool TestSpecParser::separate() { if( (m_mode==QuotedName) || (m_mode==Tag) ){ //invalid argument, signal failure to previous scope. m_mode = None; @@ -174,7 +174,63 @@ namespace Catch { addFilter(); return true; //success } - + + std::string TestSpecParser::preprocessPattern() { + std::string token = m_patternName; + for (std::size_t i = 0; i < m_escapeChars.size(); ++i) + token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1); + m_escapeChars.clear(); + if (startsWith(token, "exclude:")) { + m_exclusion = true; + token = token.substr(8); + } + + m_patternName.clear(); + + return token; + } + + void TestSpecParser::addNamePattern() { + auto token = preprocessPattern(); + + if (!token.empty()) { + TestSpec::PatternPtr pattern = std::make_shared(token, m_substring); + if (m_exclusion) + pattern = std::make_shared(pattern); + m_currentFilter.m_patterns.push_back(pattern); + } + m_substring.clear(); + m_exclusion = false; + m_mode = None; + } + + void TestSpecParser::addTagPattern() { + auto token = preprocessPattern(); + + if (!token.empty()) { + // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo]) + // we have to create a separate hide tag and shorten the real one + if (token.size() > 1 && token[0] == '.') { + token.erase(token.begin()); + TestSpec::PatternPtr pattern = std::make_shared(".", m_substring); + if (m_exclusion) { + pattern = std::make_shared(pattern); + } + m_currentFilter.m_patterns.push_back(pattern); + } + + TestSpec::PatternPtr pattern = std::make_shared(token, m_substring); + + if (m_exclusion) { + pattern = std::make_shared(pattern); + } + m_currentFilter.m_patterns.push_back(pattern); + } + m_substring.clear(); + m_exclusion = false; + m_mode = None; + } + TestSpec parseTestSpec( std::string const& arg ) { return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); } diff --git a/include/internal/catch_test_spec_parser.h b/include/internal/catch_test_spec_parser.h index 179d3532..250d7c16 100644 --- a/include/internal/catch_test_spec_parser.h +++ b/include/internal/catch_test_spec_parser.h @@ -53,35 +53,20 @@ namespace Catch { void revertBackToLastMode(); void addFilter(); bool separate(); - - template - void addPattern() { - std::string token = m_patternName; - for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) - token = token.substr( 0, m_escapeChars[i] - i ) + token.substr( m_escapeChars[i] -i +1 ); - m_escapeChars.clear(); - if( startsWith( token, "exclude:" ) ) { - m_exclusion = true; - token = token.substr( 8 ); - } - if( !token.empty() ) { - TestSpec::PatternPtr pattern = std::make_shared( token, m_substring ); - if( m_exclusion ) - pattern = std::make_shared( pattern ); - m_currentFilter.m_patterns.push_back( pattern ); - } - m_substring.clear(); - m_patternName.clear(); - m_exclusion = false; - m_mode = None; - } - + + // Handles common preprocessing of the pattern for name/tag patterns + std::string preprocessPattern(); + // Adds the current pattern as a test name + void addNamePattern(); + // Adds the current pattern as a tag + void addTagPattern(); + inline void addCharToPattern(char c) { m_substring += c; m_patternName += c; m_realPatternPos++; } - + }; TestSpec parseTestSpec( std::string const& arg ); diff --git a/projects/SelfTest/Baselines/compact.sw.approved.txt b/projects/SelfTest/Baselines/compact.sw.approved.txt index e10e63b0..a74faf9b 100644 --- a/projects/SelfTest/Baselines/compact.sw.approved.txt +++ b/projects/SelfTest/Baselines/compact.sw.approved.txt @@ -1027,6 +1027,12 @@ CmdLine.tests.cpp:: passed: spec.matches( fakeTestCase( " aardvark CmdLine.tests.cpp:: passed: spec.matches( fakeTestCase( " aardvark " ) ) for: true CmdLine.tests.cpp:: passed: spec.matches( fakeTestCase( "aardvark " ) ) for: true CmdLine.tests.cpp:: passed: spec.matches( fakeTestCase( "aardvark" ) ) for: true +CmdLine.tests.cpp:: passed: spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) for: true +CmdLine.tests.cpp:: passed: !(spec.matches(fakeTestCase("only foo", "[foo]"))) for: !false +CmdLine.tests.cpp:: passed: !(spec.matches(fakeTestCase("hidden and foo", "[.][foo]"))) for: !false +CmdLine.tests.cpp:: passed: !(spec.matches(fakeTestCase("only foo", "[foo]"))) for: !false +CmdLine.tests.cpp:: passed: !(spec.matches(fakeTestCase("only hidden", "[.]"))) for: !false +CmdLine.tests.cpp:: passed: spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")) for: true Condition.tests.cpp:: passed: p == 0 for: 0 == 0 Condition.tests.cpp:: passed: p == pNULL for: 0 == 0 Condition.tests.cpp:: passed: p != 0 for: 0x != 0 diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 039ecc09..4db2b90a 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -1381,5 +1381,5 @@ due to unexpected exception with message: =============================================================================== test cases: 304 | 230 passed | 70 failed | 4 failed as expected -assertions: 1653 | 1501 passed | 131 failed | 21 failed as expected +assertions: 1659 | 1507 passed | 131 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index e3684cc8..8de4bcaa 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -7361,6 +7361,50 @@ CmdLine.tests.cpp:: PASSED: with expansion: true +------------------------------------------------------------------------------- +Parse test names and tags + Shortened hide tags are split apart when parsing +------------------------------------------------------------------------------- +CmdLine.tests.cpp: +............................................................................... + +CmdLine.tests.cpp:: PASSED: + CHECK( spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) ) +with expansion: + true + +CmdLine.tests.cpp:: PASSED: + CHECK_FALSE( spec.matches(fakeTestCase("only foo", "[foo]")) ) +with expansion: + !false + +------------------------------------------------------------------------------- +Parse test names and tags + Shortened hide tags also properly handle exclusion +------------------------------------------------------------------------------- +CmdLine.tests.cpp: +............................................................................... + +CmdLine.tests.cpp:: PASSED: + CHECK_FALSE( spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) ) +with expansion: + !false + +CmdLine.tests.cpp:: PASSED: + CHECK_FALSE( spec.matches(fakeTestCase("only foo", "[foo]")) ) +with expansion: + !false + +CmdLine.tests.cpp:: PASSED: + CHECK_FALSE( spec.matches(fakeTestCase("only hidden", "[.]")) ) +with expansion: + !false + +CmdLine.tests.cpp:: PASSED: + CHECK( spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")) ) +with expansion: + true + ------------------------------------------------------------------------------- Pointers can be compared to null ------------------------------------------------------------------------------- @@ -13208,5 +13252,5 @@ Misc.tests.cpp:: PASSED: =============================================================================== test cases: 304 | 214 passed | 86 failed | 4 failed as expected -assertions: 1670 | 1501 passed | 148 failed | 21 failed as expected +assertions: 1676 | 1507 passed | 148 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index fcf933dd..41065c4e 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -982,6 +982,8 @@ Message.tests.cpp: + + diff --git a/projects/SelfTest/Baselines/sonarqube.sw.approved.txt b/projects/SelfTest/Baselines/sonarqube.sw.approved.txt index 0bd44a18..f1b9fe98 100644 --- a/projects/SelfTest/Baselines/sonarqube.sw.approved.txt +++ b/projects/SelfTest/Baselines/sonarqube.sw.approved.txt @@ -35,6 +35,8 @@ + + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index fa8c3084..cf7413e3 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -8019,7 +8019,7 @@ Nor would this - +
@@ -9279,6 +9279,60 @@ Nor would this
+
+ + + spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) + + + true + + + + + !(spec.matches(fakeTestCase("only foo", "[foo]"))) + + + !false + + + +
+
+ + + !(spec.matches(fakeTestCase("hidden and foo", "[.][foo]"))) + + + !false + + + + + !(spec.matches(fakeTestCase("only foo", "[foo]"))) + + + !false + + + + + !(spec.matches(fakeTestCase("only hidden", "[.]"))) + + + !false + + + + + spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")) + + + true + + + +
@@ -15790,7 +15844,7 @@ loose text artifact - + - + diff --git a/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp b/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp index 60eb97af..c1fd90e3 100644 --- a/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp +++ b/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp @@ -17,7 +17,7 @@ inline Catch::TestCase fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCase(nullptr, "", { name, desc }, CATCH_INTERNAL_LINEINFO); } -TEST_CASE( "Parse test names and tags" ) { +TEST_CASE( "Parse test names and tags", "[command-line][test-spec]" ) { using Catch::parseTestSpec; using Catch::TestSpec; @@ -269,7 +269,6 @@ TEST_CASE( "Parse test names and tags" ) { CHECK( spec.matches( fakeTestCase( " aardvark " ) ) ); CHECK( spec.matches( fakeTestCase( "aardvark " ) ) ); CHECK( spec.matches( fakeTestCase( "aardvark" ) ) ); - } SECTION( "Leading and trailing spaces in test name" ) { TestSpec spec = parseTestSpec( "aardvark" ); @@ -278,7 +277,18 @@ TEST_CASE( "Parse test names and tags" ) { CHECK( spec.matches( fakeTestCase( " aardvark " ) ) ); CHECK( spec.matches( fakeTestCase( "aardvark " ) ) ); CHECK( spec.matches( fakeTestCase( "aardvark" ) ) ); - + } + SECTION("Shortened hide tags are split apart when parsing") { + TestSpec spec = parseTestSpec("[.foo]"); + CHECK(spec.matches(fakeTestCase("hidden and foo", "[.][foo]"))); + CHECK_FALSE(spec.matches(fakeTestCase("only foo", "[foo]"))); + } + SECTION("Shortened hide tags also properly handle exclusion") { + TestSpec spec = parseTestSpec("~[.foo]"); + CHECK_FALSE(spec.matches(fakeTestCase("hidden and foo", "[.][foo]"))); + CHECK_FALSE(spec.matches(fakeTestCase("only foo", "[foo]"))); + CHECK_FALSE(spec.matches(fakeTestCase("only hidden", "[.]"))); + CHECK(spec.matches(fakeTestCase("neither foo nor hidden", "[bar]"))); } } @@ -486,7 +496,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" REQUIRE(config.benchmarkSamples == 200); } - + SECTION("resamples") { CHECK(cli.parse({ "test", "--benchmark-resamples=20000" }));