diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/gmock/gmock-generated-matchers.h | 108 | ||||
| -rw-r--r-- | include/gmock/gmock-generated-matchers.h.pump | 81 | ||||
| -rw-r--r-- | include/gmock/gmock-matchers.h | 170 | ||||
| -rw-r--r-- | include/gmock/gmock-printers.h | 34 | ||||
| -rw-r--r-- | include/gmock/internal/gmock-internal-utils.h | 247 | 
5 files changed, 495 insertions, 145 deletions
diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index afe1bd48..f3484cb4 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -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_ diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 09dfedfc..4495547d 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -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_ diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 0497be27..ce7a2fe9 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -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, diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index e233ef3e..561de3d9 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -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". diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index b5e38db3..ee6aa1e2 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -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  | 
