Add PredicateMatcher that takes an arbitrary predicate functions

Also adds `Predicate` helper function to create `PredicateMatcher`.
Because of limitations in type inference it needs to be explicitly
typed, like so
`Predicate<std::string>([](std::string const& str) { ... })`.
It also takes an optional second argument for description of the
predicate.

It is possible to infer the argument with sufficient TMP, see
https://stackoverflow.com/questions/43560492/how-to-extract-lambdas-return-type-and-variadic-parameters-pack-back-from-gener/43561563#43561563
but I don't think that the magic is worth introducing ATM.

Closes #1236
This commit is contained in:
Martin Hořeňovský
2018-04-03 23:28:14 +02:00
parent dfb83f20e9
commit 1ca8f43b01
11 changed files with 204 additions and 7 deletions

View File

@@ -97,6 +97,10 @@ Approx.tests.cpp:<line number>: passed: 0 == Approx( dZero) for: 0 == Approx( 0.
Approx.tests.cpp:<line number>: passed: 0 == Approx( dSmall ).margin( 0.001 ) for: 0 == Approx( 0.00001 )
Approx.tests.cpp:<line number>: passed: 1.234f == Approx( dMedium ) for: 1.234f == Approx( 1.234 )
Approx.tests.cpp:<line number>: passed: dMedium == Approx( 1.234f ) for: 1.234 == Approx( 1.2339999676 )
Matchers.tests.cpp:<line number>: passed: 1, Predicate<int>(alwaysTrue, "always true") for: 1 matches predicate: "always true"
Matchers.tests.cpp:<line number>: passed: 1, !Predicate<int>(alwaysFalse, "always false") for: 1 not matches predicate: "always false"
Matchers.tests.cpp:<line number>: passed: "Hello olleH", Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") for: "Hello olleH" matches predicate: "First and last character should be equal"
Matchers.tests.cpp:<line number>: passed: "This wouldn't pass", !Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) for: "This wouldn't pass" not matches undescribed predicate
Tricky.tests.cpp:<line number>: passed: true
Tricky.tests.cpp:<line number>: passed: true
Tricky.tests.cpp:<line number>: passed: true

View File

@@ -1084,6 +1084,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 203 | 150 passed | 49 failed | 4 failed as expected
assertions: 1057 | 929 passed | 107 failed | 21 failed as expected
test cases: 204 | 151 passed | 49 failed | 4 failed as expected
assertions: 1061 | 933 passed | 107 failed | 21 failed as expected

View File

@@ -814,6 +814,44 @@ PASSED:
with expansion:
1.234 == Approx( 1.2339999676 )
-------------------------------------------------------------------------------
Arbitrary predicate matcher
Function pointer
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( 1, Predicate<int>(alwaysTrue, "always true") )
with expansion:
1 matches predicate: "always true"
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( 1, !Predicate<int>(alwaysFalse, "always false") )
with expansion:
1 not matches predicate: "always false"
-------------------------------------------------------------------------------
Arbitrary predicate matcher
Lambdas + different type
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( "Hello olleH", Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") )
with expansion:
"Hello olleH" matches predicate: "First and last character should be equal"
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( "This wouldn't pass", !Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) )
with expansion:
"This wouldn't pass" not matches undescribed predicate
-------------------------------------------------------------------------------
Assertions then sections
-------------------------------------------------------------------------------
@@ -8897,6 +8935,6 @@ Misc.tests.cpp:<line number>:
PASSED:
===============================================================================
test cases: 203 | 137 passed | 62 failed | 4 failed as expected
assertions: 1071 | 929 passed | 121 failed | 21 failed as expected
test cases: 204 | 138 passed | 62 failed | 4 failed as expected
assertions: 1075 | 933 passed | 121 failed | 21 failed as expected

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="105" tests="1072" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="105" tests="1076" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
@@ -110,6 +110,8 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Approximate comparisons with floats" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Approximate comparisons with ints" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Approximate comparisons with mixed numeric types" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Function pointer" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Lambdas + different type" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Assertions then sections" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Assertions then sections/A section" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another section" time="{duration}"/>

View File

@@ -870,6 +870,47 @@
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Arbitrary predicate matcher" tags="[generic][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Section name="Function pointer" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
1, Predicate&lt;int>(alwaysTrue, "always true")
</Original>
<Expanded>
1 matches predicate: "always true"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
1, !Predicate&lt;int>(alwaysFalse, "always false")
</Original>
<Expanded>
1 not matches predicate: "always false"
</Expanded>
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
<Section name="Lambdas + different type" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
"Hello olleH", Predicate&lt;std::string>( [] (std::string const&amp; str) -> bool { return str.front() == str.back(); }, "First and last character should be equal")
</Original>
<Expanded>
"Hello olleH" matches predicate: "First and last character should be equal"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
"This wouldn't pass", !Predicate&lt;std::string>( [] (std::string const&amp; str) -> bool { return str.front() == str.back(); } )
</Original>
<Expanded>
"This wouldn't pass" not matches undescribed predicate
</Expanded>
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Assertions then sections" tags="[Tricky]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Original>
@@ -9841,7 +9882,7 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
<OverallResults successes="929" failures="122" expectedFailures="21"/>
<OverallResults successes="933" failures="122" expectedFailures="21"/>
</Group>
<OverallResults successes="929" failures="121" expectedFailures="21"/>
<OverallResults successes="933" failures="121" expectedFailures="21"/>
</Catch>