mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 04:07:10 +01:00 
			
		
		
		
	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:
		| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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}"/> | ||||
|   | ||||
| @@ -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<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<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<std::string>( [] (std::string const& 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<std::string>( [] (std::string const& 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> | ||||
|   | ||||
| @@ -32,6 +32,9 @@ namespace { namespace MatchersTests { | ||||
|         return "some completely different text that contains one common word"; | ||||
|     } | ||||
|  | ||||
|     inline bool alwaysTrue(int) { return true; } | ||||
|     inline bool alwaysFalse(int) { return false; } | ||||
|  | ||||
|  | ||||
| #ifdef _MSC_VER | ||||
| #pragma warning(disable:4702) // Unreachable code -- MSVC 19 (VS 2015) sees right through the indirection | ||||
| @@ -396,6 +399,26 @@ namespace { namespace MatchersTests { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         TEST_CASE("Arbitrary predicate matcher", "[matchers][generic]") { | ||||
|             SECTION("Function pointer") { | ||||
|                 REQUIRE_THAT(1,  Predicate<int>(alwaysTrue, "always true")); | ||||
|                 REQUIRE_THAT(1, !Predicate<int>(alwaysFalse, "always false")); | ||||
|             } | ||||
|             SECTION("Lambdas + different type") { | ||||
|                 REQUIRE_THAT("Hello olleH", | ||||
|                              Predicate<std::string>( | ||||
|                                  [] (std::string const& str) -> bool { return str.front() == str.back(); }, | ||||
|                                  "First and last character should be equal") | ||||
|                 ); | ||||
|  | ||||
|                 REQUIRE_THAT("This wouldn't pass", | ||||
|                              !Predicate<std::string>( | ||||
|                                  [] (std::string const& str) -> bool { return str.front() == str.back(); } | ||||
|                              ) | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| } } // namespace MatchersTests | ||||
|  | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Martin Hořeňovský
					Martin Hořeňovský