Makes WhenSorted() support associative containers (by billydonahue@google.com).

This commit is contained in:
zhanyong.wan 2013-03-27 16:14:55 +00:00
parent 1f122a06e6
commit a9a59e06dd
3 changed files with 179 additions and 1 deletions

View File

@ -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<const Key, Value> into std::pair<Key, Value>
// 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) {}

View File

@ -473,6 +473,20 @@ class StlContainerView< ::std::tr1::tuple<ElementPointer, Size> > {
// StlContainer with a reference type.
template <typename T> class StlContainerView<T&>;
// 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 <typename T>
struct RemoveConstFromKey {
typedef T type;
};
// Partially specialized to remove constness from std::pair<const K, V>.
template <typename K, typename V>
struct RemoveConstFromKey<std::pair<const K, V> > {
typedef std::pair<K, V> type;
};
// Mapping from booleans to types. Similar to boost::bool_<kValue> and
// std::integral_constant<bool, kValue>.
template <bool kValue>

View File

@ -37,8 +37,10 @@
#include "gmock/gmock-more-matchers.h"
#include <string.h>
#include <deque>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <set>
@ -4012,6 +4014,165 @@ TEST(WhenSortedTest, WorksForNonEmptyContainer) {
EXPECT_THAT(words, Not(WhenSorted(ElementsAre("3", "1", "2", "2"))));
}
TEST(WhenSortedTest, WorksForMapTypes) {
map<string, int> 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<int, int> 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<int> 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<int> d;
d.push_back(2);
d.push_back(1);
Matcher<const std::vector<int>&> vector_match = ElementsAre(1, 2);
EXPECT_THAT(d, WhenSorted(vector_match));
Matcher<const std::vector<int>&> 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 <typename T>
class Streamlike {
private:
class ConstIter;
public:
typedef ConstIter const_iterator;
typedef T value_type;
template <typename InIter>
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<std::input_iterator_tag,
value_type,
ptrdiff_t,
const value_type&,
const value_type*> {
public:
ConstIter(const Streamlike* s,
typename std::list<value_type>::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<value_type>::iterator pos_;
};
friend std::ostream& operator<<(std::ostream& os, const Streamlike& s) {
os << "[";
typedef typename std::list<value_type>::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<value_type> remainder_; // modified by iteration
};
TEST(StreamlikeTest, Iteration) {
const int a[5] = { 2, 1, 4, 5, 3 };
Streamlike<int> s(a, a + 5);
Streamlike<int>::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<int> 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<int> s(a, a + 5);
Matcher<const std::vector<int>&> 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) {