From a9a59e06dd7cdfe52c988bf065bc156a7ed96a5c Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 27 Mar 2013 16:14:55 +0000 Subject: Makes WhenSorted() support associative containers (by billydonahue@google.com). --- include/gmock/gmock-matchers.h | 5 +- include/gmock/internal/gmock-internal-utils.h | 14 +++ test/gmock-matchers_test.cc | 161 ++++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 1 deletion(-) diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index ceb73fdd..962cfde9 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -2189,7 +2189,10 @@ class WhenSortedByMatcher { GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)> LhsView; typedef typename LhsView::type LhsStlContainer; typedef typename LhsView::const_reference LhsStlContainerReference; - typedef typename LhsStlContainer::value_type LhsValue; + // Transforms std::pair into std::pair + // so that we can match associative containers. + typedef typename RemoveConstFromKey< + typename LhsStlContainer::value_type>::type LhsValue; Impl(const Comparator& comparator, const ContainerMatcher& matcher) : comparator_(comparator), matcher_(matcher) {} diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index f9b6b809..e12b7d7d 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -473,6 +473,20 @@ class StlContainerView< ::std::tr1::tuple > { // StlContainer with a reference type. template class StlContainerView; +// A type transform to remove constness from the first part of a pair. +// Pairs like that are used as the value_type of associative containers, +// and this transform produces a similar but assignable pair. +template +struct RemoveConstFromKey { + typedef T type; +}; + +// Partially specialized to remove constness from std::pair. +template +struct RemoveConstFromKey > { + typedef std::pair type; +}; + // Mapping from booleans to types. Similar to boost::bool_ and // std::integral_constant. template diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 3a834a18..66459464 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -37,8 +37,10 @@ #include "gmock/gmock-more-matchers.h" #include +#include #include #include +#include #include #include #include @@ -4012,6 +4014,165 @@ TEST(WhenSortedTest, WorksForNonEmptyContainer) { EXPECT_THAT(words, Not(WhenSorted(ElementsAre("3", "1", "2", "2")))); } +TEST(WhenSortedTest, WorksForMapTypes) { + map word_counts; + word_counts["and"] = 1; + word_counts["the"] = 1; + word_counts["buffalo"] = 2; + EXPECT_THAT(word_counts, WhenSorted(ElementsAre( + Pair("and", 1), Pair("buffalo", 2), Pair("the", 1)))); + EXPECT_THAT(word_counts, Not(WhenSorted(ElementsAre( + Pair("and", 1), Pair("the", 1), Pair("buffalo", 2))))); +} + +TEST(WhenSortedTest, WorksForMultiMapTypes) { + multimap ifib; + ifib.insert(make_pair(8, 6)); + ifib.insert(make_pair(2, 3)); + ifib.insert(make_pair(1, 1)); + ifib.insert(make_pair(3, 4)); + ifib.insert(make_pair(1, 2)); + ifib.insert(make_pair(5, 5)); + EXPECT_THAT(ifib, WhenSorted(ElementsAre(Pair(1, 1), + Pair(1, 2), + Pair(2, 3), + Pair(3, 4), + Pair(5, 5), + Pair(8, 6)))); + EXPECT_THAT(ifib, Not(WhenSorted(ElementsAre(Pair(8, 6), + Pair(2, 3), + Pair(1, 1), + Pair(3, 4), + Pair(1, 2), + Pair(5, 5))))); +} + +TEST(WhenSortedTest, WorksForPolymorphicMatcher) { + std::deque d; + d.push_back(2); + d.push_back(1); + EXPECT_THAT(d, WhenSorted(ElementsAre(1, 2))); + EXPECT_THAT(d, Not(WhenSorted(ElementsAre(2, 1)))); +} + +TEST(WhenSortedTest, WorksForVectorConstRefMatcher) { + std::deque d; + d.push_back(2); + d.push_back(1); + Matcher&> vector_match = ElementsAre(1, 2); + EXPECT_THAT(d, WhenSorted(vector_match)); + Matcher&> not_vector_match = ElementsAre(2, 1); + EXPECT_THAT(d, Not(WhenSorted(not_vector_match))); +} + +// Deliberately bare pseudo-container. +// Offers only begin() and end() accessors, yielding InputIterator. +template +class Streamlike { + private: + class ConstIter; + public: + typedef ConstIter const_iterator; + typedef T value_type; + + template + Streamlike(InIter first, InIter last) : remainder_(first, last) {} + + const_iterator begin() const { + return const_iterator(this, remainder_.begin()); + } + const_iterator end() const { + return const_iterator(this, remainder_.end()); + } + + private: + class ConstIter : public std::iterator { + public: + ConstIter(const Streamlike* s, + typename std::list::iterator pos) + : s_(s), pos_(pos) {} + + const value_type& operator*() const { return *pos_; } + const value_type* operator->() const { return &*pos_; } + ConstIter& operator++() { + s_->remainder_.erase(pos_++); + return *this; + } + + // *iter++ is required to work (see std::istreambuf_iterator). + // (void)iter++ is also required to work. + class PostIncrProxy { + public: + explicit PostIncrProxy(const value_type& value) : value_(value) {} + value_type operator*() const { return value_; } + private: + value_type value_; + }; + PostIncrProxy operator++(int) { + PostIncrProxy proxy(**this); + ++(*this); + return proxy; + } + + friend bool operator==(const ConstIter& a, const ConstIter& b) { + return a.s_ == b.s_ && a.pos_ == b.pos_; + } + friend bool operator!=(const ConstIter& a, const ConstIter& b) { + return !(a == b); + } + + private: + const Streamlike* s_; + typename std::list::iterator pos_; + }; + + friend std::ostream& operator<<(std::ostream& os, const Streamlike& s) { + os << "["; + typedef typename std::list::const_iterator Iter; + const char* sep = ""; + for (Iter it = s.remainder_.begin(); it != s.remainder_.end(); ++it) { + os << sep << *it; + sep = ","; + } + os << "]"; + return os; + } + + mutable std::list remainder_; // modified by iteration +}; + +TEST(StreamlikeTest, Iteration) { + const int a[5] = { 2, 1, 4, 5, 3 }; + Streamlike s(a, a + 5); + Streamlike::const_iterator it = s.begin(); + const int* ip = a; + while (it != s.end()) { + SCOPED_TRACE(ip - a); + EXPECT_EQ(*ip++, *it++); + } +} + +TEST(WhenSortedTest, WorksForStreamlike) { + // Streamlike 'container' provides only minimal iterator support. + // Its iterators are tagged with input_iterator_tag. + const int a[5] = { 2, 1, 4, 5, 3 }; + Streamlike s(a, a + 5); + EXPECT_THAT(s, WhenSorted(ElementsAre(1, 2, 3, 4, 5))); + EXPECT_THAT(s, Not(WhenSorted(ElementsAre(2, 1, 4, 5, 3)))); +} + +TEST(WhenSortedTest, WorksForVectorConstRefMatcherOnStreamlike) { + const int a[5] = { 2, 1, 4, 5, 3 }; + Streamlike s(a, a + 5); + Matcher&> vector_match = ElementsAre(1, 2, 3, 4, 5); + EXPECT_THAT(s, WhenSorted(vector_match)); + EXPECT_THAT(s, Not(WhenSorted(ElementsAre(2, 1, 4, 5, 3)))); +} + // Tests IsReadableTypeName(). TEST(IsReadableTypeNameTest, ReturnsTrueForShortNames) { -- cgit v1.2.3