From f100e8f797410b7e033a3cb1a8ab95cd83c8ceb2 Mon Sep 17 00:00:00 2001 From: helloworld922 Date: Thu, 24 Jan 2019 12:01:47 -0800 Subject: [PATCH 1/9] added general floating point near comparison --- googletest/include/gtest/gtest.h | 32 ++++++++++++++++++++++++-------- googletest/src/gtest.cc | 19 ------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index bcea14507e..0e3ff25e98 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -56,6 +56,8 @@ #include #include #include +#include +#include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" @@ -1781,12 +1783,26 @@ AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error); +template +GTEST_API_ AssertionResult FPNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + const R1& val1, const R2& val2, + const T& abs_error) { + using namespace std; + auto diff = fabs(val1 - val2); + if (diff <= abs_error) { + return AssertionSuccess(); + } + return AssertionFailure() + << std::setprecision( + std::numeric_limits::type>::max_digits10) + << "The difference between " << expr1 << " and " << expr2 << " is " + << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; +} // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // A class that enables one to stream messages to assertion macros @@ -2167,11 +2183,11 @@ class TestWithParam : public Test, public WithParamInterface { val1, val2) #define EXPECT_NEAR(val1, val2, abs_error)\ - EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + EXPECT_PRED_FORMAT3(::testing::internal::FPNearPredFormat, \ val1, val2, abs_error) #define ASSERT_NEAR(val1, val2, abs_error)\ - ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + ASSERT_PRED_FORMAT3(::testing::internal::FPNearPredFormat, \ val1, val2, abs_error) // These predicate format functions work on floating-point values, and diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index d1cfb535f5..8270228fb1 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -1380,25 +1380,6 @@ std::string GetBoolAssertionFailureMessage( return msg.GetString(); } -// Helper function for implementing ASSERT_NEAR. -AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error) { - const double diff = fabs(val1 - val2); - if (diff <= abs_error) return AssertionSuccess(); - - return AssertionFailure() - << "The difference between " << expr1 << " and " << expr2 - << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" - << expr1 << " evaluates to " << val1 << ",\n" - << expr2 << " evaluates to " << val2 << ", and\n" - << abs_error_expr << " evaluates to " << abs_error << "."; -} - - // Helper template for implementing FloatLE() and DoubleLE(). template AssertionResult FloatingPointLE(const char* expr1, From aa3827b8f36105aaa3e36436e2ceb90a63bc4ff9 Mon Sep 17 00:00:00 2001 From: helloworld922 Date: Thu, 24 Jan 2019 13:05:26 -0800 Subject: [PATCH 2/9] Didn't realize that template functions shouldn't have GTEST_API_ This should fix some issues with MSVC --- googletest/include/gtest/gtest.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index 0e3ff25e98..c17a5acf43 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -1784,11 +1784,9 @@ AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template -GTEST_API_ AssertionResult FPNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - const R1& val1, const R2& val2, - const T& abs_error) { +AssertionResult FPNearPredFormat(const char* expr1, const char* expr2, + const char* abs_error_expr, const R1& val1, + const R2& val2, const T& abs_error) { using namespace std; auto diff = fabs(val1 - val2); if (diff <= abs_error) { From 61ae79a557d444b604458c4f67ba89258a1f1eb0 Mon Sep 17 00:00:00 2001 From: helloworld922 Date: Fri, 25 Jan 2019 12:24:38 -0800 Subject: [PATCH 3/9] Fixes from code review by gennadiycivil: - Fixed order of includes - Better way to ensure ADL for std::fabs - Added unit test for EXPECT_NEAR/ASSERT_NEAR for long double and a "custom real" type --- googletest/include/gtest/gtest.h | 11 ++-- googletest/test/gtest_unittest.cc | 95 +++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index c17a5acf43..bd9a23ecf2 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -52,12 +52,12 @@ #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ +#include +#include #include #include #include #include -#include -#include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" @@ -1787,14 +1787,15 @@ template AssertionResult FPNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, const R1& val1, const R2& val2, const T& abs_error) { - using namespace std; + using std::fabs; auto diff = fabs(val1 - val2); if (diff <= abs_error) { return AssertionSuccess(); } return AssertionFailure() - << std::setprecision( - std::numeric_limits::type>::max_digits10) + << std::setprecision(std::numeric_limits< + typename std::decay::type>::max_digits10 + + 2) << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index 4ab298c411..af2f954417 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -3103,6 +3103,101 @@ TEST_F(DoubleTest, DoubleLEFails) { } +TEST(LongDoubleTest, EXPECT_NEAR) { + { + long double a = -1.0; + long double b = -1.1; + EXPECT_NEAR(a, b, 0.2); + } + { + long double a = -1.0; + long double b = -1.5; + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(a, b, 0.25), // NOLINT + "The difference between a and b is 0.5, " + "which exceeds 0.25, where\na evaluates to -1,\nb " + "evaluates to -1.5, and\n0.25 evaluates to 0.25."); + } +} + +TEST(LongDoubleTest, ASSERT_NEAR) { + { + long double a = -1.0; + long double b = -1.1; + ASSERT_NEAR(a, b, 0.2); + } + { + EXPECT_FATAL_FAILURE(long double a = -1.0; long double b = -1.5; + ASSERT_NEAR(a, b, 0.25), // NOLINT + "The difference between a and b is 0.5, " + "which exceeds 0.25, where\na evaluates to -1,\nb " + "evaluates to -1.5, and\n0.25 evaluates to 0.25."); + } +} + +// a custom floating-point like type which implements the minimal interface +// required to test EXPECT_NEAR on a custom type +class custom_real { + // internally stores as a double to prevent having to implement an actual + // custom real-like type + double value_; + + public: + custom_real(double value) : value_(value) {} + custom_real(const custom_real& o) : value_(o.value_) {} + + custom_real operator-(const custom_real& o) const { + return value_ - o.value_; + } + custom_real& operator-=(const custom_real& o) { + value_ -= o.value_; + return *this; + } + + bool operator<(const custom_real& o) { return value_ < o.value_; } + bool operator<=(const custom_real& o) { return value_ <= o.value_; } + + friend custom_real fabs(const custom_real& v); + friend std::ostream& operator<<(std::ostream& out, const custom_real& v); +}; + +static custom_real fabs(const custom_real& v) { return std::fabs(v.value_); } + +static std::ostream& operator<<(std::ostream& out, const custom_real& v) { + out << v.value_; + return out; +} + +TEST(CustomRealTest, EXPECT_NEAR) { + { + custom_real a(-1.0); + custom_real b(-1.1); + EXPECT_NEAR(a, b, 0.2); + } + { + custom_real a(-1.0); + custom_real b(-1.5); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(a, b, 0.25), // NOLINT + "The difference between a and b is 0.5, " + "which exceeds 0.25, where\na evaluates to -1,\nb " + "evaluates to -1.5, and\n0.25 evaluates to 0.25."); + } +} + +TEST(CustomRealTest, ASSERT_NEAR) { + { + custom_real a(-1.0); + custom_real b(-1.1); + ASSERT_NEAR(a, b, 0.2); + } + { + EXPECT_FATAL_FAILURE(custom_real a(-1.0); custom_real b(-1.5); + ASSERT_NEAR(a, b, 0.25), // NOLINT + "The difference between a and b is 0.5, " + "which exceeds 0.25, where\na evaluates to -1,\nb " + "evaluates to -1.5, and\n0.25 evaluates to 0.25."); + } +} + // Verifies that a test or test case whose name starts with DISABLED_ is // not run. From 557c1046490ff6019fcb50946d78ec9d27351bc0 Mon Sep 17 00:00:00 2001 From: helloworld922 Date: Fri, 25 Jan 2019 13:16:41 -0800 Subject: [PATCH 4/9] MSVC doesn't like global static functions? --- googletest/test/gtest_unittest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index af2f954417..f530da1451 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -3160,9 +3160,9 @@ class custom_real { friend std::ostream& operator<<(std::ostream& out, const custom_real& v); }; -static custom_real fabs(const custom_real& v) { return std::fabs(v.value_); } +custom_real fabs(const custom_real& v) { return std::fabs(v.value_); } -static std::ostream& operator<<(std::ostream& out, const custom_real& v) { +std::ostream& operator<<(std::ostream& out, const custom_real& v) { out << v.value_; return out; } From 78bafe1f3860f1b6f6d0d97d8e3535ef0bbdc140 Mon Sep 17 00:00:00 2001 From: helloworld922 Date: Fri, 25 Jan 2019 14:30:31 -0800 Subject: [PATCH 5/9] Wrapped custom_real in an anonymous namespace --- googletest/test/gtest_unittest.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index f530da1451..f32d142d3a 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -3134,6 +3134,7 @@ TEST(LongDoubleTest, ASSERT_NEAR) { } } +namespace { // a custom floating-point like type which implements the minimal interface // required to test EXPECT_NEAR on a custom type class custom_real { @@ -3197,6 +3198,7 @@ TEST(CustomRealTest, ASSERT_NEAR) { "evaluates to -1.5, and\n0.25 evaluates to 0.25."); } } +} // namespace // Verifies that a test or test case whose name starts with DISABLED_ is // not run. From 2abf6571cb3e240e710b6f49f7a64e72f09f5a20 Mon Sep 17 00:00:00 2001 From: Gennadiy Civil Date: Tue, 29 Jan 2019 12:37:15 -0800 Subject: [PATCH 6/9] Update googletest/include/gtest/gtest.h Co-Authored-By: helloworld922 --- googletest/include/gtest/gtest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index bd9a23ecf2..3942ccf6ae 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -1787,7 +1787,7 @@ template AssertionResult FPNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, const R1& val1, const R2& val2, const T& abs_error) { - using std::fabs; + auto diff = val1 > val2 ? val1 - val2 : val2 - val1; auto diff = fabs(val1 - val2); if (diff <= abs_error) { return AssertionSuccess(); From 13c31554d4212a6c2029fb5c555b8ad29404dd60 Mon Sep 17 00:00:00 2001 From: helloworld922 Date: Tue, 29 Jan 2019 12:41:44 -0800 Subject: [PATCH 7/9] Removed ADL for fabs (just use standard operators) Implemented suggestions for custom_real class --- googletest/include/gtest/gtest.h | 4 +- googletest/test/gtest_unittest.cc | 91 +++++++++++++++++-------------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index bd9a23ecf2..2fad7bbc95 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -52,7 +52,6 @@ #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ -#include #include #include #include @@ -1787,8 +1786,7 @@ template AssertionResult FPNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, const R1& val1, const R2& val2, const T& abs_error) { - using std::fabs; - auto diff = fabs(val1 - val2); + auto diff = val1 > val2 ? val1 - val2 : val2 - val1; if (diff <= abs_error) { return AssertionSuccess(); } diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index f32d142d3a..74377ac355 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -3134,7 +3134,7 @@ TEST(LongDoubleTest, ASSERT_NEAR) { } } -namespace { +namespace custom_real_ns { // a custom floating-point like type which implements the minimal interface // required to test EXPECT_NEAR on a custom type class custom_real { @@ -3143,62 +3143,71 @@ class custom_real { double value_; public: - custom_real(double value) : value_(value) {} - custom_real(const custom_real& o) : value_(o.value_) {} - - custom_real operator-(const custom_real& o) const { - return value_ - o.value_; + explicit custom_real(double value) : value_(value) {} + friend custom_real operator-(custom_real l, custom_real r) { + return custom_real(l.value_ - r.value_); } - custom_real& operator-=(const custom_real& o) { - value_ -= o.value_; - return *this; + friend bool operator<(custom_real l, custom_real r) { + return l.value_ < r.value_; + } + friend bool operator>(custom_real l, custom_real r) { + return l.value_ > r.value_; + } + friend bool operator<=(custom_real l, custom_real r) { + return l.value_ <= r.value_; + } + friend bool operator>=(custom_real l, custom_real r) { + return l.value_ >= r.value_; + } + friend bool operator==(custom_real l, custom_real r) { + return l.value_ == r.value_; + } + friend bool operator!=(custom_real l, custom_real r) { + return l.value_ != r.value_; + } + friend std::ostream& operator<<(std::ostream& out, custom_real v) { + out << v.value_; + return out; } - - bool operator<(const custom_real& o) { return value_ < o.value_; } - bool operator<=(const custom_real& o) { return value_ <= o.value_; } - - friend custom_real fabs(const custom_real& v); - friend std::ostream& operator<<(std::ostream& out, const custom_real& v); }; - -custom_real fabs(const custom_real& v) { return std::fabs(v.value_); } - -std::ostream& operator<<(std::ostream& out, const custom_real& v) { - out << v.value_; - return out; -} +} // namespace custom_real_ns TEST(CustomRealTest, EXPECT_NEAR) { { - custom_real a(-1.0); - custom_real b(-1.1); - EXPECT_NEAR(a, b, 0.2); + custom_real_ns::custom_real a(-1.0); + custom_real_ns::custom_real b(-1.1); + EXPECT_NEAR(a, b, custom_real_ns::custom_real(0.2)); } { - custom_real a(-1.0); - custom_real b(-1.5); - EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(a, b, 0.25), // NOLINT - "The difference between a and b is 0.5, " - "which exceeds 0.25, where\na evaluates to -1,\nb " - "evaluates to -1.5, and\n0.25 evaluates to 0.25."); + custom_real_ns::custom_real a(-1.0); + custom_real_ns::custom_real b(-1.5); + EXPECT_NONFATAL_FAILURE( + EXPECT_NEAR(a, b, custom_real_ns::custom_real(0.25)), // NOLINT + "The difference between a and b is 0.5, " + "which exceeds custom_real_ns::custom_real(0.25), where\na evaluates " + "to -1,\nb " + "evaluates to -1.5, and\ncustom_real_ns::custom_real(0.25) evaluates " + "to 0.25."); } } - TEST(CustomRealTest, ASSERT_NEAR) { { - custom_real a(-1.0); - custom_real b(-1.1); - ASSERT_NEAR(a, b, 0.2); + custom_real_ns::custom_real a(-1.0); + custom_real_ns::custom_real b(-1.1); + ASSERT_NEAR(a, b, custom_real_ns::custom_real(0.2)); } { - EXPECT_FATAL_FAILURE(custom_real a(-1.0); custom_real b(-1.5); - ASSERT_NEAR(a, b, 0.25), // NOLINT - "The difference between a and b is 0.5, " - "which exceeds 0.25, where\na evaluates to -1,\nb " - "evaluates to -1.5, and\n0.25 evaluates to 0.25."); + EXPECT_FATAL_FAILURE( + custom_real_ns::custom_real a(-1.0); + custom_real_ns::custom_real b(-1.5); + ASSERT_NEAR(a, b, custom_real_ns::custom_real(0.25)), // NOLINT + "The difference between a and b is 0.5, " + "which exceeds custom_real_ns::custom_real(0.25), where\na evaluates " + "to -1,\nb " + "evaluates to -1.5, and\ncustom_real_ns::custom_real(0.25) evaluates " + "to 0.25."); } } -} // namespace // Verifies that a test or test case whose name starts with DISABLED_ is // not run. From db6f5e0475a0d421a23914f8904943b4fd1ce0fa Mon Sep 17 00:00:00 2001 From: helloworld922 Date: Tue, 29 Jan 2019 12:47:01 -0800 Subject: [PATCH 8/9] iomanip already in gtest-internal.h, not needed in gtest.h --- googletest/include/gtest/gtest.h | 1 - 1 file changed, 1 deletion(-) diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index 2fad7bbc95..135dcdb2a8 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -52,7 +52,6 @@ #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ -#include #include #include #include From d4865c307cabd9c1bbae239f1445336840227384 Mon Sep 17 00:00:00 2001 From: helloworld922 Date: Tue, 29 Jan 2019 14:30:58 -0800 Subject: [PATCH 9/9] Automated tests complaining about unused overloaded operators --- googletest/test/gtest_unittest.cc | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index 74377ac355..eed451bc6b 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -3147,24 +3147,12 @@ class custom_real { friend custom_real operator-(custom_real l, custom_real r) { return custom_real(l.value_ - r.value_); } - friend bool operator<(custom_real l, custom_real r) { - return l.value_ < r.value_; - } friend bool operator>(custom_real l, custom_real r) { return l.value_ > r.value_; } friend bool operator<=(custom_real l, custom_real r) { return l.value_ <= r.value_; } - friend bool operator>=(custom_real l, custom_real r) { - return l.value_ >= r.value_; - } - friend bool operator==(custom_real l, custom_real r) { - return l.value_ == r.value_; - } - friend bool operator!=(custom_real l, custom_real r) { - return l.value_ != r.value_; - } friend std::ostream& operator<<(std::ostream& out, custom_real v) { out << v.value_; return out;