Commit 6b817803 authored by kosak's avatar kosak
Browse files

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.
parent 61adbcc5
......@@ -1879,20 +1879,23 @@ template <typename FloatType>
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 <typename T>
class Impl : public MatcherInterface<T> {
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<FloatType> lhs(value), rhs(rhs_);
MatchResultListener* listener) const {
const FloatingPoint<FloatType> 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<FloatType>::digits10 + 2);
if (FloatingPoint<FloatType>(rhs_).is_nan()) {
if (FloatingPoint<FloatType>(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<FloatType>::digits10 + 2);
if (FloatingPoint<FloatType>(rhs_).is_nan()) {
if (FloatingPoint<FloatType>(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<float>, a
// The following 3 type conversion operators allow FloatEq(expected) and
// NanSensitiveFloatEq(expected) to be used as a Matcher<float>, a
// Matcher<const float&>, or a Matcher<float&>, 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<FloatType>() const {
return MakeMatcher(new Impl<FloatType>(rhs_, nan_eq_nan_, max_abs_error_));
return MakeMatcher(
new Impl<FloatType>(expected_, nan_eq_nan_, max_abs_error_));
}
operator Matcher<const FloatType&>() const {
return MakeMatcher(
new Impl<const FloatType&>(rhs_, nan_eq_nan_, max_abs_error_));
new Impl<const FloatType&>(expected_, nan_eq_nan_, max_abs_error_));
}
operator Matcher<FloatType&>() const {
return MakeMatcher(new Impl<FloatType&>(rhs_, nan_eq_nan_, max_abs_error_));
return MakeMatcher(
new Impl<FloatType&>(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<Container,
......@@ -2500,11 +2520,11 @@ class ContainerEqMatcher {
void DescribeTo(::std::ostream* os) const {
*os << "equals ";
UniversalPrint(rhs_, os);
UniversalPrint(expected_, os);
}
void DescribeNegationTo(::std::ostream* os) const {
*os << "does not equal ";
UniversalPrint(rhs_, os);
UniversalPrint(expected_, os);
}
template <typename LhsContainer>
......@@ -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);
};
......
......@@ -72,7 +72,7 @@ template <class Class, typename MethodPtr>
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 <typename Result, typename ArgumentTuple>
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);
};
......
......@@ -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<double> m1 = NanSensitiveDoubleNear(2.0, 0.5);
EXPECT_EQ("is approximately 2 (absolute error <= 0.5)", Describe(m1));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment