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.
This commit is contained in:
kosak 2015-01-08 02:38:14 +00:00
parent 61adbcc5c6
commit 6b81780310
3 changed files with 73 additions and 37 deletions

View File

@ -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);
};

View File

@ -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);
};

View File

@ -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));