mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-25 23:06:10 +01:00
Provide round-tripping serialization for TestSpec
This commit is contained in:
parent
c6dfeb5e7d
commit
e19ed221bd
@ -6,12 +6,14 @@
|
|||||||
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
#include <catch2/catch_test_spec.hpp>
|
#include <catch2/catch_test_spec.hpp>
|
||||||
|
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||||
#include <catch2/internal/catch_string_manip.hpp>
|
#include <catch2/internal/catch_string_manip.hpp>
|
||||||
#include <catch2/catch_test_case_info.hpp>
|
#include <catch2/catch_test_case_info.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@ -35,6 +37,10 @@ namespace Catch {
|
|||||||
return m_wildcardPattern.matches( testCase.name );
|
return m_wildcardPattern.matches( testCase.name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestSpec::NamePattern::serializeTo( std::ostream& out ) const {
|
||||||
|
out << '"' << name() << '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
|
TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
|
||||||
: Pattern( filterString )
|
: Pattern( filterString )
|
||||||
@ -47,6 +53,10 @@ namespace Catch {
|
|||||||
Tag( m_tag ) ) != end( testCase.tags );
|
Tag( m_tag ) ) != end( testCase.tags );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestSpec::TagPattern::serializeTo( std::ostream& out ) const {
|
||||||
|
out << name();
|
||||||
|
}
|
||||||
|
|
||||||
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
|
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
|
||||||
bool should_use = !testCase.isHidden();
|
bool should_use = !testCase.isHidden();
|
||||||
for (auto const& pattern : m_required) {
|
for (auto const& pattern : m_required) {
|
||||||
@ -63,18 +73,31 @@ namespace Catch {
|
|||||||
return should_use;
|
return should_use;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TestSpec::Filter::name() const {
|
void TestSpec::Filter::serializeTo( std::ostream& out ) const {
|
||||||
std::string name;
|
bool first = true;
|
||||||
for (auto const& p : m_required) {
|
for ( auto const& pattern : m_required ) {
|
||||||
name += p->name();
|
if ( !first ) {
|
||||||
|
out << ' ';
|
||||||
}
|
}
|
||||||
for (auto const& p : m_forbidden) {
|
out << *pattern;
|
||||||
name += p->name();
|
first = false;
|
||||||
|
}
|
||||||
|
for ( auto const& pattern : m_forbidden ) {
|
||||||
|
if ( !first ) {
|
||||||
|
out << ' ';
|
||||||
|
}
|
||||||
|
out << *pattern;
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string TestSpec::extractFilterName( Filter const& filter ) {
|
||||||
|
Catch::ReusableStringStream sstr;
|
||||||
|
sstr << filter;
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
|
||||||
bool TestSpec::hasFilters() const {
|
bool TestSpec::hasFilters() const {
|
||||||
return !m_filters.empty();
|
return !m_filters.empty();
|
||||||
}
|
}
|
||||||
@ -91,7 +114,7 @@ namespace Catch {
|
|||||||
for( auto const& test : testCases )
|
for( auto const& test : testCases )
|
||||||
if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) )
|
if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) )
|
||||||
currentMatches.emplace_back( &test );
|
currentMatches.emplace_back( &test );
|
||||||
return FilterMatch{ filter.name(), currentMatches };
|
return FilterMatch{ extractFilterName(filter), currentMatches };
|
||||||
} );
|
} );
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
@ -100,4 +123,15 @@ namespace Catch {
|
|||||||
return m_invalidSpecs;
|
return m_invalidSpecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestSpec::serializeTo( std::ostream& out ) const {
|
||||||
|
bool first = true;
|
||||||
|
for ( auto const& filter : m_filters ) {
|
||||||
|
if ( !first ) {
|
||||||
|
out << ',';
|
||||||
|
}
|
||||||
|
out << filter;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
#include <catch2/internal/catch_wildcard_pattern.hpp>
|
#include <catch2/internal/catch_wildcard_pattern.hpp>
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -34,6 +35,14 @@ namespace Catch {
|
|||||||
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
|
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
|
||||||
std::string const& name() const;
|
std::string const& name() const;
|
||||||
private:
|
private:
|
||||||
|
virtual void serializeTo( std::ostream& out ) const = 0;
|
||||||
|
// Writes string that would be reparsed into the pattern
|
||||||
|
friend std::ostream& operator<<(std::ostream& out,
|
||||||
|
Pattern const& pattern) {
|
||||||
|
pattern.serializeTo( out );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
std::string const m_name;
|
std::string const m_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,6 +51,8 @@ namespace Catch {
|
|||||||
explicit NamePattern( std::string const& name, std::string const& filterString );
|
explicit NamePattern( std::string const& name, std::string const& filterString );
|
||||||
bool matches( TestCaseInfo const& testCase ) const override;
|
bool matches( TestCaseInfo const& testCase ) const override;
|
||||||
private:
|
private:
|
||||||
|
void serializeTo( std::ostream& out ) const override;
|
||||||
|
|
||||||
WildcardPattern m_wildcardPattern;
|
WildcardPattern m_wildcardPattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,6 +61,8 @@ namespace Catch {
|
|||||||
explicit TagPattern( std::string const& tag, std::string const& filterString );
|
explicit TagPattern( std::string const& tag, std::string const& filterString );
|
||||||
bool matches( TestCaseInfo const& testCase ) const override;
|
bool matches( TestCaseInfo const& testCase ) const override;
|
||||||
private:
|
private:
|
||||||
|
void serializeTo( std::ostream& out ) const override;
|
||||||
|
|
||||||
std::string m_tag;
|
std::string m_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,10 +70,19 @@ namespace Catch {
|
|||||||
std::vector<Detail::unique_ptr<Pattern>> m_required;
|
std::vector<Detail::unique_ptr<Pattern>> m_required;
|
||||||
std::vector<Detail::unique_ptr<Pattern>> m_forbidden;
|
std::vector<Detail::unique_ptr<Pattern>> m_forbidden;
|
||||||
|
|
||||||
|
//! Serializes this filter into a string that would be parsed into
|
||||||
|
//! an equivalent filter
|
||||||
|
void serializeTo( std::ostream& out ) const;
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, Filter const& f) {
|
||||||
|
f.serializeTo( out );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
bool matches( TestCaseInfo const& testCase ) const;
|
bool matches( TestCaseInfo const& testCase ) const;
|
||||||
std::string name() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static std::string extractFilterName( Filter const& filter );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct FilterMatch {
|
struct FilterMatch {
|
||||||
std::string name;
|
std::string name;
|
||||||
@ -77,7 +99,16 @@ namespace Catch {
|
|||||||
private:
|
private:
|
||||||
std::vector<Filter> m_filters;
|
std::vector<Filter> m_filters;
|
||||||
std::vector<std::string> m_invalidSpecs;
|
std::vector<std::string> m_invalidSpecs;
|
||||||
|
|
||||||
friend class TestSpecParser;
|
friend class TestSpecParser;
|
||||||
|
//! Serializes this test spec into a string that would be parsed into
|
||||||
|
//! equivalent test spec
|
||||||
|
void serializeTo( std::ostream& out ) const;
|
||||||
|
friend std::ostream& operator<<(std::ostream& out,
|
||||||
|
TestSpec const& spec) {
|
||||||
|
spec.serializeTo( out );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ add_test(NAME TestSpecs::CombiningMatchingAndNonMatchingIsOk-1 COMMAND $<TARGET_
|
|||||||
|
|
||||||
add_test(NAME TestSpecs::CombiningMatchingAndNonMatchingIsOk-2 COMMAND $<TARGET_FILE:SelfTest> Tracker, "___nonexistent_test___")
|
add_test(NAME TestSpecs::CombiningMatchingAndNonMatchingIsOk-2 COMMAND $<TARGET_FILE:SelfTest> Tracker, "___nonexistent_test___")
|
||||||
set_tests_properties(TestSpecs::CombiningMatchingAndNonMatchingIsOk-2 PROPERTIES
|
set_tests_properties(TestSpecs::CombiningMatchingAndNonMatchingIsOk-2 PROPERTIES
|
||||||
PASS_REGULAR_EXPRESSION "No test cases matched '___nonexistent_test___'"
|
PASS_REGULAR_EXPRESSION "No test cases matched '\"___nonexistent_test___\"'"
|
||||||
FAIL_REGULAR_EXPRESSION "No tests ran"
|
FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -325,3 +325,40 @@ TEST_CASE("#1912 -- test spec parser handles escaping", "[command-line][test-spe
|
|||||||
REQUIRE(spec.matches(*fakeTestCase(R"(spec \ char)")));
|
REQUIRE(spec.matches(*fakeTestCase(R"(spec \ char)")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test spec serialization is round-trippable", "[test-spec][serialization][approvals]") {
|
||||||
|
using Catch::parseTestSpec;
|
||||||
|
using Catch::TestSpec;
|
||||||
|
|
||||||
|
auto serializedTestSpec = []( std::string const& spec ) {
|
||||||
|
Catch::ReusableStringStream sstr;
|
||||||
|
sstr << parseTestSpec( spec );
|
||||||
|
return sstr.str();
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("Spaces are normalized") {
|
||||||
|
CHECK( serializedTestSpec( "[abc][def]" ) == "[abc] [def]" );
|
||||||
|
CHECK( serializedTestSpec( "[def] [abc]" ) == "[def] [abc]" );
|
||||||
|
CHECK( serializedTestSpec( "[def] [abc]" ) == "[def] [abc]" );
|
||||||
|
}
|
||||||
|
SECTION("Output is order dependent") {
|
||||||
|
CHECK( serializedTestSpec( "[abc][def]" ) == "[abc] [def]" );
|
||||||
|
CHECK( serializedTestSpec( "[def][abc]" ) == "[def] [abc]" );
|
||||||
|
}
|
||||||
|
SECTION("Multiple disjunct filters") {
|
||||||
|
CHECK( serializedTestSpec( "[abc],[def]" ) == "[abc],[def]" );
|
||||||
|
CHECK( serializedTestSpec( "[def],[abc],[idkfa]" ) == "[def],[abc],[idkfa]" );
|
||||||
|
}
|
||||||
|
SECTION("Test names are enclosed in string") {
|
||||||
|
CHECK( serializedTestSpec( "Some test" ) == "\"Some test\"" );
|
||||||
|
CHECK( serializedTestSpec( "*Some test" ) == "\"*Some test\"" );
|
||||||
|
CHECK( serializedTestSpec( "* Some test" ) == "\"* Some test\"" );
|
||||||
|
CHECK( serializedTestSpec( "* Some test *" ) == "\"* Some test *\"" );
|
||||||
|
}
|
||||||
|
SECTION( "Mixing test names and tags" ) {
|
||||||
|
CHECK( serializedTestSpec( "some test[abcd]" ) ==
|
||||||
|
"\"some test\" [abcd]" );
|
||||||
|
CHECK( serializedTestSpec( "[ab]some test[cd]" ) ==
|
||||||
|
"[ab] \"some test\" [cd]" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user