From 6b817803104b30d5951c652a1427492db116a490 Mon Sep 17 00:00:00 2001 From: kosak Date: Thu, 8 Jan 2015 02:38:14 +0000 Subject: [PATCH] Makes DoubleNear() print the diff between the actual and the expected value when the match fails. Also fix bogus MSVC warning about "alignment of a member was sensitive to packing". Also bring in gtest 701. --- include/gmock/gmock-matchers.h | 90 ++++++++++++++++++------------ include/gmock/gmock-more-actions.h | 7 ++- test/gmock-matchers_test.cc | 13 +++++ 3 files changed, 73 insertions(+), 37 deletions(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 75432bdb..ca09756f 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1879,20 +1879,23 @@ template class FloatingEqMatcher { public: // Constructor for FloatingEqMatcher. - // The matcher's input will be compared with rhs. The matcher treats two + // The matcher's input will be compared with expected. The matcher treats two // NANs as equal if nan_eq_nan is true. Otherwise, under IEEE standards, // equality comparisons between NANs will always return false. We specify a // negative max_abs_error_ term to indicate that ULP-based approximation will // be used for comparison. - FloatingEqMatcher(FloatType rhs, bool nan_eq_nan) : - rhs_(rhs), nan_eq_nan_(nan_eq_nan), max_abs_error_(-1) { + FloatingEqMatcher(FloatType expected, bool nan_eq_nan) : + expected_(expected), nan_eq_nan_(nan_eq_nan), max_abs_error_(-1) { } // Constructor that supports a user-specified max_abs_error that will be used // for comparison instead of ULP-based approximation. The max absolute // should be non-negative. - FloatingEqMatcher(FloatType rhs, bool nan_eq_nan, FloatType max_abs_error) : - rhs_(rhs), nan_eq_nan_(nan_eq_nan), max_abs_error_(max_abs_error) { + FloatingEqMatcher(FloatType expected, bool nan_eq_nan, + FloatType max_abs_error) + : expected_(expected), + nan_eq_nan_(nan_eq_nan), + max_abs_error_(max_abs_error) { GTEST_CHECK_(max_abs_error >= 0) << ", where max_abs_error is" << max_abs_error; } @@ -1901,16 +1904,18 @@ class FloatingEqMatcher { template class Impl : public MatcherInterface { public: - Impl(FloatType rhs, bool nan_eq_nan, FloatType max_abs_error) : - rhs_(rhs), nan_eq_nan_(nan_eq_nan), max_abs_error_(max_abs_error) {} + Impl(FloatType expected, bool nan_eq_nan, FloatType max_abs_error) + : expected_(expected), + nan_eq_nan_(nan_eq_nan), + max_abs_error_(max_abs_error) {} virtual bool MatchAndExplain(T value, - MatchResultListener* /* listener */) const { - const FloatingPoint lhs(value), rhs(rhs_); + MatchResultListener* listener) const { + const FloatingPoint actual(value), expected(expected_); // Compares NaNs first, if nan_eq_nan_ is true. - if (lhs.is_nan() || rhs.is_nan()) { - if (lhs.is_nan() && rhs.is_nan()) { + if (actual.is_nan() || expected.is_nan()) { + if (actual.is_nan() && expected.is_nan()) { return nan_eq_nan_; } // One is nan; the other is not nan. @@ -1918,12 +1923,24 @@ class FloatingEqMatcher { } if (HasMaxAbsError()) { // We perform an equality check so that inf will match inf, regardless - // of error bounds. If the result of value - rhs_ would result in + // of error bounds. If the result of value - expected_ would result in // overflow or if either value is inf, the default result is infinity, // which should only match if max_abs_error_ is also infinity. - return value == rhs_ || fabs(value - rhs_) <= max_abs_error_; + if (value == expected_) { + return true; + } + + const FloatType diff = value - expected_; + if (fabs(diff) <= max_abs_error_) { + return true; + } + + if (listener->IsInterested()) { + *listener << "which is " << diff << " from " << expected_; + } + return false; } else { - return lhs.AlmostEquals(rhs); + return actual.AlmostEquals(expected); } } @@ -1933,14 +1950,14 @@ class FloatingEqMatcher { // after outputting. const ::std::streamsize old_precision = os->precision( ::std::numeric_limits::digits10 + 2); - if (FloatingPoint(rhs_).is_nan()) { + if (FloatingPoint(expected_).is_nan()) { if (nan_eq_nan_) { *os << "is NaN"; } else { *os << "never matches"; } } else { - *os << "is approximately " << rhs_; + *os << "is approximately " << expected_; if (HasMaxAbsError()) { *os << " (absolute error <= " << max_abs_error_ << ")"; } @@ -1952,14 +1969,14 @@ class FloatingEqMatcher { // As before, get original precision. const ::std::streamsize old_precision = os->precision( ::std::numeric_limits::digits10 + 2); - if (FloatingPoint(rhs_).is_nan()) { + if (FloatingPoint(expected_).is_nan()) { if (nan_eq_nan_) { *os << "isn't NaN"; } else { *os << "is anything"; } } else { - *os << "isn't approximately " << rhs_; + *os << "isn't approximately " << expected_; if (HasMaxAbsError()) { *os << " (absolute error > " << max_abs_error_ << ")"; } @@ -1973,7 +1990,7 @@ class FloatingEqMatcher { return max_abs_error_ >= 0; } - const FloatType rhs_; + const FloatType expected_; const bool nan_eq_nan_; // max_abs_error will be used for value comparison when >= 0. const FloatType max_abs_error_; @@ -1981,27 +1998,29 @@ class FloatingEqMatcher { GTEST_DISALLOW_ASSIGN_(Impl); }; - // The following 3 type conversion operators allow FloatEq(rhs) and - // NanSensitiveFloatEq(rhs) to be used as a Matcher, a + // The following 3 type conversion operators allow FloatEq(expected) and + // NanSensitiveFloatEq(expected) to be used as a Matcher, a // Matcher, or a Matcher, but nothing else. // (While Google's C++ coding style doesn't allow arguments passed // by non-const reference, we may see them in code not conforming to // the style. Therefore Google Mock needs to support them.) operator Matcher() const { - return MakeMatcher(new Impl(rhs_, nan_eq_nan_, max_abs_error_)); + return MakeMatcher( + new Impl(expected_, nan_eq_nan_, max_abs_error_)); } operator Matcher() const { return MakeMatcher( - new Impl(rhs_, nan_eq_nan_, max_abs_error_)); + new Impl(expected_, nan_eq_nan_, max_abs_error_)); } operator Matcher() const { - return MakeMatcher(new Impl(rhs_, nan_eq_nan_, max_abs_error_)); + return MakeMatcher( + new Impl(expected_, nan_eq_nan_, max_abs_error_)); } private: - const FloatType rhs_; + const FloatType expected_; const bool nan_eq_nan_; // max_abs_error will be used for value comparison when >= 0. const FloatType max_abs_error_; @@ -2489,9 +2508,10 @@ class ContainerEqMatcher { typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; - // We make a copy of rhs in case the elements in it are modified + // We make a copy of expected in case the elements in it are modified // after this matcher is created. - explicit ContainerEqMatcher(const Container& rhs) : rhs_(View::Copy(rhs)) { + explicit ContainerEqMatcher(const Container& expected) + : expected_(View::Copy(expected)) { // Makes sure the user doesn't instantiate this class template // with a const or reference type. (void)testing::StaticAssertTypeEq @@ -2516,7 +2536,7 @@ class ContainerEqMatcher { LhsView; typedef typename LhsView::type LhsStlContainer; StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); - if (lhs_stl_container == rhs_) + if (lhs_stl_container == expected_) return true; ::std::ostream* const os = listener->stream(); @@ -2526,8 +2546,8 @@ class ContainerEqMatcher { for (typename LhsStlContainer::const_iterator it = lhs_stl_container.begin(); it != lhs_stl_container.end(); ++it) { - if (internal::ArrayAwareFind(rhs_.begin(), rhs_.end(), *it) == - rhs_.end()) { + if (internal::ArrayAwareFind(expected_.begin(), expected_.end(), *it) == + expected_.end()) { if (printed_header) { *os << ", "; } else { @@ -2540,8 +2560,8 @@ class ContainerEqMatcher { // Now check for missing values. bool printed_header2 = false; - for (typename StlContainer::const_iterator it = rhs_.begin(); - it != rhs_.end(); ++it) { + for (typename StlContainer::const_iterator it = expected_.begin(); + it != expected_.end(); ++it) { if (internal::ArrayAwareFind( lhs_stl_container.begin(), lhs_stl_container.end(), *it) == lhs_stl_container.end()) { @@ -2561,7 +2581,7 @@ class ContainerEqMatcher { } private: - const StlContainer rhs_; + const StlContainer expected_; GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); }; diff --git a/include/gmock/gmock-more-actions.h b/include/gmock/gmock-more-actions.h index c754440e..3d387b6b 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -72,7 +72,7 @@ template class InvokeMethodAction { public: InvokeMethodAction(Class* obj_ptr, MethodPtr method_ptr) - : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} + : method_ptr_(method_ptr), obj_ptr_(obj_ptr) {} template Result Perform(const ArgumentTuple& args) const { @@ -81,8 +81,11 @@ class InvokeMethodAction { } private: - Class* const obj_ptr_; + // The order of these members matters. Reversing the order can trigger + // warning C4121 in MSVC (see + // http://computer-programming-forum.com/7-vc.net/6fbc30265f860ad1.htm ). const MethodPtr method_ptr_; + Class* const obj_ptr_; GTEST_DISALLOW_ASSIGN_(InvokeMethodAction); }; diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index f5eff5fb..be2e9009 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -3071,6 +3071,19 @@ TEST_F(DoubleNearTest, DoubleNearCanDescribeSelf) { EXPECT_EQ("is anything", DescribeNegation(m3)); } +TEST_F(DoubleNearTest, ExplainsResultWhenMatchFails) { + EXPECT_EQ("", Explain(DoubleNear(2.0, 0.1), 2.05)); + EXPECT_EQ("which is 0.2 from 2", Explain(DoubleNear(2.0, 0.1), 2.2)); + EXPECT_EQ("which is -0.3 from 2", Explain(DoubleNear(2.0, 0.1), 1.7)); + + const string explanation = Explain(DoubleNear(2.1, 1e-10), 2.1 + 1.2e-10); + // Different C++ implementations may print floating-point numbers + // slightly differently. + EXPECT_TRUE(explanation == "which is 1.2e-10 from 2.1" || // GCC + explanation == "which is 1.2e-010 from 2.1") // MSVC + << " where explanation is \"" << explanation << "\"."; +} + TEST_F(DoubleNearTest, NanSensitiveDoubleNearCanDescribeSelf) { Matcher m1 = NanSensitiveDoubleNear(2.0, 0.5); EXPECT_EQ("is approximately 2 (absolute error <= 0.5)", Describe(m1));