Adds the ReturnArg<k>() action (by Tim Hockin); refactors gmock-matchers.h (by Zhanyong Wan).
This commit is contained in:
parent
387bdd551d
commit
1afe1c7971
|
@ -2441,6 +2441,13 @@ ACTION_TEMPLATE(InvokeArgument,
|
|||
::std::tr1::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
|
||||
}
|
||||
|
||||
// Action ReturnArg<k>() returns the k-th argument of the mock function.
|
||||
ACTION_TEMPLATE(ReturnArg,
|
||||
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||
AND_0_VALUE_PARAMS()) {
|
||||
return std::tr1::get<k>(args);
|
||||
}
|
||||
|
||||
// Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the
|
||||
// mock function to *pointer.
|
||||
ACTION_TEMPLATE(SaveArg,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$$ This is a Pump source file. Please use Pump to convert it to
|
||||
$$ gmock-generated-variadic-actions.h.
|
||||
$$ gmock-generated-actions.h.
|
||||
$$
|
||||
$var n = 10 $$ The maximum arity we support.
|
||||
$$}} This meta comment fixes auto-indentation in editors.
|
||||
|
@ -940,6 +940,13 @@ ACTION_TEMPLATE(InvokeArgument,
|
|||
|
||||
]]
|
||||
|
||||
// Action ReturnArg<k>() returns the k-th argument of the mock function.
|
||||
ACTION_TEMPLATE(ReturnArg,
|
||||
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||
AND_0_VALUE_PARAMS()) {
|
||||
return std::tr1::get<k>(args);
|
||||
}
|
||||
|
||||
// Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the
|
||||
// mock function to *pointer.
|
||||
ACTION_TEMPLATE(SaveArg,
|
||||
|
|
|
@ -290,163 +290,7 @@ class ArgsMatcher {
|
|||
const InnerMatcher inner_matcher_;
|
||||
};
|
||||
|
||||
// Implements ElementsAre() and ElementsAreArray().
|
||||
template <typename Container>
|
||||
class ElementsAreMatcherImpl : public MatcherInterface<Container> {
|
||||
public:
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
|
||||
typedef internal::StlContainerView<RawContainer> View;
|
||||
typedef typename View::type StlContainer;
|
||||
typedef typename View::const_reference StlContainerReference;
|
||||
typedef typename StlContainer::value_type Element;
|
||||
|
||||
// Constructs the matcher from a sequence of element values or
|
||||
// element matchers.
|
||||
template <typename InputIter>
|
||||
ElementsAreMatcherImpl(InputIter first, size_t count) {
|
||||
matchers_.reserve(count);
|
||||
InputIter it = first;
|
||||
for (size_t i = 0; i != count; ++i, ++it) {
|
||||
matchers_.push_back(MatcherCast<const Element&>(*it));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true iff 'container' matches.
|
||||
virtual bool Matches(Container container) const {
|
||||
StlContainerReference stl_container = View::ConstReference(container);
|
||||
if (stl_container.size() != count())
|
||||
return false;
|
||||
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
if (!matchers_[i].Matches(*it))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Describes what this matcher does.
|
||||
virtual void DescribeTo(::std::ostream* os) const {
|
||||
if (count() == 0) {
|
||||
*os << "is empty";
|
||||
} else if (count() == 1) {
|
||||
*os << "has 1 element that ";
|
||||
matchers_[0].DescribeTo(os);
|
||||
} else {
|
||||
*os << "has " << Elements(count()) << " where\n";
|
||||
for (size_t i = 0; i != count(); ++i) {
|
||||
*os << "element " << i << " ";
|
||||
matchers_[i].DescribeTo(os);
|
||||
if (i + 1 < count()) {
|
||||
*os << ",\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Describes what the negation of this matcher does.
|
||||
virtual void DescribeNegationTo(::std::ostream* os) const {
|
||||
if (count() == 0) {
|
||||
*os << "is not empty";
|
||||
return;
|
||||
}
|
||||
|
||||
*os << "does not have " << Elements(count()) << ", or\n";
|
||||
for (size_t i = 0; i != count(); ++i) {
|
||||
*os << "element " << i << " ";
|
||||
matchers_[i].DescribeNegationTo(os);
|
||||
if (i + 1 < count()) {
|
||||
*os << ", or\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explains why 'container' matches, or doesn't match, this matcher.
|
||||
virtual void ExplainMatchResultTo(Container container,
|
||||
::std::ostream* os) const {
|
||||
StlContainerReference stl_container = View::ConstReference(container);
|
||||
if (Matches(container)) {
|
||||
// We need to explain why *each* element matches (the obvious
|
||||
// ones can be skipped).
|
||||
|
||||
bool reason_printed = false;
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
::std::stringstream ss;
|
||||
matchers_[i].ExplainMatchResultTo(*it, &ss);
|
||||
|
||||
const string s = ss.str();
|
||||
if (!s.empty()) {
|
||||
if (reason_printed) {
|
||||
*os << ",\n";
|
||||
}
|
||||
*os << "element " << i << " " << s;
|
||||
reason_printed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We need to explain why the container doesn't match.
|
||||
const size_t actual_count = stl_container.size();
|
||||
if (actual_count != count()) {
|
||||
// The element count doesn't match. If the container is
|
||||
// empty, there's no need to explain anything as Google Mock
|
||||
// already prints the empty container. Otherwise we just need
|
||||
// to show how many elements there actually are.
|
||||
if (actual_count != 0) {
|
||||
*os << "has " << Elements(actual_count);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// The container has the right size but at least one element
|
||||
// doesn't match expectation. We need to find this element and
|
||||
// explain why it doesn't match.
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
if (matchers_[i].Matches(*it)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*os << "element " << i << " doesn't match";
|
||||
|
||||
::std::stringstream ss;
|
||||
matchers_[i].ExplainMatchResultTo(*it, &ss);
|
||||
const string s = ss.str();
|
||||
if (!s.empty()) {
|
||||
*os << " (" << s << ")";
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static Message Elements(size_t count) {
|
||||
return Message() << count << (count == 1 ? " element" : " elements");
|
||||
}
|
||||
|
||||
size_t count() const { return matchers_.size(); }
|
||||
std::vector<Matcher<const Element&> > matchers_;
|
||||
};
|
||||
|
||||
// Implements ElementsAre() of 0-10 arguments.
|
||||
|
||||
class ElementsAreMatcher0 {
|
||||
public:
|
||||
ElementsAreMatcher0() {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const {
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
|
||||
RawContainer;
|
||||
typedef typename internal::StlContainerView<RawContainer>::type::value_type
|
||||
Element;
|
||||
|
||||
const Matcher<const Element&>* const matchers = NULL;
|
||||
return MakeMatcher(new ElementsAreMatcherImpl<Container>(matchers, 0));
|
||||
}
|
||||
};
|
||||
// Implements ElementsAre() of 1-10 arguments.
|
||||
|
||||
template <typename T1>
|
||||
class ElementsAreMatcher1 {
|
||||
|
@ -788,28 +632,6 @@ class ElementsAreMatcher10 {
|
|||
const T10& e10_;
|
||||
};
|
||||
|
||||
// Implements ElementsAreArray().
|
||||
template <typename T>
|
||||
class ElementsAreArrayMatcher {
|
||||
public:
|
||||
ElementsAreArrayMatcher(const T* first, size_t count) :
|
||||
first_(first), count_(count) {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const {
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
|
||||
RawContainer;
|
||||
typedef typename internal::StlContainerView<RawContainer>::type::value_type
|
||||
Element;
|
||||
|
||||
return MakeMatcher(new ElementsAreMatcherImpl<Container>(first_, count_));
|
||||
}
|
||||
|
||||
private:
|
||||
const T* const first_;
|
||||
const size_t count_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Args<N1, N2, ..., Nk>(a_matcher) matches a tuple if the selected
|
||||
|
@ -1169,48 +991,6 @@ ElementsAreArray(const T (&array)[N]) {
|
|||
// To learn more about using these macros, please search for 'MATCHER'
|
||||
// on http://code.google.com/p/googlemock/wiki/CookBook.
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// Constants denoting interpolations in a matcher description string.
|
||||
const int kTupleInterpolation = -1; // "%(*)s"
|
||||
const int kPercentInterpolation = -2; // "%%"
|
||||
const int kInvalidInterpolation = -3; // "%" followed by invalid text
|
||||
|
||||
// Records the location and content of an interpolation.
|
||||
struct Interpolation {
|
||||
Interpolation(const char* start, const char* end, int param)
|
||||
: start_pos(start), end_pos(end), param_index(param) {}
|
||||
|
||||
// Points to the start of the interpolation (the '%' character).
|
||||
const char* start_pos;
|
||||
// Points to the first character after the interpolation.
|
||||
const char* end_pos;
|
||||
// 0-based index of the interpolated matcher parameter;
|
||||
// kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%".
|
||||
int param_index;
|
||||
};
|
||||
|
||||
typedef ::std::vector<Interpolation> Interpolations;
|
||||
|
||||
// Parses a matcher description string and returns a vector of
|
||||
// interpolations that appear in the string; generates non-fatal
|
||||
// failures iff 'description' is an invalid matcher description.
|
||||
// 'param_names' is a NULL-terminated array of parameter names in the
|
||||
// order they appear in the MATCHER_P*() parameter list.
|
||||
Interpolations ValidateMatcherDescription(
|
||||
const char* param_names[], const char* description);
|
||||
|
||||
// Returns the actual matcher description, given the matcher name,
|
||||
// user-supplied description template string, interpolations in the
|
||||
// string, and the printed values of the matcher parameters.
|
||||
string FormatMatcherDescription(
|
||||
const char* matcher_name, const char* description,
|
||||
const Interpolations& interp, const Strings& param_values);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#define MATCHER(name, description)\
|
||||
class name##Matcher {\
|
||||
public:\
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$$ This is a Pump source file. Please use Pump to convert it to
|
||||
$$ gmock-generated-variadic-actions.h.
|
||||
$$ gmock-generated-actions.h.
|
||||
$$
|
||||
$var n = 10 $$ The maximum arity we support.
|
||||
$$ }} This line fixes auto-indentation of the following code in Emacs.
|
||||
|
@ -173,163 +173,7 @@ class ArgsMatcher {
|
|||
const InnerMatcher inner_matcher_;
|
||||
};
|
||||
|
||||
// Implements ElementsAre() and ElementsAreArray().
|
||||
template <typename Container>
|
||||
class ElementsAreMatcherImpl : public MatcherInterface<Container> {
|
||||
public:
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
|
||||
typedef internal::StlContainerView<RawContainer> View;
|
||||
typedef typename View::type StlContainer;
|
||||
typedef typename View::const_reference StlContainerReference;
|
||||
typedef typename StlContainer::value_type Element;
|
||||
|
||||
// Constructs the matcher from a sequence of element values or
|
||||
// element matchers.
|
||||
template <typename InputIter>
|
||||
ElementsAreMatcherImpl(InputIter first, size_t count) {
|
||||
matchers_.reserve(count);
|
||||
InputIter it = first;
|
||||
for (size_t i = 0; i != count; ++i, ++it) {
|
||||
matchers_.push_back(MatcherCast<const Element&>(*it));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true iff 'container' matches.
|
||||
virtual bool Matches(Container container) const {
|
||||
StlContainerReference stl_container = View::ConstReference(container);
|
||||
if (stl_container.size() != count())
|
||||
return false;
|
||||
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
if (!matchers_[i].Matches(*it))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Describes what this matcher does.
|
||||
virtual void DescribeTo(::std::ostream* os) const {
|
||||
if (count() == 0) {
|
||||
*os << "is empty";
|
||||
} else if (count() == 1) {
|
||||
*os << "has 1 element that ";
|
||||
matchers_[0].DescribeTo(os);
|
||||
} else {
|
||||
*os << "has " << Elements(count()) << " where\n";
|
||||
for (size_t i = 0; i != count(); ++i) {
|
||||
*os << "element " << i << " ";
|
||||
matchers_[i].DescribeTo(os);
|
||||
if (i + 1 < count()) {
|
||||
*os << ",\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Describes what the negation of this matcher does.
|
||||
virtual void DescribeNegationTo(::std::ostream* os) const {
|
||||
if (count() == 0) {
|
||||
*os << "is not empty";
|
||||
return;
|
||||
}
|
||||
|
||||
*os << "does not have " << Elements(count()) << ", or\n";
|
||||
for (size_t i = 0; i != count(); ++i) {
|
||||
*os << "element " << i << " ";
|
||||
matchers_[i].DescribeNegationTo(os);
|
||||
if (i + 1 < count()) {
|
||||
*os << ", or\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explains why 'container' matches, or doesn't match, this matcher.
|
||||
virtual void ExplainMatchResultTo(Container container,
|
||||
::std::ostream* os) const {
|
||||
StlContainerReference stl_container = View::ConstReference(container);
|
||||
if (Matches(container)) {
|
||||
// We need to explain why *each* element matches (the obvious
|
||||
// ones can be skipped).
|
||||
|
||||
bool reason_printed = false;
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
::std::stringstream ss;
|
||||
matchers_[i].ExplainMatchResultTo(*it, &ss);
|
||||
|
||||
const string s = ss.str();
|
||||
if (!s.empty()) {
|
||||
if (reason_printed) {
|
||||
*os << ",\n";
|
||||
}
|
||||
*os << "element " << i << " " << s;
|
||||
reason_printed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We need to explain why the container doesn't match.
|
||||
const size_t actual_count = stl_container.size();
|
||||
if (actual_count != count()) {
|
||||
// The element count doesn't match. If the container is
|
||||
// empty, there's no need to explain anything as Google Mock
|
||||
// already prints the empty container. Otherwise we just need
|
||||
// to show how many elements there actually are.
|
||||
if (actual_count != 0) {
|
||||
*os << "has " << Elements(actual_count);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// The container has the right size but at least one element
|
||||
// doesn't match expectation. We need to find this element and
|
||||
// explain why it doesn't match.
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
if (matchers_[i].Matches(*it)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*os << "element " << i << " doesn't match";
|
||||
|
||||
::std::stringstream ss;
|
||||
matchers_[i].ExplainMatchResultTo(*it, &ss);
|
||||
const string s = ss.str();
|
||||
if (!s.empty()) {
|
||||
*os << " (" << s << ")";
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static Message Elements(size_t count) {
|
||||
return Message() << count << (count == 1 ? " element" : " elements");
|
||||
}
|
||||
|
||||
size_t count() const { return matchers_.size(); }
|
||||
std::vector<Matcher<const Element&> > matchers_;
|
||||
};
|
||||
|
||||
// Implements ElementsAre() of 0-10 arguments.
|
||||
|
||||
class ElementsAreMatcher0 {
|
||||
public:
|
||||
ElementsAreMatcher0() {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const {
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
|
||||
RawContainer;
|
||||
typedef typename internal::StlContainerView<RawContainer>::type::value_type
|
||||
Element;
|
||||
|
||||
const Matcher<const Element&>* const matchers = NULL;
|
||||
return MakeMatcher(new ElementsAreMatcherImpl<Container>(matchers, 0));
|
||||
}
|
||||
};
|
||||
// Implements ElementsAre() of 1-$n arguments.
|
||||
|
||||
|
||||
$range i 1..n
|
||||
|
@ -369,28 +213,6 @@ $for j [[
|
|||
|
||||
|
||||
]]
|
||||
// Implements ElementsAreArray().
|
||||
template <typename T>
|
||||
class ElementsAreArrayMatcher {
|
||||
public:
|
||||
ElementsAreArrayMatcher(const T* first, size_t count) :
|
||||
first_(first), count_(count) {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const {
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
|
||||
RawContainer;
|
||||
typedef typename internal::StlContainerView<RawContainer>::type::value_type
|
||||
Element;
|
||||
|
||||
return MakeMatcher(new ElementsAreMatcherImpl<Container>(first_, count_));
|
||||
}
|
||||
|
||||
private:
|
||||
const T* const first_;
|
||||
const size_t count_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Args<N1, N2, ..., Nk>(a_matcher) matches a tuple if the selected
|
||||
|
@ -625,48 +447,6 @@ $$ // show up in the generated code.
|
|||
// To learn more about using these macros, please search for 'MATCHER'
|
||||
// on http://code.google.com/p/googlemock/wiki/CookBook.
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// Constants denoting interpolations in a matcher description string.
|
||||
const int kTupleInterpolation = -1; // "%(*)s"
|
||||
const int kPercentInterpolation = -2; // "%%"
|
||||
const int kInvalidInterpolation = -3; // "%" followed by invalid text
|
||||
|
||||
// Records the location and content of an interpolation.
|
||||
struct Interpolation {
|
||||
Interpolation(const char* start, const char* end, int param)
|
||||
: start_pos(start), end_pos(end), param_index(param) {}
|
||||
|
||||
// Points to the start of the interpolation (the '%' character).
|
||||
const char* start_pos;
|
||||
// Points to the first character after the interpolation.
|
||||
const char* end_pos;
|
||||
// 0-based index of the interpolated matcher parameter;
|
||||
// kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%".
|
||||
int param_index;
|
||||
};
|
||||
|
||||
typedef ::std::vector<Interpolation> Interpolations;
|
||||
|
||||
// Parses a matcher description string and returns a vector of
|
||||
// interpolations that appear in the string; generates non-fatal
|
||||
// failures iff 'description' is an invalid matcher description.
|
||||
// 'param_names' is a NULL-terminated array of parameter names in the
|
||||
// order they appear in the MATCHER_P*() parameter list.
|
||||
Interpolations ValidateMatcherDescription(
|
||||
const char* param_names[], const char* description);
|
||||
|
||||
// Returns the actual matcher description, given the matcher name,
|
||||
// user-supplied description template string, interpolations in the
|
||||
// string, and the printed values of the matcher parameters.
|
||||
string FormatMatcherDescription(
|
||||
const char* matcher_name, const char* description,
|
||||
const Interpolations& interp, const Strings& param_values);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
$range i 0..n
|
||||
$for i
|
||||
|
||||
|
|
|
@ -1925,6 +1925,221 @@ class KeyMatcher {
|
|||
const M matcher_for_key_;
|
||||
};
|
||||
|
||||
// Implements ElementsAre() and ElementsAreArray().
|
||||
template <typename Container>
|
||||
class ElementsAreMatcherImpl : public MatcherInterface<Container> {
|
||||
public:
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
|
||||
typedef internal::StlContainerView<RawContainer> View;
|
||||
typedef typename View::type StlContainer;
|
||||
typedef typename View::const_reference StlContainerReference;
|
||||
typedef typename StlContainer::value_type Element;
|
||||
|
||||
// Constructs the matcher from a sequence of element values or
|
||||
// element matchers.
|
||||
template <typename InputIter>
|
||||
ElementsAreMatcherImpl(InputIter first, size_t count) {
|
||||
matchers_.reserve(count);
|
||||
InputIter it = first;
|
||||
for (size_t i = 0; i != count; ++i, ++it) {
|
||||
matchers_.push_back(MatcherCast<const Element&>(*it));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true iff 'container' matches.
|
||||
virtual bool Matches(Container container) const {
|
||||
StlContainerReference stl_container = View::ConstReference(container);
|
||||
if (stl_container.size() != count())
|
||||
return false;
|
||||
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
if (!matchers_[i].Matches(*it))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Describes what this matcher does.
|
||||
virtual void DescribeTo(::std::ostream* os) const {
|
||||
if (count() == 0) {
|
||||
*os << "is empty";
|
||||
} else if (count() == 1) {
|
||||
*os << "has 1 element that ";
|
||||
matchers_[0].DescribeTo(os);
|
||||
} else {
|
||||
*os << "has " << Elements(count()) << " where\n";
|
||||
for (size_t i = 0; i != count(); ++i) {
|
||||
*os << "element " << i << " ";
|
||||
matchers_[i].DescribeTo(os);
|
||||
if (i + 1 < count()) {
|
||||
*os << ",\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Describes what the negation of this matcher does.
|
||||
virtual void DescribeNegationTo(::std::ostream* os) const {
|
||||
if (count() == 0) {
|
||||
*os << "is not empty";
|
||||
return;
|
||||
}
|
||||
|
||||
*os << "does not have " << Elements(count()) << ", or\n";
|
||||
for (size_t i = 0; i != count(); ++i) {
|
||||
*os << "element " << i << " ";
|
||||
matchers_[i].DescribeNegationTo(os);
|
||||
if (i + 1 < count()) {
|
||||
*os << ", or\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explains why 'container' matches, or doesn't match, this matcher.
|
||||
virtual void ExplainMatchResultTo(Container container,
|
||||
::std::ostream* os) const {
|
||||
StlContainerReference stl_container = View::ConstReference(container);
|
||||
if (Matches(container)) {
|
||||
// We need to explain why *each* element matches (the obvious
|
||||
// ones can be skipped).
|
||||
|
||||
bool reason_printed = false;
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
::std::stringstream ss;
|
||||
matchers_[i].ExplainMatchResultTo(*it, &ss);
|
||||
|
||||
const string s = ss.str();
|
||||
if (!s.empty()) {
|
||||
if (reason_printed) {
|
||||
*os << ",\n";
|
||||
}
|
||||
*os << "element " << i << " " << s;
|
||||
reason_printed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We need to explain why the container doesn't match.
|
||||
const size_t actual_count = stl_container.size();
|
||||
if (actual_count != count()) {
|
||||
// The element count doesn't match. If the container is
|
||||
// empty, there's no need to explain anything as Google Mock
|
||||
// already prints the empty container. Otherwise we just need
|
||||
// to show how many elements there actually are.
|
||||
if (actual_count != 0) {
|
||||
*os << "has " << Elements(actual_count);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// The container has the right size but at least one element
|
||||
// doesn't match expectation. We need to find this element and
|
||||
// explain why it doesn't match.
|
||||
typename StlContainer::const_iterator it = stl_container.begin();
|
||||
for (size_t i = 0; i != count(); ++it, ++i) {
|
||||
if (matchers_[i].Matches(*it)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*os << "element " << i << " doesn't match";
|
||||
|
||||
::std::stringstream ss;
|
||||
matchers_[i].ExplainMatchResultTo(*it, &ss);
|
||||
const string s = ss.str();
|
||||
if (!s.empty()) {
|
||||
*os << " (" << s << ")";
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static Message Elements(size_t count) {
|
||||
return Message() << count << (count == 1 ? " element" : " elements");
|
||||
}
|
||||
|
||||
size_t count() const { return matchers_.size(); }
|
||||
std::vector<Matcher<const Element&> > matchers_;
|
||||
};
|
||||
|
||||
// Implements ElementsAre() of 0 arguments.
|
||||
class ElementsAreMatcher0 {
|
||||
public:
|
||||
ElementsAreMatcher0() {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const {
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
|
||||
RawContainer;
|
||||
typedef typename internal::StlContainerView<RawContainer>::type::value_type
|
||||
Element;
|
||||
|
||||
const Matcher<const Element&>* const matchers = NULL;
|
||||
return MakeMatcher(new ElementsAreMatcherImpl<Container>(matchers, 0));
|
||||
}
|
||||
};
|
||||
|
||||
// Implements ElementsAreArray().
|
||||
template <typename T>
|
||||
class ElementsAreArrayMatcher {
|
||||
public:
|
||||
ElementsAreArrayMatcher(const T* first, size_t count) :
|
||||
first_(first), count_(count) {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const {
|
||||
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
|
||||
RawContainer;
|
||||
typedef typename internal::StlContainerView<RawContainer>::type::value_type
|
||||
Element;
|
||||
|
||||
return MakeMatcher(new ElementsAreMatcherImpl<Container>(first_, count_));
|
||||
}
|
||||
|
||||
private:
|
||||
const T* const first_;
|
||||
const size_t count_;
|
||||
};
|
||||
|
||||
// Constants denoting interpolations in a matcher description string.
|
||||
const int kTupleInterpolation = -1; // "%(*)s"
|
||||
const int kPercentInterpolation = -2; // "%%"
|
||||
const int kInvalidInterpolation = -3; // "%" followed by invalid text
|
||||
|
||||
// Records the location and content of an interpolation.
|
||||
struct Interpolation {
|
||||
Interpolation(const char* start, const char* end, int param)
|
||||
: start_pos(start), end_pos(end), param_index(param) {}
|
||||
|
||||
// Points to the start of the interpolation (the '%' character).
|
||||
const char* start_pos;
|
||||
// Points to the first character after the interpolation.
|
||||
const char* end_pos;
|
||||
// 0-based index of the interpolated matcher parameter;
|
||||
// kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%".
|
||||
int param_index;
|
||||
};
|
||||
|
||||
typedef ::std::vector<Interpolation> Interpolations;
|
||||
|
||||
// Parses a matcher description string and returns a vector of
|
||||
// interpolations that appear in the string; generates non-fatal
|
||||
// failures iff 'description' is an invalid matcher description.
|
||||
// 'param_names' is a NULL-terminated array of parameter names in the
|
||||
// order they appear in the MATCHER_P*() parameter list.
|
||||
Interpolations ValidateMatcherDescription(
|
||||
const char* param_names[], const char* description);
|
||||
|
||||
// Returns the actual matcher description, given the matcher name,
|
||||
// user-supplied description template string, interpolations in the
|
||||
// string, and the printed values of the matcher parameters.
|
||||
string FormatMatcherDescription(
|
||||
const char* matcher_name, const char* description,
|
||||
const Interpolations& interp, const Strings& param_values);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Implements MatcherCast().
|
||||
|
|
|
@ -59,6 +59,7 @@ using testing::DoAll;
|
|||
using testing::Invoke;
|
||||
using testing::InvokeArgument;
|
||||
using testing::Return;
|
||||
using testing::ReturnArg;
|
||||
using testing::ReturnNew;
|
||||
using testing::SaveArg;
|
||||
using testing::SetArgReferee;
|
||||
|
@ -1382,6 +1383,21 @@ TEST(ActionPnMacroTest, CanExplicitlyInstantiateWithReferenceTypes) {
|
|||
EXPECT_EQ(55, a.Perform(empty));
|
||||
}
|
||||
|
||||
TEST(ReturnArgActionTest, WorksForOneArgIntArg0) {
|
||||
const Action<int(int)> a = ReturnArg<0>();
|
||||
EXPECT_EQ(5, a.Perform(make_tuple(5)));
|
||||
}
|
||||
|
||||
TEST(ReturnArgActionTest, WorksForMultiArgBoolArg0) {
|
||||
const Action<bool(bool, bool, bool)> a = ReturnArg<0>();
|
||||
EXPECT_TRUE(a.Perform(make_tuple(true, false, false)));
|
||||
}
|
||||
|
||||
TEST(ReturnArgActionTest, WorksForMultiArgStringArg2) {
|
||||
const Action<string(int, int, string, int)> a = ReturnArg<2>();
|
||||
EXPECT_EQ("seven", a.Perform(make_tuple(5, 6, string("seven"), 8)));
|
||||
}
|
||||
|
||||
TEST(SaveArgActionTest, WorksForSameType) {
|
||||
int result = 0;
|
||||
const Action<void(int n)> a1 = SaveArg<0>(&result);
|
||||
|
|
Loading…
Reference in New Issue
Block a user