mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	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 #1798This commit is contained in:
		| @@ -113,9 +113,9 @@ namespace Catch { | ||||
|         switch( m_mode ) { | ||||
|         case Name: | ||||
|         case QuotedName: | ||||
|             return addPattern<TestSpec::NamePattern>(); | ||||
|             return addNamePattern(); | ||||
|         case Tag: | ||||
|             return addPattern<TestSpec::TagPattern>(); | ||||
|             return addTagPattern(); | ||||
|         case EscapedName: | ||||
|             revertBackToLastMode(); | ||||
|             return; | ||||
| @@ -175,6 +175,63 @@ namespace Catch { | ||||
|       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()) { | ||||
|             if (m_exclusion) { | ||||
|                 m_currentFilter.m_forbidden.emplace_back(std::make_unique<TestSpec::NamePattern>(token, m_substring)); | ||||
|             } else { | ||||
|                 m_currentFilter.m_required.emplace_back(std::make_unique<TestSpec::NamePattern>(token, m_substring)); | ||||
|             } | ||||
|         } | ||||
|         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()); | ||||
|                 if (m_exclusion) { | ||||
|                     m_currentFilter.m_forbidden.emplace_back(std::make_unique<TestSpec::TagPattern>(".", m_substring)); | ||||
|                     m_currentFilter.m_forbidden.emplace_back(std::make_unique<TestSpec::TagPattern>(token, m_substring)); | ||||
|                 } else { | ||||
|                     m_currentFilter.m_required.emplace_back(std::make_unique<TestSpec::TagPattern>(".", m_substring)); | ||||
|                     m_currentFilter.m_required.emplace_back(std::make_unique<TestSpec::TagPattern>(token, m_substring)); | ||||
|                 } | ||||
|             } | ||||
|             if (m_exclusion) { | ||||
|                 m_currentFilter.m_forbidden.emplace_back(std::make_unique<TestSpec::TagPattern>(token, m_substring)); | ||||
|             } else { | ||||
|                 m_currentFilter.m_required.emplace_back(std::make_unique<TestSpec::TagPattern>(token, m_substring)); | ||||
|             } | ||||
|         } | ||||
|         m_substring.clear(); | ||||
|         m_exclusion = false; | ||||
|         m_mode = None; | ||||
|     } | ||||
|  | ||||
|     TestSpec parseTestSpec( std::string const& arg ) { | ||||
|         return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); | ||||
|     } | ||||
|   | ||||
| @@ -54,28 +54,12 @@ namespace Catch { | ||||
|         void addFilter(); | ||||
|         bool separate(); | ||||
|  | ||||
|         template<typename T> | ||||
|         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() ) { | ||||
|                 if (m_exclusion) { | ||||
|                     m_currentFilter.m_forbidden.emplace_back(std::make_unique<T>(token, m_substring)); | ||||
|                 } else { | ||||
|                     m_currentFilter.m_required.emplace_back(std::make_unique<T>(token, m_substring)); | ||||
|                 } | ||||
|             } | ||||
|             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; | ||||
|   | ||||
| @@ -1028,6 +1028,12 @@ CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( "  aardvar | ||||
| CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( " aardvark " ) ) for: true | ||||
| CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( "aardvark " ) ) for: true | ||||
| CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( "aardvark" ) ) for: true | ||||
| CmdLine.tests.cpp:<line number>: passed: spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) for: true | ||||
| CmdLine.tests.cpp:<line number>: passed: !(spec.matches(*fakeTestCase("only foo", "[foo]"))) for: !false | ||||
| CmdLine.tests.cpp:<line number>: passed: !(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]"))) for: !false | ||||
| CmdLine.tests.cpp:<line number>: passed: !(spec.matches(*fakeTestCase("only foo", "[foo]"))) for: !false | ||||
| CmdLine.tests.cpp:<line number>: passed: !(spec.matches(*fakeTestCase("only hidden", "[.]"))) for: !false | ||||
| CmdLine.tests.cpp:<line number>: passed: spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")) for: true | ||||
| Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0 | ||||
| Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0 | ||||
| Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 0 | ||||
|   | ||||
| @@ -1381,5 +1381,5 @@ due to unexpected exception with message: | ||||
|  | ||||
| =============================================================================== | ||||
| test cases:  320 |  246 passed |  70 failed |  4 failed as expected | ||||
| assertions: 1776 | 1624 passed | 131 failed | 21 failed as expected | ||||
| assertions: 1782 | 1630 passed | 131 failed | 21 failed as expected | ||||
|  | ||||
|   | ||||
| @@ -7370,6 +7370,50 @@ CmdLine.tests.cpp:<line number>: PASSED: | ||||
| with expansion: | ||||
|   true | ||||
|  | ||||
| ------------------------------------------------------------------------------- | ||||
| Parse test names and tags | ||||
|   Shortened hide tags are split apart when parsing | ||||
| ------------------------------------------------------------------------------- | ||||
| CmdLine.tests.cpp:<line number> | ||||
| ............................................................................... | ||||
|  | ||||
| CmdLine.tests.cpp:<line number>: PASSED: | ||||
|   CHECK( spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) ) | ||||
| with expansion: | ||||
|   true | ||||
|  | ||||
| CmdLine.tests.cpp:<line number>: 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:<line number> | ||||
| ............................................................................... | ||||
|  | ||||
| CmdLine.tests.cpp:<line number>: PASSED: | ||||
|   CHECK_FALSE( spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) ) | ||||
| with expansion: | ||||
|   !false | ||||
|  | ||||
| CmdLine.tests.cpp:<line number>: PASSED: | ||||
|   CHECK_FALSE( spec.matches(*fakeTestCase("only foo", "[foo]")) ) | ||||
| with expansion: | ||||
|   !false | ||||
|  | ||||
| CmdLine.tests.cpp:<line number>: PASSED: | ||||
|   CHECK_FALSE( spec.matches(*fakeTestCase("only hidden", "[.]")) ) | ||||
| with expansion: | ||||
|   !false | ||||
|  | ||||
| CmdLine.tests.cpp:<line number>: PASSED: | ||||
|   CHECK( spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")) ) | ||||
| with expansion: | ||||
|   true | ||||
|  | ||||
| ------------------------------------------------------------------------------- | ||||
| Pointers can be compared to null | ||||
| ------------------------------------------------------------------------------- | ||||
| @@ -13961,5 +14005,5 @@ Misc.tests.cpp:<line number>: PASSED: | ||||
|  | ||||
| =============================================================================== | ||||
| test cases:  320 |  230 passed |  86 failed |  4 failed as expected | ||||
| assertions: 1793 | 1624 passed | 148 failed | 21 failed as expected | ||||
| assertions: 1799 | 1630 passed | 148 failed | 21 failed as expected | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <testsuitesloose text artifact | ||||
| > | ||||
|   <testsuite name="<exe-name>" errors="17" failures="132" tests="1794" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}"> | ||||
|   <testsuite name="<exe-name>" errors="17" failures="132" tests="1800" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}"> | ||||
|     <properties> | ||||
|       <property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/> | ||||
|       <property name="random-seed" value="1"/> | ||||
| @@ -983,6 +983,8 @@ Message.tests.cpp:<line number> | ||||
|     <testcase classname="<exe-name>.global" name="Parse test names and tags/quoted string followed by tag exclusion" time="{duration}"/> | ||||
|     <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test spec" time="{duration}"/> | ||||
|     <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test name" time="{duration}"/> | ||||
|     <testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags are split apart when parsing" time="{duration}"/> | ||||
|     <testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags also properly handle exclusion" time="{duration}"/> | ||||
|     <testcase classname="<exe-name>.global" name="Pointers can be compared to null" time="{duration}"/> | ||||
|     <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Floats" time="{duration}"/> | ||||
|     <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Double" time="{duration}"/> | ||||
|   | ||||
| @@ -35,6 +35,8 @@ | ||||
|     <testCase name="Parse test names and tags/quoted string followed by tag exclusion" duration="{duration}"/> | ||||
|     <testCase name="Parse test names and tags/Leading and trailing spaces in test spec" duration="{duration}"/> | ||||
|     <testCase name="Parse test names and tags/Leading and trailing spaces in test name" duration="{duration}"/> | ||||
|     <testCase name="Parse test names and tags/Shortened hide tags are split apart when parsing" duration="{duration}"/> | ||||
|     <testCase name="Parse test names and tags/Shortened hide tags also properly handle exclusion" duration="{duration}"/> | ||||
|     <testCase name="Process can be configured on command line/empty args don't cause a crash" duration="{duration}"/> | ||||
|     <testCase name="Process can be configured on command line/default - no arguments" duration="{duration}"/> | ||||
|     <testCase name="Process can be configured on command line/test lists/Specify one test case using" duration="{duration}"/> | ||||
|   | ||||
| @@ -1978,6 +1978,18 @@ ok {test-number} - spec.matches( *fakeTestCase( " aardvark " ) ) for: true | ||||
| ok {test-number} - spec.matches( *fakeTestCase( "aardvark " ) ) for: true | ||||
| # Parse test names and tags | ||||
| ok {test-number} - spec.matches( *fakeTestCase( "aardvark" ) ) for: true | ||||
| # Parse test names and tags | ||||
| ok {test-number} - spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) for: true | ||||
| # Parse test names and tags | ||||
| ok {test-number} - !(spec.matches(*fakeTestCase("only foo", "[foo]"))) for: !false | ||||
| # Parse test names and tags | ||||
| ok {test-number} - !(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]"))) for: !false | ||||
| # Parse test names and tags | ||||
| ok {test-number} - !(spec.matches(*fakeTestCase("only foo", "[foo]"))) for: !false | ||||
| # Parse test names and tags | ||||
| ok {test-number} - !(spec.matches(*fakeTestCase("only hidden", "[.]"))) for: !false | ||||
| # Parse test names and tags | ||||
| ok {test-number} - spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")) for: true | ||||
| # Pointers can be compared to null | ||||
| ok {test-number} - p == 0 for: 0 == 0 | ||||
| # Pointers can be compared to null | ||||
| @@ -2928,9 +2940,9 @@ not ok {test-number} - unexpected exception with message: 'expected exception'; | ||||
| # When unchecked exceptions are thrown from sections they are always failures | ||||
| not ok {test-number} - unexpected exception with message: 'unexpected exception' | ||||
| # Where the LHS is not a simple value | ||||
| warning 1461 - 'Uncomment the code in this test to check that it gives a sensible compiler error' | ||||
| warning 1467 - 'Uncomment the code in this test to check that it gives a sensible compiler error' | ||||
| # Where there is more to the expression after the RHS | ||||
| warning 1462 - 'Uncomment the code in this test to check that it gives a sensible compiler error' | ||||
| warning 1468 - 'Uncomment the code in this test to check that it gives a sensible compiler error' | ||||
| # X/level/0/a | ||||
| ok {test-number} - | ||||
| # X/level/0/b | ||||
| @@ -3197,9 +3209,9 @@ ok {test-number} - s.result == 17 for: 17 == 17 | ||||
| # measure | ||||
| ok {test-number} - s.iterations == 1 for: 1 == 1 | ||||
| # mix info, unscoped info and warning | ||||
| warning 1595 - 'info' with 2 messages: 'unscoped info' and 'and warn may mix' | ||||
| warning 1601 - 'info' with 2 messages: 'unscoped info' and 'and warn may mix' | ||||
| # mix info, unscoped info and warning | ||||
| warning 1596 - 'info' with 2 messages: 'unscoped info' and 'they are not cleared after warnings' | ||||
| warning 1602 - 'info' with 2 messages: 'unscoped info' and 'they are not cleared after warnings' | ||||
| # more nested SECTION tests | ||||
| not ok {test-number} - a == b for: 1 == 2 | ||||
| # more nested SECTION tests | ||||
| @@ -3578,5 +3590,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0 | ||||
| ok {test-number} - | ||||
| # xmlentitycheck | ||||
| ok {test-number} - | ||||
| 1..1785 | ||||
| 1..1791 | ||||
|  | ||||
|   | ||||
| @@ -8025,7 +8025,7 @@ Nor would this | ||||
|       </Section> | ||||
|       <OverallResult success="false"/> | ||||
|     </TestCase> | ||||
|     <TestCase name="Parse test names and tags" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|     <TestCase name="Parse test names and tags" tags="[command-line][test-spec]" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|       <Section name="Empty test spec should have no filters" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|         <Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|           <Original> | ||||
| @@ -9285,6 +9285,60 @@ Nor would this | ||||
|         </Expression> | ||||
|         <OverallResults successes="5" failures="0" expectedFailures="0"/> | ||||
|       </Section> | ||||
|       <Section name="Shortened hide tags are split apart when parsing" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|         <Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|           <Original> | ||||
|             spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) | ||||
|           </Original> | ||||
|           <Expanded> | ||||
|             true | ||||
|           </Expanded> | ||||
|         </Expression> | ||||
|         <Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|           <Original> | ||||
|             !(spec.matches(*fakeTestCase("only foo", "[foo]"))) | ||||
|           </Original> | ||||
|           <Expanded> | ||||
|             !false | ||||
|           </Expanded> | ||||
|         </Expression> | ||||
|         <OverallResults successes="2" failures="0" expectedFailures="0"/> | ||||
|       </Section> | ||||
|       <Section name="Shortened hide tags also properly handle exclusion" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|         <Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|           <Original> | ||||
|             !(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]"))) | ||||
|           </Original> | ||||
|           <Expanded> | ||||
|             !false | ||||
|           </Expanded> | ||||
|         </Expression> | ||||
|         <Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|           <Original> | ||||
|             !(spec.matches(*fakeTestCase("only foo", "[foo]"))) | ||||
|           </Original> | ||||
|           <Expanded> | ||||
|             !false | ||||
|           </Expanded> | ||||
|         </Expression> | ||||
|         <Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|           <Original> | ||||
|             !(spec.matches(*fakeTestCase("only hidden", "[.]"))) | ||||
|           </Original> | ||||
|           <Expanded> | ||||
|             !false | ||||
|           </Expanded> | ||||
|         </Expression> | ||||
|         <Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > | ||||
|           <Original> | ||||
|             spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")) | ||||
|           </Original> | ||||
|           <Expanded> | ||||
|             true | ||||
|           </Expanded> | ||||
|         </Expression> | ||||
|         <OverallResults successes="4" failures="0" expectedFailures="0"/> | ||||
|       </Section> | ||||
|       <OverallResult success="true"/> | ||||
|     </TestCase> | ||||
|     <TestCase name="Pointers can be compared to null" filename="tests/<exe-name>/UsageTests/Condition.tests.cpp" > | ||||
| @@ -16841,7 +16895,7 @@ loose text artifact | ||||
|       </Section> | ||||
|       <OverallResult success="true"/> | ||||
|     </TestCase> | ||||
|     <OverallResults successes="1624" failures="149" expectedFailures="21"/> | ||||
|     <OverallResults successes="1630" failures="149" expectedFailures="21"/> | ||||
|   </Group> | ||||
|   <OverallResults successes="1624" failures="148" expectedFailures="21"/> | ||||
|   <OverallResults successes="1630" failures="148" expectedFailures="21"/> | ||||
| </Catch> | ||||
|   | ||||
| @@ -19,7 +19,7 @@ namespace { | ||||
|     auto fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCaseInfo("", { 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; | ||||
| @@ -280,7 +280,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]"))); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Martin Hořeňovský
					Martin Hořeňovský