Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMartin Hořeňovský2022-10-27 17:10:28 +0200
committerMartin Hořeňovský2022-10-27 18:23:59 +0200
commite19ed221bde6b8d8a1a62a71ed942c238ae345a7 (patch)
tree954ce5e9334d0dd588d12d6290756896897d92a2
parentc6dfeb5e7dc175ca4765e884414dab52736cde9e (diff)
downloadcatch3-e19ed221bde6b8d8a1a62a71ed942c238ae345a7.tar.gz
Provide round-tripping serialization for TestSpec
-rw-r--r--src/catch2/catch_test_spec.cpp50
-rw-r--r--src/catch2/catch_test_spec.hpp33
-rw-r--r--tests/CMakeLists.txt2
-rw-r--r--tests/SelfTest/IntrospectiveTests/TestSpec.tests.cpp37
4 files changed, 112 insertions, 10 deletions
diff --git a/src/catch2/catch_test_spec.cpp b/src/catch2/catch_test_spec.cpp
index a3235d43..0a64de0d 100644
--- a/src/catch2/catch_test_spec.cpp
+++ b/src/catch2/catch_test_spec.cpp
@@ -6,12 +6,14 @@
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_spec.hpp>
+#include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_string_manip.hpp>
#include <catch2/catch_test_case_info.hpp>
#include <algorithm>
#include <string>
#include <vector>
+#include <ostream>
namespace Catch {
@@ -35,6 +37,10 @@ namespace Catch {
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 )
: Pattern( filterString )
@@ -47,6 +53,10 @@ namespace Catch {
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 should_use = !testCase.isHidden();
for (auto const& pattern : m_required) {
@@ -63,18 +73,31 @@ namespace Catch {
return should_use;
}
- std::string TestSpec::Filter::name() const {
- std::string name;
- for (auto const& p : m_required) {
- name += p->name();
+ void TestSpec::Filter::serializeTo( std::ostream& out ) const {
+ bool first = true;
+ for ( auto const& pattern : m_required ) {
+ if ( !first ) {
+ out << ' ';
+ }
+ out << *pattern;
+ first = false;
}
- for (auto const& p : m_forbidden) {
- name += p->name();
+ 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 {
return !m_filters.empty();
}
@@ -91,7 +114,7 @@ namespace Catch {
for( auto const& test : testCases )
if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) )
currentMatches.emplace_back( &test );
- return FilterMatch{ filter.name(), currentMatches };
+ return FilterMatch{ extractFilterName(filter), currentMatches };
} );
return matches;
}
@@ -100,4 +123,15 @@ namespace Catch {
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;
+ }
+ }
+
}
diff --git a/src/catch2/catch_test_spec.hpp b/src/catch2/catch_test_spec.hpp
index 499bfaa5..98881f8b 100644
--- a/src/catch2/catch_test_spec.hpp
+++ b/src/catch2/catch_test_spec.hpp
@@ -16,6 +16,7 @@
#include <catch2/internal/catch_unique_ptr.hpp>
#include <catch2/internal/catch_wildcard_pattern.hpp>
+#include <iosfwd>
#include <string>
#include <vector>
@@ -34,6 +35,14 @@ namespace Catch {
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
std::string const& name() const;
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;
};
@@ -42,6 +51,8 @@ namespace Catch {
explicit NamePattern( std::string const& name, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
+ void serializeTo( std::ostream& out ) const override;
+
WildcardPattern m_wildcardPattern;
};
@@ -50,6 +61,8 @@ namespace Catch {
explicit TagPattern( std::string const& tag, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
+ void serializeTo( std::ostream& out ) const override;
+
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_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;
- std::string name() const;
};
+ static std::string extractFilterName( Filter const& filter );
+
public:
struct FilterMatch {
std::string name;
@@ -77,7 +99,16 @@ namespace Catch {
private:
std::vector<Filter> m_filters;
std::vector<std::string> m_invalidSpecs;
+
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;
+ }
};
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 1fec3914..ff941cef 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -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___")
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"
)
diff --git a/tests/SelfTest/IntrospectiveTests/TestSpec.tests.cpp b/tests/SelfTest/IntrospectiveTests/TestSpec.tests.cpp
index 99ad6073..f692ae61 100644
--- a/tests/SelfTest/IntrospectiveTests/TestSpec.tests.cpp
+++ b/tests/SelfTest/IntrospectiveTests/TestSpec.tests.cpp
@@ -325,3 +325,40 @@ TEST_CASE("#1912 -- test spec parser handles escaping", "[command-line][test-spe
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]" );
+ }
+}