Adds the ReturnArg<k>() action (by Tim Hockin); refactors gmock-matchers.h (by Zhanyong Wan).

This commit is contained in:
zhanyong.wan 2009-07-21 23:26:31 +00:00
parent 387bdd551d
commit 1afe1c7971
6 changed files with 249 additions and 444 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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:\

View File

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

View File

@ -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().

View File

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