Googletest export

Change Matcher<T> to allow binding an implementation by value directly:
 - Drop the requirement of MatcherInterface. Doing manual type erasure avoid
   extra layers in many cases.
 - Avoid the adaptor for `MatcherInterface<T>` and `MatcherInterface<const T&>` mismatch.
 - Use a small object optimization when possible. This makes things like
   `_` and `Eq(1)` really cheap and do not require memory allocations.
 - Migrate some matchers to the new model to speed them up and to test the new framework. More matchers to come in future changes.

PiperOrigin-RevId: 350580998
This commit is contained in:
Abseil Team 2021-01-07 12:43:27 -05:00 committed by Derek Mauro
parent 489283524e
commit c13c27a513
4 changed files with 417 additions and 199 deletions

View File

@ -1315,32 +1315,30 @@ how you can define a matcher to do it:
```cpp ```cpp
using ::testing::Matcher; using ::testing::Matcher;
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
class BarPlusBazEqMatcher : public MatcherInterface<const Foo&> { class BarPlusBazEqMatcher {
public: public:
explicit BarPlusBazEqMatcher(int expected_sum) explicit BarPlusBazEqMatcher(int expected_sum)
: expected_sum_(expected_sum) {} : expected_sum_(expected_sum) {}
bool MatchAndExplain(const Foo& foo, bool MatchAndExplain(const Foo& foo,
MatchResultListener* /* listener */) const override { std::ostream* /* listener */) const {
return (foo.bar() + foo.baz()) == expected_sum_; return (foo.bar() + foo.baz()) == expected_sum_;
} }
void DescribeTo(std::ostream* os) const override { void DescribeTo(std::ostream& os) const {
*os << "bar() + baz() equals " << expected_sum_; os << "bar() + baz() equals " << expected_sum_;
} }
void DescribeNegationTo(std::ostream* os) const override { void DescribeNegationTo(std::ostream& os) const {
*os << "bar() + baz() does not equal " << expected_sum_; os << "bar() + baz() does not equal " << expected_sum_;
} }
private: private:
const int expected_sum_; const int expected_sum_;
}; };
Matcher<const Foo&> BarPlusBazEq(int expected_sum) { Matcher<const Foo&> BarPlusBazEq(int expected_sum) {
return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); return BarPlusBazEqMatcher(expected_sum);
} }
... ...
@ -3535,21 +3533,147 @@ MATCHER_P2(Blah, a, b, description_string_2) { ... }
``` ```
While it's tempting to always use the `MATCHER*` macros when defining a new While it's tempting to always use the `MATCHER*` macros when defining a new
matcher, you should also consider implementing `MatcherInterface` or using matcher, you should also consider implementing the matcher interface directly
`MakePolymorphicMatcher()` instead (see the recipes that follow), especially if instead (see the recipes that follow), especially if you need to use the matcher
you need to use the matcher a lot. While these approaches require more work, a lot. While these approaches require more work, they give you more control on
they give you more control on the types of the value being matched and the the types of the value being matched and the matcher parameters, which in
matcher parameters, which in general leads to better compiler error messages general leads to better compiler error messages that pay off in the long run.
that pay off in the long run. They also allow overloading matchers based on They also allow overloading matchers based on parameter types (as opposed to
parameter types (as opposed to just based on the number of parameters). just based on the number of parameters).
### Writing New Monomorphic Matchers ### Writing New Monomorphic Matchers
A matcher of argument type `T` implements `::testing::MatcherInterface<T>` and A matcher of argument type `T` implements the matcher interface for `T` and does
does two things: it tests whether a value of type `T` matches the matcher, and two things: it tests whether a value of type `T` matches the matcher, and can
can describe what kind of values it matches. The latter ability is used for describe what kind of values it matches. The latter ability is used for
generating readable error messages when expectations are violated. generating readable error messages when expectations are violated.
A matcher of `T` must declare a typedef like:
```cpp
using is_gtest_matcher = void;
```
and supports the following operations:
```cpp
// Match a value and optionally explain into an ostream.
bool matched = matcher.MatchAndExplain(value, maybe_os);
// where `value` is of type `T` and
// `maybe_os` is of type `std::ostream*`, where it can be null if the caller
// is not interested in there textual explanation.
matcher.DescribeTo(os);
matcher.DescribeNegationTo(os);
// where `os` is of type `std::ostream*`.
```
If you need a custom matcher but `Truly()` is not a good option (for example,
you may not be happy with the way `Truly(predicate)` describes itself, or you
may want your matcher to be polymorphic as `Eq(value)` is), you can define a
matcher to do whatever you want in two steps: first implement the matcher
interface, and then define a factory function to create a matcher instance. The
second step is not strictly needed but it makes the syntax of using the matcher
nicer.
For example, you can define a matcher to test whether an `int` is divisible by 7
and then use it like this:
```cpp
using ::testing::Matcher;
class DivisibleBy7Matcher {
public:
bool MatchAndExplain(int n, std::ostream*) const {
return (n % 7) == 0;
}
void DescribeTo(std::ostream* os) const {
*os << "is divisible by 7";
}
void DescribeNegationTo(std::ostream* os) const {
*os << "is not divisible by 7";
}
};
Matcher<int> DivisibleBy7() {
return DivisibleBy7Matcher();
}
...
EXPECT_CALL(foo, Bar(DivisibleBy7()));
```
You may improve the matcher message by streaming additional information to the
`os` argument in `MatchAndExplain()`:
```cpp
class DivisibleBy7Matcher {
public:
bool MatchAndExplain(int n, std::ostream* os) const {
const int remainder = n % 7;
if (remainder != 0 && os != nullptr) {
*os << "the remainder is " << remainder;
}
return remainder == 0;
}
...
};
```
Then, `EXPECT_THAT(x, DivisibleBy7());` may generate a message like this:
```shell
Value of: x
Expected: is divisible by 7
Actual: 23 (the remainder is 2)
```
### Writing New Polymorphic Matchers
Expanding what we learned above to *polymorphic* matchers is now just as simple
as adding templates in the right place.
```cpp
class NotNullMatcher {
public:
// To implement a polymorphic matcher, we just need to make MatchAndExplain a
// template on its first argument.
// In this example, we want to use NotNull() with any pointer, so
// MatchAndExplain() accepts a pointer of any type as its first argument.
// In general, you can define MatchAndExplain() as an ordinary method or
// a method template, or even overload it.
template <typename T>
bool MatchAndExplain(T* p, std::ostream*) const {
return p != nullptr;
}
// Describes the property of a value matching this matcher.
void DescribeTo(std::ostream& os) const { *os << "is not NULL"; }
// Describes the property of a value NOT matching this matcher.
void DescribeNegationTo(std::ostream* os) const { *os << "is NULL"; }
};
NotNullMatcher NotNull() {
return NotNullMatcher();
}
...
EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer.
```
### Legacy Matcher Implementation
Defining matchers used to be somewhat more complicated, in which it required
several supporting classes and virtual functions. To implement a matcher for
type `T` using the legacy API you have to derive from `MatcherInterface<T>` and
call `MakeMatcher` to construct the object.
The interface looks like this: The interface looks like this:
```cpp ```cpp
@ -3582,83 +3706,6 @@ class MatcherInterface {
}; };
``` ```
If you need a custom matcher but `Truly()` is not a good option (for example,
you may not be happy with the way `Truly(predicate)` describes itself, or you
may want your matcher to be polymorphic as `Eq(value)` is), you can define a
matcher to do whatever you want in two steps: first implement the matcher
interface, and then define a factory function to create a matcher instance. The
second step is not strictly needed but it makes the syntax of using the matcher
nicer.
For example, you can define a matcher to test whether an `int` is divisible by 7
and then use it like this:
```cpp
using ::testing::MakeMatcher;
using ::testing::Matcher;
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
class DivisibleBy7Matcher : public MatcherInterface<int> {
public:
bool MatchAndExplain(int n,
MatchResultListener* /* listener */) const override {
return (n % 7) == 0;
}
void DescribeTo(std::ostream* os) const override {
*os << "is divisible by 7";
}
void DescribeNegationTo(std::ostream* os) const override {
*os << "is not divisible by 7";
}
};
Matcher<int> DivisibleBy7() {
return MakeMatcher(new DivisibleBy7Matcher);
}
...
EXPECT_CALL(foo, Bar(DivisibleBy7()));
```
You may improve the matcher message by streaming additional information to the
`listener` argument in `MatchAndExplain()`:
```cpp
class DivisibleBy7Matcher : public MatcherInterface<int> {
public:
bool MatchAndExplain(int n,
MatchResultListener* listener) const override {
const int remainder = n % 7;
if (remainder != 0) {
*listener << "the remainder is " << remainder;
}
return remainder == 0;
}
...
};
```
Then, `EXPECT_THAT(x, DivisibleBy7());` may generate a message like this:
```shell
Value of: x
Expected: is divisible by 7
Actual: 23 (the remainder is 2)
```
### Writing New Polymorphic Matchers
You've learned how to write your own matchers in the previous recipe. Just one
problem: a matcher created using `MakeMatcher()` only works for one particular
type of arguments. If you want a *polymorphic* matcher that works with arguments
of several types (for instance, `Eq(x)` can be used to match a *`value`* as long
as `value == x` compiles -- *`value`* and `x` don't have to share the same
type), you can learn the trick from `testing/base/public/gmock-matchers.h` but
it's a bit involved.
Fortunately, most of the time you can define a polymorphic matcher easily with Fortunately, most of the time you can define a polymorphic matcher easily with
the help of `MakePolymorphicMatcher()`. Here's how you can define `NotNull()` as the help of `MakePolymorphicMatcher()`. Here's how you can define `NotNull()` as
an example: an example:

