Makes all container matchers work with (possibly multi-dimensional) native arrays; makes Contains() accept a matcher; adds Value(x, m); improves gmock doctor to diagnose the Type in Template Base disease.

This commit is contained in:
zhanyong.wan
2009-06-04 05:48:20 +00:00
parent c2ad46a5df
commit b82431625d
12 changed files with 1026 additions and 162 deletions

View File

@@ -50,7 +50,10 @@ template <typename Container>
class ElementsAreMatcherImpl : public MatcherInterface<Container> {
public:
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
typedef typename RawContainer::value_type Element;
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.
@@ -65,12 +68,13 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
// Returns true iff 'container' matches.
virtual bool Matches(Container container) const {
if (container.size() != count())
StlContainerReference stl_container = View::ConstReference(container);
if (stl_container.size() != count())
return false;
typename RawContainer::const_iterator container_iter = container.begin();
for (size_t i = 0; i != count(); ++container_iter, ++i) {
if (!matchers_[i].Matches(*container_iter))
typename StlContainer::const_iterator it = stl_container.begin();
for (size_t i = 0; i != count(); ++it, ++i) {
if (!matchers_[i].Matches(*it))
return false;
}
@@ -116,15 +120,16 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
// 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 RawContainer::const_iterator container_iter = container.begin();
for (size_t i = 0; i != count(); ++container_iter, ++i) {
typename StlContainer::const_iterator it = stl_container.begin();
for (size_t i = 0; i != count(); ++it, ++i) {
::std::stringstream ss;
matchers_[i].ExplainMatchResultTo(*container_iter, &ss);
matchers_[i].ExplainMatchResultTo(*it, &ss);
const string s = ss.str();
if (!s.empty()) {
@@ -137,7 +142,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
}
} else {
// We need to explain why the container doesn't match.
const size_t actual_count = container.size();
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
@@ -152,16 +157,16 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
// 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 RawContainer::const_iterator container_iter = container.begin();
for (size_t i = 0; i != count(); ++container_iter, ++i) {
if (matchers_[i].Matches(*container_iter)) {
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(*container_iter, &ss);
matchers_[i].ExplainMatchResultTo(*it, &ss);
const string s = ss.str();
if (!s.empty()) {
*os << " (" << s << ")";
@@ -190,7 +195,8 @@ class ElementsAreMatcher0 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&>* const matchers = NULL;
return MakeMatcher(new ElementsAreMatcherImpl<Container>(matchers, 0));
@@ -206,7 +212,8 @@ class ElementsAreMatcher1 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -228,7 +235,8 @@ class ElementsAreMatcher2 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -253,7 +261,8 @@ class ElementsAreMatcher3 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -280,7 +289,8 @@ class ElementsAreMatcher4 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -309,7 +319,8 @@ class ElementsAreMatcher5 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -342,7 +353,8 @@ class ElementsAreMatcher6 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -377,7 +389,8 @@ class ElementsAreMatcher7 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -414,7 +427,8 @@ class ElementsAreMatcher8 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -454,7 +468,8 @@ class ElementsAreMatcher9 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -496,7 +511,8 @@ class ElementsAreMatcher10 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
MatcherCast<const Element&>(e1_),
@@ -538,7 +554,8 @@ class ElementsAreArrayMatcher {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
return MakeMatcher(new ElementsAreMatcherImpl<Container>(first_, count_));
}
@@ -1573,45 +1590,4 @@ string FormatMatcherDescription(
p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>::\
gmock_Impl<arg_type>::Matches(arg_type arg) const
namespace testing {
namespace internal {
// Returns true iff element is in the STL-style container.
template <typename Container, typename Element>
inline bool Contains(const Container& container, const Element& element) {
return ::std::find(container.begin(), container.end(), element) !=
container.end();
}
// Returns true iff element is in the C-style array.
template <typename ArrayElement, size_t N, typename Element>
inline bool Contains(const ArrayElement (&array)[N], const Element& element) {
return ::std::find(array, array + N, element) != array + N;
}
} // namespace internal
// Matches an STL-style container or a C-style array that contains the given
// element.
//
// Examples:
// ::std::set<int> page_ids;
// page_ids.insert(3);
// page_ids.insert(1);
// EXPECT_THAT(page_ids, Contains(1));
// EXPECT_THAT(page_ids, Contains(3.0));
// EXPECT_THAT(page_ids, Not(Contains(4)));
//
// ::std::map<int, size_t> page_lengths;
// page_lengths[1] = 100;
// EXPECT_THAT(map_int, Contains(::std::pair<const int, size_t>(1, 100)));
//
// const char* user_ids[] = { "joe", "mike", "tom" };
// EXPECT_THAT(user_ids, Contains(::std::string("tom")));
MATCHER_P(Contains, element, "") {
return internal::Contains(arg, element);
}
} // namespace testing
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_

View File

@@ -53,7 +53,10 @@ template <typename Container>
class ElementsAreMatcherImpl : public MatcherInterface<Container> {
public:
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
typedef typename RawContainer::value_type Element;
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.
@@ -68,12 +71,13 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
// Returns true iff 'container' matches.
virtual bool Matches(Container container) const {
if (container.size() != count())
StlContainerReference stl_container = View::ConstReference(container);
if (stl_container.size() != count())
return false;
typename RawContainer::const_iterator container_iter = container.begin();
for (size_t i = 0; i != count(); ++container_iter, ++i) {
if (!matchers_[i].Matches(*container_iter))
typename StlContainer::const_iterator it = stl_container.begin();
for (size_t i = 0; i != count(); ++it, ++i) {
if (!matchers_[i].Matches(*it))
return false;
}
@@ -119,15 +123,16 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
// 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 RawContainer::const_iterator container_iter = container.begin();
for (size_t i = 0; i != count(); ++container_iter, ++i) {
typename StlContainer::const_iterator it = stl_container.begin();
for (size_t i = 0; i != count(); ++it, ++i) {
::std::stringstream ss;
matchers_[i].ExplainMatchResultTo(*container_iter, &ss);
matchers_[i].ExplainMatchResultTo(*it, &ss);
const string s = ss.str();
if (!s.empty()) {
@@ -140,7 +145,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
}
} else {
// We need to explain why the container doesn't match.
const size_t actual_count = container.size();
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
@@ -155,16 +160,16 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
// 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 RawContainer::const_iterator container_iter = container.begin();
for (size_t i = 0; i != count(); ++container_iter, ++i) {
if (matchers_[i].Matches(*container_iter)) {
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(*container_iter, &ss);
matchers_[i].ExplainMatchResultTo(*it, &ss);
const string s = ss.str();
if (!s.empty()) {
*os << " (" << s << ")";
@@ -193,7 +198,8 @@ class ElementsAreMatcher0 {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&>* const matchers = NULL;
return MakeMatcher(new ElementsAreMatcherImpl<Container>(matchers, 0));
@@ -214,7 +220,8 @@ class ElementsAreMatcher$i {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
const Matcher<const Element&> matchers[] = {
@@ -248,7 +255,8 @@ class ElementsAreArrayMatcher {
operator Matcher<Container>() const {
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
RawContainer;
typedef typename RawContainer::value_type Element;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
return MakeMatcher(new ElementsAreMatcherImpl<Container>(first_, count_));
}
@@ -590,45 +598,4 @@ $var param_field_decls2 = [[$for j
]]
namespace testing {
namespace internal {
// Returns true iff element is in the STL-style container.
template <typename Container, typename Element>
inline bool Contains(const Container& container, const Element& element) {
return ::std::find(container.begin(), container.end(), element) !=
container.end();
}
// Returns true iff element is in the C-style array.
template <typename ArrayElement, size_t N, typename Element>
inline bool Contains(const ArrayElement (&array)[N], const Element& element) {
return ::std::find(array, array + N, element) != array + N;
}
} // namespace internal
// Matches an STL-style container or a C-style array that contains the given
// element.
//
// Examples:
// ::std::set<int> page_ids;
// page_ids.insert(3);
// page_ids.insert(1);
// EXPECT_THAT(page_ids, Contains(1));
// EXPECT_THAT(page_ids, Contains(3.0));
// EXPECT_THAT(page_ids, Not(Contains(4)));
//
// ::std::map<int, size_t> page_lengths;
// page_lengths[1] = 100;
// EXPECT_THAT(map_int, Contains(::std::pair<const int, size_t>(1, 100)));
//
// const char* user_ids[] = { "joe", "mike", "tom" };
// EXPECT_THAT(user_ids, Contains(::std::string("tom")));
MATCHER_P(Contains, element, "") {
return internal::Contains(arg, element);
}
} // namespace testing
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_

View File

@@ -1709,60 +1709,164 @@ void ExplainMatchResultTo(const ResultOfMatcher<Callable>& matcher,
template <typename Container>
class ContainerEqMatcher {
public:
explicit ContainerEqMatcher(const Container& rhs) : rhs_(rhs) {}
bool Matches(const Container& lhs) const { return lhs == rhs_; }
typedef internal::StlContainerView<Container> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
// We make a copy of rhs in case the elements in it are modified
// after this matcher is created.
explicit ContainerEqMatcher(const Container& rhs) : rhs_(View::Copy(rhs)) {
// Makes sure the user doesn't instantiate this class template
// with a const or reference type.
testing::StaticAssertTypeEq<Container,
GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))>();
}
template <typename LhsContainer>
bool Matches(const LhsContainer& lhs) const {
// GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug
// that causes LhsContainer to be a const type sometimes.
typedef internal::StlContainerView<GMOCK_REMOVE_CONST_(LhsContainer)>
LhsView;
StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
return lhs_stl_container == rhs_;
}
void DescribeTo(::std::ostream* os) const {
*os << "equals ";
UniversalPrinter<Container>::Print(rhs_, os);
UniversalPrinter<StlContainer>::Print(rhs_, os);
}
void DescribeNegationTo(::std::ostream* os) const {
*os << "does not equal ";
UniversalPrinter<Container>::Print(rhs_, os);
UniversalPrinter<StlContainer>::Print(rhs_, os);
}
void ExplainMatchResultTo(const Container& lhs,
template <typename LhsContainer>
void ExplainMatchResultTo(const LhsContainer& lhs,
::std::ostream* os) const {
// GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug
// that causes LhsContainer to be a const type sometimes.
typedef internal::StlContainerView<GMOCK_REMOVE_CONST_(LhsContainer)>
LhsView;
typedef typename LhsView::type LhsStlContainer;
StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
// Something is different. Check for missing values first.
bool printed_header = false;
for (typename Container::const_iterator it = lhs.begin();
it != lhs.end(); ++it) {
if (std::find(rhs_.begin(), rhs_.end(), *it) == rhs_.end()) {
for (typename LhsStlContainer::const_iterator it =
lhs_stl_container.begin();
it != lhs_stl_container.end(); ++it) {
if (internal::ArrayAwareFind(rhs_.begin(), rhs_.end(), *it) ==
rhs_.end()) {
if (printed_header) {
*os << ", ";
} else {
*os << "Only in actual: ";
printed_header = true;
}
UniversalPrinter<typename Container::value_type>::Print(*it, os);
UniversalPrinter<typename LhsStlContainer::value_type>::Print(*it, os);
}
}
// Now check for extra values.
bool printed_header2 = false;
for (typename Container::const_iterator it = rhs_.begin();
for (typename StlContainer::const_iterator it = rhs_.begin();
it != rhs_.end(); ++it) {
if (std::find(lhs.begin(), lhs.end(), *it) == lhs.end()) {
if (internal::ArrayAwareFind(
lhs_stl_container.begin(), lhs_stl_container.end(), *it) ==
lhs_stl_container.end()) {
if (printed_header2) {
*os << ", ";
} else {
*os << (printed_header ? "; not" : "Not") << " in actual: ";
printed_header2 = true;
}
UniversalPrinter<typename Container::value_type>::Print(*it, os);
UniversalPrinter<typename StlContainer::value_type>::Print(*it, os);
}
}
}
private:
const Container rhs_;
const StlContainer rhs_;
};
template <typename Container>
template <typename LhsContainer, typename Container>
void ExplainMatchResultTo(const ContainerEqMatcher<Container>& matcher,
const Container& lhs,
const LhsContainer& lhs,
::std::ostream* os) {
matcher.ExplainMatchResultTo(lhs, os);
}
// Implements Contains(element_matcher) for the given argument type Container.
template <typename Container>
class ContainsMatcherImpl : public MatcherInterface<Container> {
public:
typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
typedef StlContainerView<RawContainer> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
typedef typename StlContainer::value_type Element;
template <typename InnerMatcher>
explicit ContainsMatcherImpl(InnerMatcher inner_matcher)
: inner_matcher_(
testing::SafeMatcherCast<const Element&>(inner_matcher)) {}
// Returns true iff 'container' matches.
virtual bool Matches(Container container) const {
StlContainerReference stl_container = View::ConstReference(container);
for (typename StlContainer::const_iterator it = stl_container.begin();
it != stl_container.end(); ++it) {
if (inner_matcher_.Matches(*it))
return true;
}
return false;
}
// Describes what this matcher does.
virtual void DescribeTo(::std::ostream* os) const {
*os << "contains at least one element that ";
inner_matcher_.DescribeTo(os);
}
// Describes what the negation of this matcher does.
virtual void DescribeNegationTo(::std::ostream* os) const {
*os << "doesn't contain any element that ";
inner_matcher_.DescribeTo(os);
}
// 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);
// We need to explain which (if any) element matches inner_matcher_.
typename StlContainer::const_iterator it = stl_container.begin();
for (size_t i = 0; it != stl_container.end(); ++it, ++i) {
if (inner_matcher_.Matches(*it)) {
*os << "element " << i << " matches";
return;
}
}
}
private:
const Matcher<const Element&> inner_matcher_;
};
// Implements polymorphic Contains(element_matcher).
template <typename M>
class ContainsMatcher {
public:
explicit ContainsMatcher(M m) : inner_matcher_(m) {}
template <typename Container>
operator Matcher<Container>() const {
return MakeMatcher(new ContainsMatcherImpl<Container>(inner_matcher_));
}
private:
const M inner_matcher_;
};
} // namespace internal
// Implements MatcherCast().
@@ -2206,9 +2310,35 @@ Truly(Predicate pred) {
// values that are included in one container but not the other. (Duplicate
// values and order differences are not explained.)
template <typename Container>
inline PolymorphicMatcher<internal::ContainerEqMatcher<Container> >
inline PolymorphicMatcher<internal::ContainerEqMatcher<
GMOCK_REMOVE_CONST_(Container)> >
ContainerEq(const Container& rhs) {
return MakePolymorphicMatcher(internal::ContainerEqMatcher<Container>(rhs));
// This following line is for working around a bug in MSVC 8.0,
// which causes Container to be a const type sometimes.
typedef GMOCK_REMOVE_CONST_(Container) RawContainer;
return MakePolymorphicMatcher(internal::ContainerEqMatcher<RawContainer>(rhs));
}
// Matches an STL-style container or a native array that contains at
// least one element matching the given value or matcher.
//
// Examples:
// ::std::set<int> page_ids;
// page_ids.insert(3);
// page_ids.insert(1);
// EXPECT_THAT(page_ids, Contains(1));
// EXPECT_THAT(page_ids, Contains(Gt(2)));
// EXPECT_THAT(page_ids, Not(Contains(4)));
//
// ::std::map<int, size_t> page_lengths;
// page_lengths[1] = 100;
// EXPECT_THAT(map_int, Contains(::std::pair<const int, size_t>(1, 100)));
//
// const char* user_ids[] = { "joe", "mike", "tom" };
// EXPECT_THAT(user_ids, Contains(Eq(::std::string("tom"))));
template <typename M>
inline internal::ContainsMatcher<M> Contains(M matcher) {
return internal::ContainsMatcher<M>(matcher);
}
// Returns a predicate that is satisfied by anything that matches the
@@ -2218,6 +2348,12 @@ inline internal::MatcherAsPredicate<M> Matches(M matcher) {
return internal::MatcherAsPredicate<M>(matcher);
}
// Returns true iff the value matches the matcher.
template <typename T, typename M>
inline bool Value(const T& value, M matcher) {
return testing::Matches(matcher)(value);
}
// These macros allow using matchers to check values in Google Test
// tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher)
// succeed iff the value matches the matcher. If the assertion fails,

View File

@@ -66,10 +66,28 @@
// // printed.
// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
//
// // Prints value using the type inferred by the compiler. The difference
// // from UniversalTersePrint() is that this function prints both the
// // pointer and the NUL-terminated string for a (const) char pointer.
// void ::testing::internal::UniversalPrint(const T& value, ostream*);
//
// // Prints the fields of a tuple tersely to a string vector, one
// // element for each field.
// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
// const Tuple& value);
//
// Known limitation:
//
// The print primitives print the elements of an STL-style container
// using the compiler-inferred type of *iter where iter is a
// const_iterator of the container. When const_iterator is an input
// iterator but not a forward iterator, this inferred type may not
// match value_type, and the print output may be incorrect. In
// practice, this is rarely a problem as for most containers
// const_iterator is a forward iterator. We'll fix this if there's an
// actual need for it. Note that this fix cannot rely on value_type
// being defined as many user-defined container types don't have
// value_type.
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_
@@ -208,6 +226,9 @@ namespace internal {
template <typename T>
class UniversalPrinter;
template <typename T>
void UniversalPrint(const T& value, ::std::ostream* os);
// Used to print an STL-style container when the user doesn't define
// a PrintTo() for it.
template <typename C>
@@ -227,7 +248,9 @@ void DefaultPrintTo(IsContainer /* dummy */,
}
}
*os << ' ';
PrintTo(*it, os);
// We cannot call PrintTo(*it, os) here as PrintTo() doesn't
// handle *it being a native array.
internal::UniversalPrint(*it, os);
}
if (count > 0) {
@@ -683,6 +706,15 @@ inline void UniversalTersePrint(char* str, ::std::ostream* os) {
UniversalTersePrint(static_cast<const char*>(str), os);
}
// Prints a value using the type inferred by the compiler. The
// difference between this and UniversalTersePrint() is that for a
// (const) char pointer, this prints both the pointer and the
// NUL-terminated string.
template <typename T>
void UniversalPrint(const T& value, ::std::ostream* os) {
UniversalPrinter<T>::Print(value, os);
}
// Prints the fields of a tuple tersely to a string vector, one
// element for each field. See the comment before
// UniversalTersePrint() for how we define "tersely".

View File

@@ -99,6 +99,17 @@ struct RemoveConst { typedef T type; }; // NOLINT
template <typename T>
struct RemoveConst<const T> { typedef T type; }; // NOLINT
// MSVC 8.0 has a bug which causes the above definition to fail to
// remove the const in 'const int[3]'. The following specialization
// works around the bug. However, it causes trouble with gcc and thus
// needs to be conditionally compiled.
#ifdef _MSC_VER
template <typename T, size_t N>
struct RemoveConst<T[N]> {
typedef typename RemoveConst<T>::type type[N];
};
#endif // _MSC_VER
// A handy wrapper around RemoveConst that works when the argument
// T depends on template parameters.
#define GMOCK_REMOVE_CONST_(T) \
@@ -451,10 +462,6 @@ bool LogIsVisible(LogSeverity severity);
// conservative.
void Log(LogSeverity severity, const string& message, int stack_frames_to_skip);
// The universal value printer (public/gmock-printers.h) needs this
// to declare an unused << operator in the global namespace.
struct Unused {};
// TODO(wan@google.com): group all type utilities together.
// Type traits.
@@ -482,6 +489,238 @@ inline T Invalid() {
template <>
inline void Invalid<void>() {}
// Utilities for native arrays.
// ArrayEq() compares two k-dimensional native arrays using the
// elements' operator==, where k can be any integer >= 0. When k is
// 0, ArrayEq() degenerates into comparing a single pair of values.
template <typename T, typename U>
bool ArrayEq(const T* lhs, size_t size, const U* rhs);
// This generic version is used when k is 0.
template <typename T, typename U>
inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
// This overload is used when k >= 1.
template <typename T, typename U, size_t N>
inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
return internal::ArrayEq(lhs, N, rhs);
}
// This helper reduces code bloat. If we instead put its logic inside
// the previous ArrayEq() function, arrays with different sizes would
// lead to different copies of the template code.
template <typename T, typename U>
bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
for (size_t i = 0; i != size; i++) {
if (!internal::ArrayEq(lhs[i], rhs[i]))
return false;
}
return true;
}
// Finds the first element in the iterator range [begin, end) that
// equals elem. Element may be a native array type itself.
template <typename Iter, typename Element>
Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
for (Iter it = begin; it != end; ++it) {
if (internal::ArrayEq(*it, elem))
return it;
}
return end;
}
// CopyArray() copies a k-dimensional native array using the elements'
// operator=, where k can be any integer >= 0. When k is 0,
// CopyArray() degenerates into copying a single value.
template <typename T, typename U>
void CopyArray(const T* from, size_t size, U* to);
// This generic version is used when k is 0.
template <typename T, typename U>
inline void CopyArray(const T& from, U* to) { *to = from; }
// This overload is used when k >= 1.
template <typename T, typename U, size_t N>
inline void CopyArray(const T(&from)[N], U(*to)[N]) {
internal::CopyArray(from, N, *to);
}
// This helper reduces code bloat. If we instead put its logic inside
// the previous CopyArray() function, arrays with different sizes
// would lead to different copies of the template code.
template <typename T, typename U>
void CopyArray(const T* from, size_t size, U* to) {
for (size_t i = 0; i != size; i++) {
internal::CopyArray(from[i], to + i);
}
}
// The relation between an NativeArray object (see below) and the
// native array it represents.
enum RelationToSource {
kReference, // The NativeArray references the native array.
kCopy // The NativeArray makes a copy of the native array and
// owns the copy.
};
// Adapts a native array to a read-only STL-style container. Instead
// of the complete STL container concept, this adaptor only implements
// members useful for Google Mock's container matchers. New members
// should be added as needed. To simplify the implementation, we only
// support Element being a raw type (i.e. having no top-level const or
// reference modifier). It's the client's responsibility to satisfy
// this requirement. Element can be an array type itself (hence
// multi-dimensional arrays are supported).
template <typename Element>
class NativeArray {
public:
// STL-style container typedefs.
typedef Element value_type;
typedef const Element* const_iterator;
// Constructs from a native array passed by reference.
template <size_t N>
NativeArray(const Element (&array)[N], RelationToSource relation) {
Init(array, N, relation);
}
// Constructs from a native array passed by a pointer and a size.
// For generality we don't artificially restrict the types of the
// pointer and the size.
template <typename Pointer, typename Size>
NativeArray(const ::std::tr1::tuple<Pointer, Size>& array,
RelationToSource relation) {
Init(internal::GetRawPointer(::std::tr1::get<0>(array)),
::std::tr1::get<1>(array),
relation);
}
// Copy constructor.
NativeArray(const NativeArray& rhs) {
Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
}
~NativeArray() {
// Ensures that the user doesn't instantiate NativeArray with a
// const or reference type.
testing::StaticAssertTypeEq<Element,
GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Element))>();
if (relation_to_source_ == kCopy)
delete[] array_;
}
// STL-style container methods.
size_t size() const { return size_; }
const_iterator begin() const { return array_; }
const_iterator end() const { return array_ + size_; }
bool operator==(const NativeArray& rhs) const {
return size() == rhs.size() &&
ArrayEq(begin(), size(), rhs.begin());
}
private:
// Not implemented as we don't want to support assignment.
void operator=(const NativeArray& rhs);
// Initializes this object; makes a copy of the input array if
// 'relation' is kCopy.
void Init(const Element* array, size_t size, RelationToSource relation) {
if (relation == kReference) {
array_ = array;
} else {
Element* const copy = new Element[size];
CopyArray(array, size, copy);
array_ = copy;
}
size_ = size;
relation_to_source_ = relation;
}
const Element* array_;
size_t size_;
RelationToSource relation_to_source_;
};
// Given a raw type (i.e. having no top-level reference or const
// modifier) RawContainer that's either an STL-style container or a
// native array, class StlContainerView<RawContainer> has the
// following members:
//
// - type is a type that provides an STL-style container view to
// (i.e. implements the STL container concept for) RawContainer;
// - const_reference is a type that provides a reference to a const
// RawContainer;
// - ConstReference(raw_container) returns a const reference to an STL-style
// container view to raw_container, which is a RawContainer.
// - Copy(raw_container) returns an STL-style container view of a
// copy of raw_container, which is a RawContainer.
//
// This generic version is used when RawContainer itself is already an
// STL-style container.
template <class RawContainer>
class StlContainerView {
public:
typedef RawContainer type;
typedef const type& const_reference;
static const_reference ConstReference(const RawContainer& container) {
// Ensures that RawContainer is not a const type.
testing::StaticAssertTypeEq<RawContainer,
GMOCK_REMOVE_CONST_(RawContainer)>();
return container;
}
static type Copy(const RawContainer& container) { return container; }
};
// This specialization is used when RawContainer is a native array type.
template <typename Element, size_t N>
class StlContainerView<Element[N]> {
public:
typedef GMOCK_REMOVE_CONST_(Element) RawElement;
typedef internal::NativeArray<RawElement> type;
// NativeArray<T> can represent a native array either by value or by
// reference (selected by a constructor argument), so 'const type'
// can be used to reference a const native array. We cannot
// 'typedef const type& const_reference' here, as that would mean
// ConstReference() has to return a reference to a local variable.
typedef const type const_reference;
static const_reference ConstReference(const Element (&array)[N]) {
// Ensures that Element is not a const type.
testing::StaticAssertTypeEq<Element, RawElement>();
return type(array, kReference);
}
static type Copy(const Element (&array)[N]) {
return type(array, kCopy);
}
};
// This specialization is used when RawContainer is a native array
// represented as a (pointer, size) tuple.
template <typename ElementPointer, typename Size>
class StlContainerView< ::std::tr1::tuple<ElementPointer, Size> > {
public:
typedef GMOCK_REMOVE_CONST_(
typename internal::PointeeOf<ElementPointer>::type) RawElement;
typedef internal::NativeArray<RawElement> type;
typedef const type const_reference;
static const_reference ConstReference(
const ::std::tr1::tuple<ElementPointer, Size>& array) {
return type(array, kReference);
}
static type Copy(const ::std::tr1::tuple<ElementPointer, Size>& array) {
return type(array, kCopy);
}
};
// The following specialization prevents the user from instantiating
// StlContainer with a reference type.
template <typename T> class StlContainerView<T&>;
} // namespace internal
} // namespace testing