mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-03 22:05:39 +02:00
Feature: generic matchers (#1843)
This commit extends the Matchers feature with the ability to have type-independent (e.g. templated) matchers. This is done by adding a new base type that Matchers can extend, `MatcherGenericBase`, and overloads of operators `!`, `&&` and `||` that handle matchers extending `MatcherGenericBase` in a special manner. These new matchers can also take their arguments as values and non-const references. Closes #1307 Closes #1553 Closes #1554 Co-authored-by: Martin Hořeňovský <martin.horenovsky@gmail.com>
This commit is contained in:
@@ -2116,6 +2116,217 @@ ToStringGeneral.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
5 == 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining MatchAllOfGeneric does not nest
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() && MatcherB() && MatcherC()), Catch::
|
||||
Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() && MatcherB() && MatcherC() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T)
|
||||
1 )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() && MatcherB() && MatcherC() && MatcherD()),
|
||||
Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC,
|
||||
MatcherD> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() && MatcherB() && MatcherC() && MatcherD() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T)
|
||||
1 and equals: true )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining MatchAnyOfGeneric does not nest
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() || MatcherB() || MatcherC()), Catch::
|
||||
Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() || MatcherB() || MatcherC() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1
|
||||
)
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() || MatcherB() || MatcherC() || MatcherD()),
|
||||
Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC,
|
||||
MatcherD> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() || MatcherB() || MatcherC() || MatcherD() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1
|
||||
or equals: true )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining MatchNotOfGeneric does not nest
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(!MatcherA()), Catch::Matchers::Impl::MatchNotOfGeneric
|
||||
<MatcherA> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 0, !MatcherA() )
|
||||
with expansion:
|
||||
0 not equals: (int) 1 or (float) 1.0f
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(!!MatcherA()), MatcherA const& >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, !!MatcherA() )
|
||||
with expansion:
|
||||
1 equals: (int) 1 or (float) 1.0f
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(!!!MatcherA()), Catch::Matchers::Impl::
|
||||
MatchNotOfGeneric<MatcherA> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 0, !!!MatcherA() )
|
||||
with expansion:
|
||||
0 not equals: (int) 1 or (float) 1.0f
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(!!!!MatcherA()), MatcherA const & >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, !!!!MatcherA() )
|
||||
with expansion:
|
||||
1 equals: (int) 1 or (float) 1.0f
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining concrete matchers does not use templated matchers
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(StartsWith("foo") || (StartsWith("bar") && EndsWith
|
||||
("bar") && !EndsWith("foo"))), Catch::Matchers::Impl::MatchAnyOf<std::string>
|
||||
>::value
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining only templated matchers
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() || MatcherB()), Catch::Matchers::Impl::
|
||||
MatchAnyOfGeneric<MatcherA, MatcherB> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() || MatcherB() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() && MatcherB()), Catch::Matchers::Impl::
|
||||
MatchAllOfGeneric<MatcherA, MatcherB> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() && MatcherB() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() || !MatcherB()), Catch::Matchers::Impl::
|
||||
MatchAnyOfGeneric<MatcherA, Catch::Matchers::Impl::MatchNotOfGeneric
|
||||
<MatcherB>> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() || !MatcherB() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f or not equals: (long long) 1 )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining templated and concrete matchers
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( vec, Predicate<std::vector<int>>([](auto const& vec) { return std::all_of(vec.begin(), vec.end(), [](int elem) { return elem % 2 == 1; }); }, "All elements are odd") && !EqualsRange(a) )
|
||||
with expansion:
|
||||
{ 1, 3, 5 } ( matches predicate: "All elements are odd" and not Equals: { 5,
|
||||
3, 1 } )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, StartsWith("foo") && EqualsRange(arr) && EndsWith("bar") )
|
||||
with expansion:
|
||||
"foobar" ( starts with: "foo" and Equals: { 'f', 'o', 'o', 'b', 'a', 'r' }
|
||||
and ends with: "bar" )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, StartsWith("foo") && !EqualsRange(bad_arr) && EndsWith("bar") )
|
||||
with expansion:
|
||||
"foobar" ( starts with: "foo" and not Equals: { 'o', 'o', 'f', 'b', 'a', 'r'
|
||||
} and ends with: "bar" )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, EqualsRange(arr) && StartsWith("foo") && EndsWith("bar") )
|
||||
with expansion:
|
||||
"foobar" ( Equals: { 'f', 'o', 'o', 'b', 'a', 'r' } and starts with: "foo"
|
||||
and ends with: "bar" )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, !EqualsRange(bad_arr) && StartsWith("foo") && EndsWith("bar") )
|
||||
with expansion:
|
||||
"foobar" ( not Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } and starts with:
|
||||
"foo" and ends with: "bar" )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, EqualsRange(bad_arr) || (StartsWith("foo") && EndsWith("bar")) )
|
||||
with expansion:
|
||||
"foobar" ( Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } or ( starts with: "foo"
|
||||
and ends with: "bar" ) )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, (StartsWith("foo") && EndsWith("bar")) || EqualsRange(bad_arr) )
|
||||
with expansion:
|
||||
"foobar" ( ( starts with: "foo" and ends with: "bar" ) or Equals: { 'o', 'o',
|
||||
'f', 'b', 'a', 'r' } )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining templated matchers
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( container, EqualsRange(a) || EqualsRange(b) || EqualsRange(c) )
|
||||
with expansion:
|
||||
{ 1, 2, 3 } ( Equals: { 1, 2, 3 } or Equals: { 0, 1, 2 } or Equals: { 4, 5, 6
|
||||
} )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Commas in various macros are allowed
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -6414,6 +6625,24 @@ Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
Message from section two
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Overloaded comma or address-of operators are not used
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS_AS( (EvilMatcher(), EvilMatcher()), EvilCommaOperatorUsed )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS_AS( &EvilMatcher(), EvilAddressOfOperatorUsed )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_NOTHROW( EvilMatcher() || EvilMatcher() && !EvilMatcher() )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_NOTHROW( (EvilMatcher() && EvilMatcher()) || !EvilMatcher() )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Parse test names and tags
|
||||
Empty test spec should have no filters
|
||||
@@ -14053,6 +14282,6 @@ Misc.tests.cpp:<line number>
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
===============================================================================
|
||||
test cases: 320 | 230 passed | 86 failed | 4 failed as expected
|
||||
assertions: 1809 | 1640 passed | 148 failed | 21 failed as expected
|
||||
test cases: 328 | 238 passed | 86 failed | 4 failed as expected
|
||||
assertions: 1844 | 1675 passed | 148 failed | 21 failed as expected
|
||||
|
||||
|
Reference in New Issue
Block a user