View File

@ -735,31 +735,25 @@ OutIter TransformTupleValues(Func f, const Tuple& t, OutIter out) {
return TransformTupleValuesHelper<Tuple, Func, OutIter>::Run(f, t, out); return TransformTupleValuesHelper<Tuple, Func, OutIter>::Run(f, t, out);
} }
// Implements A<T>().
template <typename T>
class AnyMatcherImpl : public MatcherInterface<const T&> {
public:
bool MatchAndExplain(const T& /* x */,
MatchResultListener* /* listener */) const override {
return true;
}
void DescribeTo(::std::ostream* os) const override { *os << "is anything"; }
void DescribeNegationTo(::std::ostream* os) const override {
// This is mostly for completeness' safe, as it's not very useful
// to write Not(A<bool>()). However we cannot completely rule out
// such a possibility, and it doesn't hurt to be prepared.
*os << "never matches";
}
};
// Implements _, a matcher that matches any value of any // Implements _, a matcher that matches any value of any
// type. This is a polymorphic matcher, so we need a template type // type. This is a polymorphic matcher, so we need a template type
// conversion operator to make it appearing as a Matcher<T> for any // conversion operator to make it appearing as a Matcher<T> for any
// type T. // type T.
class AnythingMatcher { class AnythingMatcher {
public: public:
using is_gtest_matcher = void;
template <typename T> template <typename T>
operator Matcher<T>() const { return A<T>(); } bool MatchAndExplain(const T& /* x */, std::ostream* /* listener */) const {
return true;
}
void DescribeTo(std::ostream* os) const { *os << "is anything"; }
void DescribeNegationTo(::std::ostream* os) const {
// This is mostly for completeness' sake, as it's not very useful
// to write Not(A<bool>()). However we cannot completely rule out
// such a possibility, and it doesn't hurt to be prepared.
*os << "never matches";
}
}; };
// Implements the polymorphic IsNull() matcher, which matches any raw or smart // Implements the polymorphic IsNull() matcher, which matches any raw or smart
@ -3443,7 +3437,9 @@ class UnorderedElementsAreMatcherImpl
: UnorderedElementsAreMatcherImplBase(matcher_flags) { : UnorderedElementsAreMatcherImplBase(matcher_flags) {
for (; first != last; ++first) { for (; first != last; ++first) {
matchers_.push_back(MatcherCast<const Element&>(*first)); matchers_.push_back(MatcherCast<const Element&>(*first));
matcher_describers().push_back(matchers_.back().GetDescriber()); }
for (const auto& m : matchers_) {
matcher_describers().push_back(m.GetDescriber());
} }
} }
@ -4068,12 +4064,14 @@ const internal::AnythingMatcher _ = {};
// Creates a matcher that matches any value of the given type T. // Creates a matcher that matches any value of the given type T.
template <typename T> template <typename T>
inline Matcher<T> A() { inline Matcher<T> A() {
return Matcher<T>(new internal::AnyMatcherImpl<T>()); return _;
} }
// Creates a matcher that matches any value of the given type T. // Creates a matcher that matches any value of the given type T.
template <typename T> template <typename T>
inline Matcher<T> An() { return A<T>(); } inline Matcher<T> An() {
return _;
}
template <typename T, typename M> template <typename T, typename M>
Matcher<T> internal::MatcherCastImpl<T, M>::CastImpl( Matcher<T> internal::MatcherCastImpl<T, M>::CastImpl(

View File

@ -410,7 +410,7 @@ TEST(StringMatcherTest,
// MatcherInterface* without requiring the user to explicitly // MatcherInterface* without requiring the user to explicitly
// write the type. // write the type.
TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) { TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) {
const MatcherInterface<int>* dummy_impl = nullptr; const MatcherInterface<int>* dummy_impl = new EvenMatcherImpl;
Matcher<int> m = MakeMatcher(dummy_impl); Matcher<int> m = MakeMatcher(dummy_impl);
} }

View File

@ -39,6 +39,7 @@
#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ #ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
#include <atomic>
#include <memory> #include <memory>
#include <ostream> #include <ostream>
#include <string> #include <string>
@ -63,20 +64,15 @@ GTEST_DISABLE_MSC_WARNINGS_PUSH_(
namespace testing { namespace testing {
// To implement a matcher Foo for type T, define: // To implement a matcher Foo for type T, define:
// 1. a class FooMatcherImpl that implements the // 1. a class FooMatcherMatcher that implements the matcher interface:
// MatcherInterface<T> interface, and // using is_gtest_matcher = void;
// bool MatchAndExplain(const T&, std::ostream*);
// void DescribeTo(std::ostream*);
// void DescribeNegationTo(std::ostream*);
//
// 2. a factory function that creates a Matcher<T> object from a // 2. a factory function that creates a Matcher<T> object from a
// FooMatcherImpl*. // FooMatcherMatcher.
//
// The two-level delegation design makes it possible to allow a user
// to write "v" instead of "Eq(v)" where a Matcher is expected, which
// is impossible if we pass matchers by pointers. It also eases
// ownership management as Matcher objects can now be copied like
// plain values.
// MatchResultListener is an abstract class. Its << operator can be
// used by a matcher to explain why a value matches or doesn't match.
//
class MatchResultListener { class MatchResultListener {
public: public:
// Creates a listener object with the given underlying ostream. The // Creates a listener object with the given underlying ostream. The
@ -181,31 +177,6 @@ class MatcherInterface : public MatcherDescriberInterface {
namespace internal { namespace internal {
// Converts a MatcherInterface<T> to a MatcherInterface<const T&>.
template <typename T>
class MatcherInterfaceAdapter : public MatcherInterface<const T&> {
public:
explicit MatcherInterfaceAdapter(const MatcherInterface<T>* impl)
: impl_(impl) {}
~MatcherInterfaceAdapter() override { delete impl_; }
void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); }
void DescribeNegationTo(::std::ostream* os) const override {
impl_->DescribeNegationTo(os);
}
bool MatchAndExplain(const T& x,
MatchResultListener* listener) const override {
return impl_->MatchAndExplain(x, listener);
}
private:
const MatcherInterface<T>* const impl_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter);
};
struct AnyEq { struct AnyEq {
template <typename A, typename B> template <typename A, typename B>
bool operator()(const A& a, const B& b) const { return a == b; } bool operator()(const A& a, const B& b) const { return a == b; }
@ -252,16 +223,35 @@ class StreamMatchResultListener : public MatchResultListener {
GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener);
}; };
struct SharedPayloadBase {
std::atomic<int> ref{1};
void Ref() { ref.fetch_add(1, std::memory_order_relaxed); }
bool Unref() { return ref.fetch_sub(1, std::memory_order_acq_rel) == 1; }
};
template <typename T>
struct SharedPayload : SharedPayloadBase {
explicit SharedPayload(const T& v) : value(v) {}
explicit SharedPayload(T&& v) : value(std::move(v)) {}
static void Destroy(SharedPayloadBase* shared) {
delete static_cast<SharedPayload*>(shared);
}
T value;
};
// An internal class for implementing Matcher<T>, which will derive // An internal class for implementing Matcher<T>, which will derive
// from it. We put functionalities common to all Matcher<T> // from it. We put functionalities common to all Matcher<T>
// specializations here to avoid code duplication. // specializations here to avoid code duplication.
template <typename T> template <typename T>
class MatcherBase { class MatcherBase : private MatcherDescriberInterface {
public: public:
// Returns true if and only if the matcher matches x; also explains the // Returns true if and only if the matcher matches x; also explains the
// match result to 'listener'. // match result to 'listener'.
bool MatchAndExplain(const T& x, MatchResultListener* listener) const { bool MatchAndExplain(const T& x, MatchResultListener* listener) const {
return impl_->MatchAndExplain(x, listener); GTEST_CHECK_(vtable_ != nullptr);
return vtable_->match_and_explain(*this, x, listener);
} }
// Returns true if and only if this matcher matches x. // Returns true if and only if this matcher matches x.
@ -271,11 +261,15 @@ class MatcherBase {
} }
// Describes this matcher to an ostream. // Describes this matcher to an ostream.
void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } void DescribeTo(::std::ostream* os) const final {
GTEST_CHECK_(vtable_ != nullptr);
vtable_->describe(*this, os, false);
}
// Describes the negation of this matcher to an ostream. // Describes the negation of this matcher to an ostream.
void DescribeNegationTo(::std::ostream* os) const { void DescribeNegationTo(::std::ostream* os) const final {
impl_->DescribeNegationTo(os); GTEST_CHECK_(vtable_ != nullptr);
vtable_->describe(*this, os, true);
} }
// Explains why x matches, or doesn't match, the matcher. // Explains why x matches, or doesn't match, the matcher.
@ -288,31 +282,190 @@ class MatcherBase {
// of the describer, which is only guaranteed to be alive when // of the describer, which is only guaranteed to be alive when
// this matcher object is alive. // this matcher object is alive.
const MatcherDescriberInterface* GetDescriber() const { const MatcherDescriberInterface* GetDescriber() const {
return impl_.get(); if (vtable_ == nullptr) return nullptr;
return vtable_->get_describer(*this);
} }
protected: protected:
MatcherBase() {} MatcherBase() : vtable_(nullptr) {}
// Constructs a matcher from its implementation. // Constructs a matcher from its implementation.
explicit MatcherBase(const MatcherInterface<const T&>* impl) : impl_(impl) {}
template <typename U> template <typename U>
explicit MatcherBase( explicit MatcherBase(const MatcherInterface<U>* impl) {
const MatcherInterface<U>* impl, Init(impl);
typename std::enable_if<!std::is_same<U, const U&>::value>::type* = }
nullptr)
: impl_(new internal::MatcherInterfaceAdapter<U>(impl)) {}
MatcherBase(const MatcherBase&) = default; template <typename M, typename = typename std::remove_reference<
MatcherBase& operator=(const MatcherBase&) = default; M>::type::is_gtest_matcher>
MatcherBase(MatcherBase&&) = default; MatcherBase(M&& m) { // NOLINT
MatcherBase& operator=(MatcherBase&&) = default; Init(std::forward<M>(m));
}
virtual ~MatcherBase() {} MatcherBase(const MatcherBase& other)
: vtable_(other.vtable_), buffer_(other.buffer_) {
if (IsShared()) buffer_.shared->Ref();
}
MatcherBase& operator=(const MatcherBase& other) {
if (this == &other) return *this;
Destroy();
vtable_ = other.vtable_;
buffer_ = other.buffer_;
if (IsShared()) buffer_.shared->Ref();
return *this;
}
MatcherBase(MatcherBase&& other)
: vtable_(other.vtable_), buffer_(other.buffer_) {
other.vtable_ = nullptr;
}
MatcherBase& operator=(MatcherBase&& other) {
if (this == &other) return *this;
Destroy();
vtable_ = other.vtable_;
buffer_ = other.buffer_;
other.vtable_ = nullptr;
return *this;
}
~MatcherBase() override { Destroy(); }
private: private:
std::shared_ptr<const MatcherInterface<const T&>> impl_; struct VTable {
bool (*match_and_explain)(const MatcherBase&, const T&,
MatchResultListener*);
void (*describe)(const MatcherBase&, std::ostream*, bool negation);
// Returns the captured object if it implements the interface, otherwise
// returns the MatcherBase itself.
const MatcherDescriberInterface* (*get_describer)(const MatcherBase&);
// Called on shared instances when the reference count reaches 0.
void (*shared_destroy)(SharedPayloadBase*);
};
bool IsShared() const {
return vtable_ != nullptr && vtable_->shared_destroy != nullptr;
}
// If the implementation uses a listener, call that.
template <typename P>
static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
MatchResultListener* listener)
-> decltype(P::Get(m).MatchAndExplain(value, listener->stream())) {
return P::Get(m).MatchAndExplain(value, listener->stream());
}
template <typename P>
static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
MatchResultListener* listener)
-> decltype(P::Get(m).MatchAndExplain(value, listener)) {
return P::Get(m).MatchAndExplain(value, listener);
}
template <typename P>
static void DescribeImpl(const MatcherBase& m, std::ostream* os,
bool negation) {
if (negation) {
P::Get(m).DescribeNegationTo(os);
} else {
P::Get(m).DescribeTo(os);
}
}
template <typename P>
static const MatcherDescriberInterface* GetDescriberImpl(
const MatcherBase& m) {
// If the impl is a MatcherDescriberInterface, then return it.
// Otherwise use MatcherBase itself.
// This allows us to implement the GetDescriber() function without support
// from the impl, but some users really want to get their impl back when
// they call GetDescriber().
// We use std::get on a tuple as a workaround of not having `if constexpr`.
return std::get<(
std::is_convertible<decltype(&P::Get(m)),
const MatcherDescriberInterface*>::value
? 1
: 0)>(std::make_tuple(&m, &P::Get(m)));
}
template <typename P>
const VTable* GetVTable() {
static constexpr VTable kVTable = {&MatchAndExplainImpl<P>,
&DescribeImpl<P>, &GetDescriberImpl<P>,
P::shared_destroy};
return &kVTable;
}
union Buffer {
// Add some types to give Buffer some common alignment/size use cases.
void* ptr;
double d;
int64_t i;
// And add one for the out-of-line cases.
SharedPayloadBase* shared;
};
void Destroy() {
if (IsShared() && buffer_.shared->Unref()) {
vtable_->shared_destroy(buffer_.shared);
}
}
template <typename M>
static constexpr bool IsInlined() {
return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) &&
std::is_trivially_copy_constructible<M>::value &&
std::is_trivially_destructible<M>::value;
}
template <typename M, bool = IsInlined<M>()>
struct ValuePolicy {
static const M& Get(const MatcherBase& m) {
return reinterpret_cast<const M&>(m.buffer_);
}
static void Init(MatcherBase& m, M impl) {
::new (static_cast<void*>(&m.buffer_)) M(impl);
}
static constexpr auto shared_destroy = nullptr;
};
template <typename M>
struct ValuePolicy<M, false> {
using Shared = SharedPayload<M>;
static const M& Get(const MatcherBase& m) {
return static_cast<Shared*>(m.buffer_.shared)->value;
}
template <typename Arg>
static void Init(MatcherBase& m, Arg&& arg) {
m.buffer_.shared = new Shared(std::forward<Arg>(arg));
}
static constexpr auto shared_destroy = &Shared::Destroy;
};
template <typename U, bool B>
struct ValuePolicy<const MatcherInterface<U>*, B> {
using M = const MatcherInterface<U>;
using Shared = SharedPayload<std::unique_ptr<M>>;
static const M& Get(const MatcherBase& m) {
return *static_cast<Shared*>(m.buffer_.shared)->value;
}
static void Init(MatcherBase& m, M* impl) {
m.buffer_.shared = new Shared(std::unique_ptr<M>(impl));
}
static constexpr auto shared_destroy = &Shared::Destroy;
};
template <typename M>
void Init(M&& m) {
using MM = typename std::decay<M>::type;
using Policy = ValuePolicy<MM>;
vtable_ = GetVTable<Policy>();
Policy::Init(*this, std::forward<M>(m));
}
const VTable* vtable_;
Buffer buffer_;
}; };
} // namespace internal } // namespace internal
@ -340,6 +493,10 @@ class Matcher : public internal::MatcherBase<T> {
nullptr) nullptr)
: internal::MatcherBase<T>(impl) {} : internal::MatcherBase<T>(impl) {}
template <typename M, typename = typename std::remove_reference<
M>::type::is_gtest_matcher>
Matcher(M&& m) : internal::MatcherBase<T>(std::forward<M>(m)) {} // NOLINT
// Implicit constructor here allows people to write // Implicit constructor here allows people to write
// EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes
Matcher(T value); // NOLINT Matcher(T value); // NOLINT
@ -357,6 +514,11 @@ class GTEST_API_ Matcher<const std::string&>
explicit Matcher(const MatcherInterface<const std::string&>* impl) explicit Matcher(const MatcherInterface<const std::string&>* impl)
: internal::MatcherBase<const std::string&>(impl) {} : internal::MatcherBase<const std::string&>(impl) {}
template <typename M, typename = typename std::remove_reference<
M>::type::is_gtest_matcher>
Matcher(M&& m) // NOLINT
: internal::MatcherBase<const std::string&>(std::forward<M>(m)) {}
// Allows the user to write str instead of Eq(str) sometimes, where // Allows the user to write str instead of Eq(str) sometimes, where
// str is a std::string object. // str is a std::string object.
Matcher(const std::string& s); // NOLINT Matcher(const std::string& s); // NOLINT
@ -376,6 +538,11 @@ class GTEST_API_ Matcher<std::string>
explicit Matcher(const MatcherInterface<std::string>* impl) explicit Matcher(const MatcherInterface<std::string>* impl)
: internal::MatcherBase<std::string>(impl) {} : internal::MatcherBase<std::string>(impl) {}
template <typename M, typename = typename std::remove_reference<
M>::type::is_gtest_matcher>
Matcher(M&& m) // NOLINT
: internal::MatcherBase<std::string>(std::forward<M>(m)) {}
// Allows the user to write str instead of Eq(str) sometimes, where // Allows the user to write str instead of Eq(str) sometimes, where
// str is a string object. // str is a string object.
Matcher(const std::string& s); // NOLINT Matcher(const std::string& s); // NOLINT
@ -397,6 +564,12 @@ class GTEST_API_ Matcher<const internal::StringView&>
explicit Matcher(const MatcherInterface<const internal::StringView&>* impl) explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
: internal::MatcherBase<const internal::StringView&>(impl) {} : internal::MatcherBase<const internal::StringView&>(impl) {}
template <typename M, typename = typename std::remove_reference<
M>::type::is_gtest_matcher>
Matcher(M&& m) // NOLINT
: internal::MatcherBase<const internal::StringView&>(std::forward<M>(m)) {
}
// Allows the user to write str instead of Eq(str) sometimes, where // Allows the user to write str instead of Eq(str) sometimes, where
// str is a std::string object. // str is a std::string object.
Matcher(const std::string& s); // NOLINT Matcher(const std::string& s); // NOLINT
@ -419,6 +592,11 @@ class GTEST_API_ Matcher<internal::StringView>
explicit Matcher(const MatcherInterface<internal::StringView>* impl) explicit Matcher(const MatcherInterface<internal::StringView>* impl)
: internal::MatcherBase<internal::StringView>(impl) {} : internal::MatcherBase<internal::StringView>(impl) {}
template <typename M, typename = typename std::remove_reference<
M>::type::is_gtest_matcher>
Matcher(M&& m) // NOLINT
: internal::MatcherBase<internal::StringView>(std::forward<M>(m)) {}
// Allows the user to write str instead of Eq(str) sometimes, where // Allows the user to write str instead of Eq(str) sometimes, where
// str is a std::string object. // str is a std::string object.
Matcher(const std::string& s); // NOLINT Matcher(const std::string& s); // NOLINT
@ -529,37 +707,32 @@ template <typename D, typename Rhs, typename Op>
class ComparisonBase { class ComparisonBase {
public: public:
explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {}
using is_gtest_matcher = void;
template <typename Lhs> template <typename Lhs>
operator Matcher<Lhs>() const { bool MatchAndExplain(const Lhs& lhs, std::ostream*) const {
return Matcher<Lhs>(new Impl<const Lhs&>(rhs_)); return Op()(lhs, Unwrap(rhs_));
}
void DescribeTo(std::ostream* os) const {
*os << D::Desc() << " ";
UniversalPrint(Unwrap(rhs_), os);
}
void DescribeNegationTo(std::ostream* os) const {
*os << D::NegatedDesc() << " ";
UniversalPrint(Unwrap(rhs_), os);
} }
private: private:
template <typename T> template <typename T>
static const T& Unwrap(const T& v) { return v; } static const T& Unwrap(const T& v) {
return v;
}
template <typename T> template <typename T>
static const T& Unwrap(std::reference_wrapper<T> v) { return v; } static const T& Unwrap(std::reference_wrapper<T> v) {
return v;
}
template <typename Lhs, typename = Rhs>
class Impl : public MatcherInterface<Lhs> {
public:
explicit Impl(const Rhs& rhs) : rhs_(rhs) {}
bool MatchAndExplain(Lhs lhs,
MatchResultListener* /* listener */) const override {
return Op()(lhs, Unwrap(rhs_));
}
void DescribeTo(::std::ostream* os) const override {
*os << D::Desc() << " ";
UniversalPrint(Unwrap(rhs_), os);
}
void DescribeNegationTo(::std::ostream* os) const override {
*os << D::NegatedDesc() << " ";
UniversalPrint(Unwrap(rhs_), os);
}
private:
Rhs rhs_;
};
Rhs rhs_; Rhs rhs_;
}; };