Skip to content

Commit

Permalink
Add IsNaN matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
horenmar committed Feb 25, 2023
1 parent 9ff3cde commit 6fbb3f0
Show file tree
Hide file tree
Showing 17 changed files with 178 additions and 21 deletions.
13 changes: 11 additions & 2 deletions docs/matchers.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,18 +141,27 @@ are a permutation of the ones in `some_vec`.

### Floating point matchers

Catch2 provides 3 matchers that target floating point numbers. These
Catch2 provides 4 matchers that target floating point numbers. These
are:

* `WithinAbs(double target, double margin)`,
* `WithinULP(FloatingPoint target, uint64_t maxUlpDiff)`, and
* `WithinRel(FloatingPoint target, FloatingPoint eps)`.
* `IsNaN()`

> `WithinRel` matcher was introduced in Catch2 2.10.0
For more details, read [the docs on comparing floating point
> `IsNaN` matcher was introduced in Catch2 X.Y.Z.
The first three serve to compare two floating pointe numbers. For more
details about how they work, read [the docs on comparing floating point
numbers](comparing-floating-point-numbers.md#floating-point-matchers).

`IsNaN` then does exactly what it says on the tin. It matches the input
if it is a NaN (Not a Number). The advantage of using it over just plain
`REQUIRE(std::isnan(x))`, is that if the check fails, with `REQUIRE` you
won't see the value of `x`, but with `REQUIRE_THAT(x, IsNaN())`, you will.


### Miscellaneous matchers

Expand Down
14 changes: 13 additions & 1 deletion src/catch2/matchers/catch_matchers_floating_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,5 +225,17 @@ WithinRelMatcher WithinRel(float target) {
}


} // namespace Matchers

bool IsNaNMatcher::match( double const& matchee ) const {
return std::isnan( matchee );
}

std::string IsNaNMatcher::describe() const {
using namespace std::string_literals;
return "is NaN"s;
}

IsNaNMatcher IsNaN() { return IsNaNMatcher(); }

} // namespace Matchers
} // namespace Catch
30 changes: 23 additions & 7 deletions src/catch2/matchers/catch_matchers_floating_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ namespace Matchers {
double m_margin;
};

//! Creates a matcher that accepts numbers within certain range of target
WithinAbsMatcher WithinAbs( double target, double margin );



class WithinUlpsMatcher final : public MatcherBase<double> {
public:
WithinUlpsMatcher( double target,
Expand All @@ -40,6 +45,13 @@ namespace Matchers {
Detail::FloatingPointKind m_type;
};

//! Creates a matcher that accepts doubles within certain ULP range of target
WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts floats within certain ULP range of target
WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);



// Given IEEE-754 format for floats and doubles, we can assume
// that float -> double promotion is lossless. Given this, we can
// assume that if we do the standard relative comparison of
Expand All @@ -56,13 +68,6 @@ namespace Matchers {
double m_epsilon;
};

//! Creates a matcher that accepts doubles within certain ULP range of target
WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts floats within certain ULP range of target
WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts numbers within certain range of target
WithinAbsMatcher WithinAbs(double target, double margin);

//! Creates a matcher that accepts doubles within certain relative range of target
WithinRelMatcher WithinRel(double target, double eps);
//! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
Expand All @@ -72,6 +77,17 @@ namespace Matchers {
//! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
WithinRelMatcher WithinRel(float target);



class IsNaNMatcher final : public MatcherBase<double> {
public:
IsNaNMatcher() = default;
bool match( double const& matchee ) const override;
std::string describe() const override;
};

IsNaNMatcher IsNaN();

} // namespace Matchers
} // namespace Catch

Expand Down
4 changes: 3 additions & 1 deletion tests/SelfTest/Baselines/compact.sw.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP( 1., 0 )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., 0. )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., -0.2 ), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., 1. ), std::domain_error
Matchers.tests.cpp:<line number>: passed: 1., !IsNaN() for: 1.0 not is NaN
Matchers.tests.cpp:<line number>: passed: 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 10.f, !WithinRel( 11.2f, 0.1f ) for: 10.0f not and 11.2 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 1.f, !WithinRel( 0.f, 0.99f ) for: 1.0f not and 0 are within 99% of each other
Expand Down Expand Up @@ -661,6 +662,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP( 1.f, static_cast<uint64_t>(
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, 0.f )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, -0.2f ), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, 1.f ), std::domain_error
Matchers.tests.cpp:<line number>: passed: 1., !IsNaN() for: 1.0 not is NaN
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Expand Down Expand Up @@ -2537,6 +2539,6 @@ InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
test cases: 409 | 309 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2224 | 2047 passed | 145 failed | 32 failed as expected
assertions: 2226 | 2049 passed | 145 failed | 32 failed as expected


