New floating-point matchers: DoubleNear() and friends;
AllOf() and AnyOf() can accept any number of arguments now in C++11 mode.
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
|
||||
#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
|
||||
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <ostream> // NOLINT
|
||||
@@ -1406,6 +1407,91 @@ class BothOfMatcherImpl : public MatcherInterface<T> {
|
||||
GTEST_DISALLOW_ASSIGN_(BothOfMatcherImpl);
|
||||
};
|
||||
|
||||
#if GTEST_LANG_CXX11
|
||||
// MatcherList provides mechanisms for storing a variable number of matchers in
|
||||
// a list structure (ListType) and creating a combining matcher from such a
|
||||
// list.
|
||||
// The template is defined recursively using the following template paramters:
|
||||
// * kSize is the length of the MatcherList.
|
||||
// * Head is the type of the first matcher of the list.
|
||||
// * Tail denotes the types of the remaining matchers of the list.
|
||||
template <int kSize, typename Head, typename... Tail>
|
||||
struct MatcherList {
|
||||
typedef MatcherList<kSize - 1, Tail...> MatcherListTail;
|
||||
typedef pair<Head, typename MatcherListTail::ListType> ListType;
|
||||
|
||||
// BuildList stores variadic type values in a nested pair structure.
|
||||
// Example:
|
||||
// MatcherList<3, int, string, float>::BuildList(5, "foo", 2.0) will return
|
||||
// the corresponding result of type pair<int, pair<string, float>>.
|
||||
static ListType BuildList(const Head& matcher, const Tail&... tail) {
|
||||
return ListType(matcher, MatcherListTail::BuildList(tail...));
|
||||
}
|
||||
|
||||
// CreateMatcher<T> creates a Matcher<T> from a given list of matchers (built
|
||||
// by BuildList()). CombiningMatcher<T> is used to combine the matchers of the
|
||||
// list. CombiningMatcher<T> must implement MatcherInterface<T> and have a
|
||||
// constructor taking two Matcher<T>s as input.
|
||||
template <typename T, template <typename /* T */> class CombiningMatcher>
|
||||
static Matcher<T> CreateMatcher(const ListType& matchers) {
|
||||
return Matcher<T>(new CombiningMatcher<T>(
|
||||
SafeMatcherCast<T>(matchers.first),
|
||||
MatcherListTail::template CreateMatcher<T, CombiningMatcher>(
|
||||
matchers.second)));
|
||||
}
|
||||
};
|
||||
|
||||
// The following defines the base case for the recursive definition of
|
||||
// MatcherList.
|
||||
template <typename Matcher1, typename Matcher2>
|
||||
struct MatcherList<2, Matcher1, Matcher2> {
|
||||
typedef pair<Matcher1, Matcher2> ListType;
|
||||
|
||||
static ListType BuildList(const Matcher1& matcher1,
|
||||
const Matcher2& matcher2) {
|
||||
return pair<Matcher1, Matcher2>(matcher1, matcher2);
|
||||
}
|
||||
|
||||
template <typename T, template <typename /* T */> class CombiningMatcher>
|
||||
static Matcher<T> CreateMatcher(const ListType& matchers) {
|
||||
return Matcher<T>(new CombiningMatcher<T>(
|
||||
SafeMatcherCast<T>(matchers.first),
|
||||
SafeMatcherCast<T>(matchers.second)));
|
||||
}
|
||||
};
|
||||
|
||||
// VariadicMatcher is used for the variadic implementation of
|
||||
// AllOf(m_1, m_2, ...) and AnyOf(m_1, m_2, ...).
|
||||
// CombiningMatcher<T> is used to recursively combine the provided matchers
|
||||
// (of type Args...).
|
||||
template <template <typename T> class CombiningMatcher, typename... Args>
|
||||
class VariadicMatcher {
|
||||
public:
|
||||
VariadicMatcher(const Args&... matchers) // NOLINT
|
||||
: matchers_(MatcherListType::BuildList(matchers...)) {}
|
||||
|
||||
// This template type conversion operator allows an
|
||||
// VariadicMatcher<Matcher1, Matcher2...> object to match any type that
|
||||
// all of the provided matchers (Matcher1, Matcher2, ...) can match.
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return MatcherListType::template CreateMatcher<T, CombiningMatcher>(
|
||||
matchers_);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef MatcherList<sizeof...(Args), Args...> MatcherListType;
|
||||
|
||||
const typename MatcherListType::ListType matchers_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(VariadicMatcher);
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
using AllOfMatcher = VariadicMatcher<BothOfMatcherImpl, Args...>;
|
||||
|
||||
#endif // GTEST_LANG_CXX11
|
||||
|
||||
// Used for implementing the AllOf(m_1, ..., m_n) matcher, which
|
||||
// matches a value that matches all of the matchers m_1, ..., and m_n.
|
||||
template <typename Matcher1, typename Matcher2>
|
||||
@@ -1493,6 +1579,13 @@ class EitherOfMatcherImpl : public MatcherInterface<T> {
|
||||
GTEST_DISALLOW_ASSIGN_(EitherOfMatcherImpl);
|
||||
};
|
||||
|
||||
#if GTEST_LANG_CXX11
|
||||
// AnyOfMatcher is used for the variadic implementation of AnyOf(m_1, m_2, ...).
|
||||
template <typename... Args>
|
||||
using AnyOfMatcher = VariadicMatcher<EitherOfMatcherImpl, Args...>;
|
||||
|
||||
#endif // GTEST_LANG_CXX11
|
||||
|
||||
// Used for implementing the AnyOf(m_1, ..., m_n) matcher, which
|
||||
// matches a value that matches at least one of the matchers m_1, ...,
|
||||
// and m_n.
|
||||
@@ -1646,37 +1739,60 @@ MakePredicateFormatterFromMatcher(const M& matcher) {
|
||||
return PredicateFormatterFromMatcher<M>(matcher);
|
||||
}
|
||||
|
||||
// Implements the polymorphic floating point equality matcher, which
|
||||
// matches two float values using ULP-based approximation. The
|
||||
// template is meant to be instantiated with FloatType being either
|
||||
// float or double.
|
||||
// Implements the polymorphic floating point equality matcher, which matches
|
||||
// two float values using ULP-based approximation or, optionally, a
|
||||
// user-specified epsilon. The template is meant to be instantiated with
|
||||
// FloatType being either float or double.
|
||||
template <typename FloatType>
|
||||
class FloatingEqMatcher {
|
||||
public:
|
||||
// Constructor for FloatingEqMatcher.
|
||||
// The matcher's input will be compared with rhs. 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.
|
||||
// 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) {}
|
||||
rhs_(rhs), 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) {
|
||||
GTEST_CHECK_(max_abs_error >= 0)
|
||||
<< ", where max_abs_error is" << max_abs_error;
|
||||
}
|
||||
|
||||
// Implements floating point equality matcher as a Matcher<T>.
|
||||
template <typename T>
|
||||
class Impl : public MatcherInterface<T> {
|
||||
public:
|
||||
Impl(FloatType rhs, bool nan_eq_nan) :
|
||||
rhs_(rhs), nan_eq_nan_(nan_eq_nan) {}
|
||||
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) {}
|
||||
|
||||
virtual bool MatchAndExplain(T value,
|
||||
MatchResultListener* /* listener */) const {
|
||||
const FloatingPoint<FloatType> lhs(value), rhs(rhs_);
|
||||
|
||||
// Compares NaNs first, if nan_eq_nan_ is true.
|
||||
if (nan_eq_nan_ && lhs.is_nan()) {
|
||||
return rhs.is_nan();
|
||||
if (lhs.is_nan() || rhs.is_nan()) {
|
||||
if (lhs.is_nan() && rhs.is_nan()) {
|
||||
return nan_eq_nan_;
|
||||
}
|
||||
// One is nan; the other is not nan.
|
||||
return false;
|
||||
}
|
||||
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
|
||||
// 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_;
|
||||
} else {
|
||||
return lhs.AlmostEquals(rhs);
|
||||
}
|
||||
|
||||
return lhs.AlmostEquals(rhs);
|
||||
}
|
||||
|
||||
virtual void DescribeTo(::std::ostream* os) const {
|
||||
@@ -1693,6 +1809,9 @@ class FloatingEqMatcher {
|
||||
}
|
||||
} else {
|
||||
*os << "is approximately " << rhs_;
|
||||
if (HasMaxAbsError()) {
|
||||
*os << " (absolute error <= " << max_abs_error_ << ")";
|
||||
}
|
||||
}
|
||||
os->precision(old_precision);
|
||||
}
|
||||
@@ -1709,14 +1828,23 @@ class FloatingEqMatcher {
|
||||
}
|
||||
} else {
|
||||
*os << "isn't approximately " << rhs_;
|
||||
if (HasMaxAbsError()) {
|
||||
*os << " (absolute error > " << max_abs_error_ << ")";
|
||||
}
|
||||
}
|
||||
// Restore original precision.
|
||||
os->precision(old_precision);
|
||||
}
|
||||
|
||||
private:
|
||||
bool HasMaxAbsError() const {
|
||||
return max_abs_error_ >= 0;
|
||||
}
|
||||
|
||||
const FloatType rhs_;
|
||||
const bool nan_eq_nan_;
|
||||
// max_abs_error will be used for value comparison when >= 0.
|
||||
const FloatType max_abs_error_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(Impl);
|
||||
};
|
||||
@@ -1728,20 +1856,23 @@ class FloatingEqMatcher {
|
||||
// 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_));
|
||||
return MakeMatcher(new Impl<FloatType>(rhs_, nan_eq_nan_, max_abs_error_));
|
||||
}
|
||||
|
||||
operator Matcher<const FloatType&>() const {
|
||||
return MakeMatcher(new Impl<const FloatType&>(rhs_, nan_eq_nan_));
|
||||
return MakeMatcher(
|
||||
new Impl<const FloatType&>(rhs_, nan_eq_nan_, max_abs_error_));
|
||||
}
|
||||
|
||||
operator Matcher<FloatType&>() const {
|
||||
return MakeMatcher(new Impl<FloatType&>(rhs_, nan_eq_nan_));
|
||||
return MakeMatcher(new Impl<FloatType&>(rhs_, nan_eq_nan_, max_abs_error_));
|
||||
}
|
||||
|
||||
private:
|
||||
const FloatType rhs_;
|
||||
const bool nan_eq_nan_;
|
||||
// max_abs_error will be used for value comparison when >= 0.
|
||||
const FloatType max_abs_error_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(FloatingEqMatcher);
|
||||
};
|
||||
@@ -2931,18 +3062,50 @@ inline internal::FloatingEqMatcher<double> NanSensitiveDoubleEq(double rhs) {
|
||||
return internal::FloatingEqMatcher<double>(rhs, true);
|
||||
}
|
||||
|
||||
// Creates a matcher that matches any double argument approximately equal to
|
||||
// rhs, up to the specified max absolute error bound, where two NANs are
|
||||
// considered unequal. The max absolute error bound must be non-negative.
|
||||
inline internal::FloatingEqMatcher<double> DoubleNear(
|
||||
double rhs, double max_abs_error) {
|
||||
return internal::FloatingEqMatcher<double>(rhs, false, max_abs_error);
|
||||
}
|
||||
|
||||
// Creates a matcher that matches any double argument approximately equal to
|
||||
// rhs, up to the specified max absolute error bound, including NaN values when
|
||||
// rhs is NaN. The max absolute error bound must be non-negative.
|
||||
inline internal::FloatingEqMatcher<double> NanSensitiveDoubleNear(
|
||||
double rhs, double max_abs_error) {
|
||||
return internal::FloatingEqMatcher<double>(rhs, true, max_abs_error);
|
||||
}
|
||||
|
||||
// Creates a matcher that matches any float argument approximately
|
||||
// equal to rhs, where two NANs are considered unequal.
|
||||
inline internal::FloatingEqMatcher<float> FloatEq(float rhs) {
|
||||
return internal::FloatingEqMatcher<float>(rhs, false);
|
||||
}
|
||||
|
||||
// Creates a matcher that matches any double argument approximately
|
||||
// Creates a matcher that matches any float argument approximately
|
||||
// equal to rhs, including NaN values when rhs is NaN.
|
||||
inline internal::FloatingEqMatcher<float> NanSensitiveFloatEq(float rhs) {
|
||||
return internal::FloatingEqMatcher<float>(rhs, true);
|
||||
}
|
||||
|
||||
// Creates a matcher that matches any float argument approximately equal to
|
||||
// rhs, up to the specified max absolute error bound, where two NANs are
|
||||
// considered unequal. The max absolute error bound must be non-negative.
|
||||
inline internal::FloatingEqMatcher<float> FloatNear(
|
||||
float rhs, float max_abs_error) {
|
||||
return internal::FloatingEqMatcher<float>(rhs, false, max_abs_error);
|
||||
}
|
||||
|
||||
// Creates a matcher that matches any float argument approximately equal to
|
||||
// rhs, up to the specified max absolute error bound, including NaN values when
|
||||
// rhs is NaN. The max absolute error bound must be non-negative.
|
||||
inline internal::FloatingEqMatcher<float> NanSensitiveFloatNear(
|
||||
float rhs, float max_abs_error) {
|
||||
return internal::FloatingEqMatcher<float>(rhs, true, max_abs_error);
|
||||
}
|
||||
|
||||
// Creates a matcher that matches a pointer (raw or smart) that points
|
||||
// to a value that matches inner_matcher.
|
||||
template <typename InnerMatcher>
|
||||
@@ -3341,6 +3504,21 @@ inline bool ExplainMatchResult(
|
||||
return SafeMatcherCast<const T&>(matcher).MatchAndExplain(value, listener);
|
||||
}
|
||||
|
||||
#if GTEST_LANG_CXX11
|
||||
// Define variadic matcher versions. They are overloaded in
|
||||
// gmock-generated-matchers.h for the cases supported by pre C++11 compilers.
|
||||
template <typename... Args>
|
||||
inline internal::AllOfMatcher<Args...> AllOf(const Args&... matchers) {
|
||||
return internal::AllOfMatcher<Args...>(matchers...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline internal::AnyOfMatcher<Args...> AnyOf(const Args&... matchers) {
|
||||
return internal::AnyOfMatcher<Args...>(matchers...);
|
||||
}
|
||||
|
||||
#endif // GTEST_LANG_CXX11
|
||||
|
||||
// AllArgs(m) is a synonym of m. This is useful in
|
||||
//
|
||||
// EXPECT_CALL(foo, Bar(_, _)).With(AllArgs(Eq()));
|
||||
|
||||
Reference in New Issue
Block a user