From 5a9072d01e92bd049c2b85b244062f02128e032d Mon Sep 17 00:00:00 2001 From: Jonathan Coe Date: Thu, 12 May 2016 19:18:44 +0100 Subject: [PATCH] Add support for comparison of Approx with strong typedefs closes #652 --- include/internal/catch_approx.hpp | 52 +++++++++++++++++++++++++++++++ projects/SelfTest/ApproxTests.cpp | 41 ++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/include/internal/catch_approx.hpp b/include/internal/catch_approx.hpp index 163d2680..87d40fe9 100644 --- a/include/internal/catch_approx.hpp +++ b/include/internal/catch_approx.hpp @@ -13,6 +13,10 @@ #include #include +#if defined(CATCH_CPP11_OR_GREATER) +#include +#endif + namespace Catch { namespace Detail { @@ -41,6 +45,53 @@ namespace Detail { return approx; } +#if defined(CATCH_CPP11_OR_GREATER) + template ::value>::type> + friend bool operator == ( const T& lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + auto lhs_v = double(lhs); + return fabs( lhs_v - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs_v), fabs(rhs.m_value) ) ); + } + + template ::value>::type> + friend bool operator == ( Approx const& lhs, const T& rhs ) { + return operator==( rhs, lhs ); + } + + template ::value>::type> + friend bool operator != ( T lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + template ::value>::type> + friend bool operator != ( Approx const& lhs, T rhs ) { + return !operator==( rhs, lhs ); + } + + template ::value>::type> + friend bool operator <= ( T lhs, Approx const& rhs ) + { + return double(lhs) < rhs.m_value || lhs == rhs; + } + + template ::value>::type> + friend bool operator <= ( Approx const& lhs, T rhs ) + { + return lhs.m_value < double(rhs) || lhs == rhs; + } + + template ::value>::type> + friend bool operator >= ( T lhs, Approx const& rhs ) + { + return double(lhs) > rhs.m_value || lhs == rhs; + } + + template ::value>::type> + friend bool operator >= ( Approx const& lhs, T rhs ) + { + return lhs.m_value > double(rhs) || lhs == rhs; + } +#else friend bool operator == ( double lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); @@ -77,6 +128,7 @@ namespace Detail { { return lhs.m_value > rhs || lhs == rhs; } +#endif Approx& epsilon( double newEpsilon ) { m_epsilon = newEpsilon; diff --git a/projects/SelfTest/ApproxTests.cpp b/projects/SelfTest/ApproxTests.cpp index cd708f2d..a16dd59f 100644 --- a/projects/SelfTest/ApproxTests.cpp +++ b/projects/SelfTest/ApproxTests.cpp @@ -140,3 +140,44 @@ TEST_CASE( "Approximate PI", "[Approx][PI]" ) REQUIRE( divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) ); REQUIRE( divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) ); } + +//////////////////////////////////////////////////////////////////////////////// + +#if defined(CATCH_CPP11_OR_GREATER) +class StrongDoubleTypedef +{ + double d_ = 0.0; + + public: + explicit StrongDoubleTypedef(double d) : d_(d) {} + explicit operator double() const { return d_; } +}; + +TEST_CASE +( + "Comparison with explicitly convertible types", + "[Approx]" +) +{ + StrongDoubleTypedef td(10.0); + + REQUIRE(td == Approx(10.0)); + REQUIRE(Approx(10.0) == td); + + REQUIRE(td != Approx(11.0)); + REQUIRE(Approx(11.0) != td); + + REQUIRE(td <= Approx(10.0)); + REQUIRE(td <= Approx(11.0)); + REQUIRE(Approx(10.0) <= td); + REQUIRE(Approx(9.0) <= td); + + REQUIRE(td >= Approx(9.0)); + REQUIRE(td >= Approx(10.0)); + REQUIRE(Approx(10.0) >= td); + REQUIRE(Approx(11.0) >= td); + +} +#endif + +////////////////////////////////////////////////////////////////////////////////