4 changes: 3 additions & 1 deletion tests/SelfTest/Baselines/compact.sw.multi.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP( 1., 0 )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., 0. )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., -0.2 ), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., 1. ), std::domain_error
Matchers.tests.cpp:<line number>: passed: 1., !IsNaN() for: 1.0 not is NaN
Matchers.tests.cpp:<line number>: passed: 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 10.f, !WithinRel( 11.2f, 0.1f ) for: 10.0f not and 11.2 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 1.f, !WithinRel( 0.f, 0.99f ) for: 1.0f not and 0 are within 99% of each other
Expand Down Expand Up @@ -659,6 +660,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP( 1.f, static_cast<uint64_t>(
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, 0.f )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, -0.2f ), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, 1.f ), std::domain_error
Matchers.tests.cpp:<line number>: passed: 1., !IsNaN() for: 1.0 not is NaN
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Expand Down Expand Up @@ -2526,6 +2528,6 @@ InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
test cases: 409 | 309 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2224 | 2047 passed | 145 failed | 32 failed as expected
assertions: 2226 | 2049 passed | 145 failed | 32 failed as expected


2 changes: 1 addition & 1 deletion tests/SelfTest/Baselines/console.std.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1534,5 +1534,5 @@ due to unexpected exception with message:

===============================================================================
test cases: 409 | 323 passed | 69 failed | 6 skipped | 11 failed as expected
assertions: 2207 | 2047 passed | 128 failed | 32 failed as expected
assertions: 2209 | 2049 passed | 128 failed | 32 failed as expected

26 changes: 25 additions & 1 deletion tests/SelfTest/Baselines/console.sw.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4671,6 +4671,18 @@ Matchers.tests.cpp:<line number>: PASSED:
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( WithinRel( 1., 1. ), std::domain_error )

-------------------------------------------------------------------------------
Floating point matchers: double
IsNaN
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., !IsNaN() )
with expansion:
1.0 not is NaN

-------------------------------------------------------------------------------
Floating point matchers: float
Relative
Expand Down Expand Up @@ -4864,6 +4876,18 @@ Matchers.tests.cpp:<line number>: PASSED:
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( WithinRel( 1.f, 1.f ), std::domain_error )

-------------------------------------------------------------------------------
Floating point matchers: float
IsNaN
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., !IsNaN() )
with expansion:
1.0 not is NaN

-------------------------------------------------------------------------------
Generators -- adapters
Filtering by predicate
Expand Down Expand Up @@ -18208,5 +18232,5 @@ Misc.tests.cpp:<line number>: PASSED:

===============================================================================
test cases: 409 | 309 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2224 | 2047 passed | 145 failed | 32 failed as expected
assertions: 2226 | 2049 passed | 145 failed | 32 failed as expected

26 changes: 25 additions & 1 deletion tests/SelfTest/Baselines/console.sw.multi.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4669,6 +4669,18 @@ Matchers.tests.cpp:<line number>: PASSED:
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( WithinRel( 1., 1. ), std::domain_error )

-------------------------------------------------------------------------------
Floating point matchers: double
IsNaN
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., !IsNaN() )
with expansion:
1.0 not is NaN

-------------------------------------------------------------------------------
Floating point matchers: float
Relative
Expand Down Expand Up @@ -4862,6 +4874,18 @@ Matchers.tests.cpp:<line number>: PASSED:
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( WithinRel( 1.f, 1.f ), std::domain_error )

-------------------------------------------------------------------------------
Floating point matchers: float
IsNaN
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., !IsNaN() )
with expansion:
1.0 not is NaN

-------------------------------------------------------------------------------
Generators -- adapters
Filtering by predicate
Expand Down Expand Up @@ -18197,5 +18221,5 @@ Misc.tests.cpp:<line number>: PASSED:

===============================================================================
test cases: 409 | 309 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2224 | 2047 passed | 145 failed | 32 failed as expected
assertions: 2226 | 2049 passed | 145 failed | 32 failed as expected

4 changes: 3 additions & 1 deletion tests/SelfTest/Baselines/junit.sw.approved.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="128" skipped="11" tests="2235" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="128" skipped="11" tests="2237" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="random-seed" value="1"/>
<property name="filters" value="&quot;*&quot; ~[!nonportable] ~[!benchmark] ~[approvals]"/>
Expand Down Expand Up @@ -694,12 +694,14 @@ at Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/ULPs" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Composed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Constructor validation" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/IsNaN" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative/Some subnormal values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Margin" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/IsNaN" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Basic usage" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Shortening a range" time="{duration}" status="run"/>
Expand Down
4 changes: 3 additions & 1 deletion tests/SelfTest/Baselines/junit.sw.multi.approved.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="<exe-name>" errors="17" failures="128" skipped="11" tests="2235" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="128" skipped="11" tests="2237" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="random-seed" value="1"/>
<property name="filters" value="&quot;*&quot; ~[!nonportable] ~[!benchmark] ~[approvals]"/>
Expand Down Expand Up @@ -693,12 +693,14 @@ at Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/ULPs" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Composed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Constructor validation" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/IsNaN" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative/Some subnormal values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Margin" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/IsNaN" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Basic usage" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Shortening a range" time="{duration}" status="run"/>
Expand Down
2 changes: 2 additions & 0 deletions tests/SelfTest/Baselines/sonarqube.sw.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1172,12 +1172,14 @@ at Matchers.tests.cpp:<line number>
<testCase name="Floating point matchers: double/ULPs" duration="{duration}"/>
<testCase name="Floating point matchers: double/Composed" duration="{duration}"/>
<testCase name="Floating point matchers: double/Constructor validation" duration="{duration}"/>
<testCase name="Floating point matchers: double/IsNaN" duration="{duration}"/>
<testCase name="Floating point matchers: float/Relative" duration="{duration}"/>
<testCase name="Floating point matchers: float/Relative/Some subnormal values" duration="{duration}"/>
<testCase name="Floating point matchers: float/Margin" duration="{duration}"/>
<testCase name="Floating point matchers: float/ULPs" duration="{duration}"/>
<testCase name="Floating point matchers: float/Composed" duration="{duration}"/>
<testCase name="Floating point matchers: float/Constructor validation" duration="{duration}"/>
<testCase name="Floating point matchers: float/IsNaN" duration="{duration}"/>
<testCase name="Matchers can be (AllOf) composed with the &amp;&amp; operator" duration="{duration}"/>
<testCase name="Matchers can be (AnyOf) composed with the || operator" duration="{duration}"/>
<testCase name="Matchers can be composed with both &amp;&amp; and ||" duration="{duration}"/>
Expand Down
2 changes: 2 additions & 0 deletions tests/SelfTest/Baselines/sonarqube.sw.multi.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1171,12 +1171,14 @@ at Matchers.tests.cpp:<line number>
<testCase name="Floating point matchers: double/ULPs" duration="{duration}"/>
<testCase name="Floating point matchers: double/Composed" duration="{duration}"/>
<testCase name="Floating point matchers: double/Constructor validation" duration="{duration}"/>
<testCase name="Floating point matchers: double/IsNaN" duration="{duration}"/>
<testCase name="Floating point matchers: float/Relative" duration="{duration}"/>
<testCase name="Floating point matchers: float/Relative/Some subnormal values" duration="{duration}"/>
<testCase name="Floating point matchers: float/Margin" duration="{duration}"/>
<testCase name="Floating point matchers: float/ULPs" duration="{duration}"/>
<testCase name="Floating point matchers: float/Composed" duration="{duration}"/>
<testCase name="Floating point matchers: float/Constructor validation" duration="{duration}"/>
<testCase name="Floating point matchers: float/IsNaN" duration="{duration}"/>
<testCase name="Matchers can be (AllOf) composed with the &amp;&amp; operator" duration="{duration}"/>
<testCase name="Matchers can be (AnyOf) composed with the || operator" duration="{duration}"/>
<testCase name="Matchers can be composed with both &amp;&amp; and ||" duration="{duration}"/>
Expand Down
6 changes: 5 additions & 1 deletion tests/SelfTest/Baselines/tap.sw.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,8 @@ ok {test-number} - WithinRel( 1., 0. )
ok {test-number} - WithinRel( 1., -0.2 ), std::domain_error
# Floating point matchers: double
ok {test-number} - WithinRel( 1., 1. ), std::domain_error
# Floating point matchers: double
ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN
# Floating point matchers: float
ok {test-number} - 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other
# Floating point matchers: float
Expand Down Expand Up @@ -1254,6 +1256,8 @@ ok {test-number} - WithinRel( 1.f, 0.f )
ok {test-number} - WithinRel( 1.f, -0.2f ), std::domain_error
# Floating point matchers: float
ok {test-number} - WithinRel( 1.f, 1.f ), std::domain_error
# Floating point matchers: float
ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN
# Generators -- adapters
ok {test-number} - i % 2 == 0 for: 0 == 0
# Generators -- adapters
Expand Down Expand Up @@ -4473,5 +4477,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} -
# xmlentitycheck
ok {test-number} -
1..2235
1..2237

0 comments on commit 6fbb3f0

Please sign in to comment.