From fb25d5391143a0fd4cbce862f19472ddc2a1ecab Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Sun, 28 Jul 2013 08:24:00 +0000 Subject: Adds matchers UnorderedElementsAre[Array]() (by Billy Donahue); pulls in gtest r660. --- include/gmock/gmock-generated-matchers.h | 828 ++++++++++++-------------- include/gmock/gmock-generated-matchers.h.pump | 157 ++--- include/gmock/gmock-matchers.h | 472 +++++++++++++-- 3 files changed, 860 insertions(+), 597 deletions(-) (limited to 'include') diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index bc3f610c..b4c85715 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -306,374 +306,6 @@ class ArgsMatcher { GTEST_DISALLOW_ASSIGN_(ArgsMatcher); }; -// Implements ElementsAre() of 1-10 arguments. The use of DecayArray in -// the implementation allows ElementsAre() to accept string literals, whose -// inferred type is const char[N] while we want to treat them as const char*. - -template -class ElementsAreMatcher1 { - public: - explicit ElementsAreMatcher1(const T1& e1) : e1_(e1) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - // Nokia's Symbian Compiler has a nasty bug where the object put - // in a one-element local array is not destructed when the array - // goes out of scope. This leads to obvious badness as we've - // added the linked_ptr in it to our other linked_ptrs list. - // Hence we implement ElementsAreMatcher1 specially to avoid using - // a local array. - const Matcher matcher = - MatcherCast(e1_); - return MakeMatcher(new ElementsAreMatcherImpl(&matcher, - &matcher + 1)); - } - - private: - const typename DecayArray::type e1_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher1); -}; - -template -class ElementsAreMatcher2 { - public: - ElementsAreMatcher2(const T1& e1, const T2& e2) : e1_(e1), e2_(e2) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 2)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher2); -}; - -template -class ElementsAreMatcher3 { - public: - ElementsAreMatcher3(const T1& e1, const T2& e2, const T3& e3) : e1_(e1), - e2_(e2), e3_(e3) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - MatcherCast(e3_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 3)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - const typename DecayArray::type e3_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher3); -}; - -template -class ElementsAreMatcher4 { - public: - ElementsAreMatcher4(const T1& e1, const T2& e2, const T3& e3, - const T4& e4) : e1_(e1), e2_(e2), e3_(e3), e4_(e4) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - MatcherCast(e3_), - MatcherCast(e4_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 4)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - const typename DecayArray::type e3_; - const typename DecayArray::type e4_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher4); -}; - -template -class ElementsAreMatcher5 { - public: - ElementsAreMatcher5(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5) : e1_(e1), e2_(e2), e3_(e3), e4_(e4), e5_(e5) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - MatcherCast(e3_), - MatcherCast(e4_), - MatcherCast(e5_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 5)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - const typename DecayArray::type e3_; - const typename DecayArray::type e4_; - const typename DecayArray::type e5_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher5); -}; - -template -class ElementsAreMatcher6 { - public: - ElementsAreMatcher6(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6) : e1_(e1), e2_(e2), e3_(e3), e4_(e4), - e5_(e5), e6_(e6) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - MatcherCast(e3_), - MatcherCast(e4_), - MatcherCast(e5_), - MatcherCast(e6_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 6)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - const typename DecayArray::type e3_; - const typename DecayArray::type e4_; - const typename DecayArray::type e5_; - const typename DecayArray::type e6_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher6); -}; - -template -class ElementsAreMatcher7 { - public: - ElementsAreMatcher7(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7) : e1_(e1), e2_(e2), e3_(e3), - e4_(e4), e5_(e5), e6_(e6), e7_(e7) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - MatcherCast(e3_), - MatcherCast(e4_), - MatcherCast(e5_), - MatcherCast(e6_), - MatcherCast(e7_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 7)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - const typename DecayArray::type e3_; - const typename DecayArray::type e4_; - const typename DecayArray::type e5_; - const typename DecayArray::type e6_; - const typename DecayArray::type e7_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher7); -}; - -template -class ElementsAreMatcher8 { - public: - ElementsAreMatcher8(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8) : e1_(e1), - e2_(e2), e3_(e3), e4_(e4), e5_(e5), e6_(e6), e7_(e7), e8_(e8) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - MatcherCast(e3_), - MatcherCast(e4_), - MatcherCast(e5_), - MatcherCast(e6_), - MatcherCast(e7_), - MatcherCast(e8_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 8)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - const typename DecayArray::type e3_; - const typename DecayArray::type e4_; - const typename DecayArray::type e5_; - const typename DecayArray::type e6_; - const typename DecayArray::type e7_; - const typename DecayArray::type e8_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher8); -}; - -template -class ElementsAreMatcher9 { - public: - ElementsAreMatcher9(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8, - const T9& e9) : e1_(e1), e2_(e2), e3_(e3), e4_(e4), e5_(e5), e6_(e6), - e7_(e7), e8_(e8), e9_(e9) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - MatcherCast(e3_), - MatcherCast(e4_), - MatcherCast(e5_), - MatcherCast(e6_), - MatcherCast(e7_), - MatcherCast(e8_), - MatcherCast(e9_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 9)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - const typename DecayArray::type e3_; - const typename DecayArray::type e4_; - const typename DecayArray::type e5_; - const typename DecayArray::type e6_; - const typename DecayArray::type e7_; - const typename DecayArray::type e8_; - const typename DecayArray::type e9_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher9); -}; - -template -class ElementsAreMatcher10 { - public: - ElementsAreMatcher10(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, - const T10& e10) : e1_(e1), e2_(e2), e3_(e3), e4_(e4), e5_(e5), e6_(e6), - e7_(e7), e8_(e8), e9_(e9), e10_(e10) {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - - const Matcher matchers[] = { - MatcherCast(e1_), - MatcherCast(e2_), - MatcherCast(e3_), - MatcherCast(e4_), - MatcherCast(e5_), - MatcherCast(e6_), - MatcherCast(e7_), - MatcherCast(e8_), - MatcherCast(e9_), - MatcherCast(e10_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + 10)); - } - - private: - const typename DecayArray::type e1_; - const typename DecayArray::type e2_; - const typename DecayArray::type e3_; - const typename DecayArray::type e4_; - const typename DecayArray::type e5_; - const typename DecayArray::type e6_; - const typename DecayArray::type e7_; - const typename DecayArray::type e8_; - const typename DecayArray::type e9_; - const typename DecayArray::type e10_; - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher10); -}; - // A set of metafunctions for computing the result type of AllOf. // AllOf(m1, ..., mN) returns // AllOfResultN::type. @@ -930,144 +562,448 @@ Args(const InnerMatcher& matcher) { k9, k10>(matcher); } -// ElementsAre(e0, e1, ..., e_n) matches an STL-style container with -// (n + 1) elements, where the i-th element in the container must +// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with +// n elements, where the i-th element in the container must // match the i-th argument in the list. Each argument of // ElementsAre() can be either a value or a matcher. We support up to // 10 arguments. // +// The use of DecayArray in the implementation allows ElementsAre() +// to accept string literals, whose type is const char[N], but we +// want to treat them as const char*. +// // NOTE: Since ElementsAre() cares about the order of the elements, it // must not be used with containers whose elements's order is // undefined (e.g. hash_map). -inline internal::ElementsAreMatcher0 ElementsAre() { - return internal::ElementsAreMatcher0(); +inline internal::ElementsAreMatcher< + std::tr1::tuple<> > +ElementsAre() { + typedef std::tr1::tuple<> Args; + return internal::ElementsAreMatcher(Args()); } template -inline internal::ElementsAreMatcher1 ElementsAre(const T1& e1) { - return internal::ElementsAreMatcher1(e1); +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type> > +ElementsAre(const T1& e1) { + typedef std::tr1::tuple< + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1)); } template -inline internal::ElementsAreMatcher2 ElementsAre(const T1& e1, - const T2& e2) { - return internal::ElementsAreMatcher2(e1, e2); +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2)); } template -inline internal::ElementsAreMatcher3 ElementsAre(const T1& e1, - const T2& e2, const T3& e3) { - return internal::ElementsAreMatcher3(e1, e2, e3); +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3)); } template -inline internal::ElementsAreMatcher4 ElementsAre(const T1& e1, - const T2& e2, const T3& e3, const T4& e4) { - return internal::ElementsAreMatcher4(e1, e2, e3, e4); +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4)); } template -inline internal::ElementsAreMatcher5 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5) { - return internal::ElementsAreMatcher5(e1, e2, e3, e4, e5); + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5)); } template -inline internal::ElementsAreMatcher6 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6) { - return internal::ElementsAreMatcher6(e1, e2, e3, e4, - e5, e6); + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6)); } template -inline internal::ElementsAreMatcher7 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7) { - return internal::ElementsAreMatcher7(e1, e2, e3, - e4, e5, e6, e7); + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7)); } template -inline internal::ElementsAreMatcher8 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8) { - return internal::ElementsAreMatcher8(e1, e2, - e3, e4, e5, e6, e7, e8); + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8)); } template -inline internal::ElementsAreMatcher9 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { - return internal::ElementsAreMatcher9(e1, - e2, e3, e4, e5, e6, e7, e8, e9); + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8, e9)); } template -inline internal::ElementsAreMatcher10 ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, +inline internal::ElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, const T10& e10) { - return internal::ElementsAreMatcher10(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, + e8, e9, e10)); } -// ElementsAreArray(array) -// ElementsAreArray(pointer, count) -// ElementsAreArray(vector) -// ElementsAreArray(first, last) -// -// The ElementsAreArray() functions are like ElementsAre(...), except that -// they are given a sequence of matchers or values rather than taking each -// element as a function argument. The sequence can be specified as a -// C-style array, a pointer and count, a vector, or an STL iterator range. -// -// * The array form infers the size of 'array', which must be of a -// statically-sized C-style array type. -// -// * The (pointer, count) form can take either a statically-sized C-style -// array or a pointer to a dynamically created array. It does not take -// ownership of the pointer. -// -// * The vector form can take a std::vector either of values or of matchers. -// -// * The (first, last) form can take any STL iterator range. -// -// All forms of ElementsAreArray() make a copy of the input sequence. -template -inline internal::ElementsAreArrayMatcher ElementsAreArray( - const T* first, size_t count) { - return internal::ElementsAreArrayMatcher(first, first + count); +// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension +// that matches n elements in any order. We support up to n=10 arguments. + +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple<> > +UnorderedElementsAre() { + typedef std::tr1::tuple<> Args; + return internal::UnorderedElementsAreMatcher(Args()); } -template -inline internal::ElementsAreArrayMatcher ElementsAreArray( - const T (&array)[N]) { - return internal::ElementsAreArrayMatcher(array, array + N); +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1) { + typedef std::tr1::tuple< + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1)); } -template -inline internal::ElementsAreArrayMatcher ElementsAreArray( - const std::vector& vec) { - return internal::ElementsAreArrayMatcher(vec.begin(), vec.end()); +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2)); } -template -inline internal::ElementsAreArrayMatcher< - typename std::iterator_traits::value_type> -ElementsAreArray(Iter first, Iter last) { - typedef typename std::iterator_traits::value_type T; - return internal::ElementsAreArrayMatcher(first, last); +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3)); } +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8, e9)); +} + +template +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> > +UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, + const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, + const T10& e10) { + typedef std::tr1::tuple< + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type, + typename internal::DecayArray::type> Args; + return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, + e6, e7, e8, e9, e10)); +} // AllOf(m1, m2, ..., mk) matches any value that matches all of the given // sub-matchers. AllOf is called fully qualified to prevent ADL from firing. diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index a8d7612d..af02acbc 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -187,66 +187,6 @@ class ArgsMatcher { GTEST_DISALLOW_ASSIGN_(ArgsMatcher); }; -// Implements ElementsAre() of 1-$n arguments. The use of DecayArray in -// the implementation allows ElementsAre() to accept string literals, whose -// inferred type is const char[N] while we want to treat them as const char*. - - -$range i 1..n -$for i [[ -$range j 1..i -template <$for j, [[typename T$j]]> -class ElementsAreMatcher$i { - public: - $if i==1 [[explicit ]]ElementsAreMatcher$i($for j, [[const T$j& e$j]])$if i > 0 [[ : ]] - $for j, [[e$j[[]]_(e$j)]] {} - - template - operator Matcher() const { - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; - -$if i==1 [[ - - // Nokia's Symbian Compiler has a nasty bug where the object put - // in a one-element local array is not destructed when the array - // goes out of scope. This leads to obvious badness as we've - // added the linked_ptr in it to our other linked_ptrs list. - // Hence we implement ElementsAreMatcher1 specially to avoid using - // a local array. - const Matcher matcher = - MatcherCast(e1_); - return MakeMatcher(new ElementsAreMatcherImpl(&matcher, - &matcher + 1)); -]] $else [[ - - const Matcher matchers[] = { - -$for j [[ - MatcherCast(e$j[[]]_), - -]] - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers + $i)); -]] - - } - - private: - -$for j [[ - const typename DecayArray::type e$j[[]]_; - -]] - - GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher$i); -}; - - -]] // A set of metafunctions for computing the result type of AllOf. // AllOf(m1, ..., mN) returns // AllOfResultN::type. @@ -324,79 +264,72 @@ Args(const InnerMatcher& matcher) { ]] -// ElementsAre(e0, e1, ..., e_n) matches an STL-style container with -// (n + 1) elements, where the i-th element in the container must +// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with +// n elements, where the i-th element in the container must // match the i-th argument in the list. Each argument of // ElementsAre() can be either a value or a matcher. We support up to // $n arguments. // +// The use of DecayArray in the implementation allows ElementsAre() +// to accept string literals, whose type is const char[N], but we +// want to treat them as const char*. +// // NOTE: Since ElementsAre() cares about the order of the elements, it // must not be used with containers whose elements's order is // undefined (e.g. hash_map). -inline internal::ElementsAreMatcher0 ElementsAre() { - return internal::ElementsAreMatcher0(); -} - -$range i 1..n +$range i 0..n $for i [[ + $range j 1..i +$if i>0 [[ + template <$for j, [[typename T$j]]> -inline internal::ElementsAreMatcher$i<$for j, [[T$j]]> ElementsAre($for j, [[const T$j& e$j]]) { - return internal::ElementsAreMatcher$i<$for j, [[T$j]]>($for j, [[e$j]]); +]] + +inline internal::ElementsAreMatcher< + std::tr1::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> > +ElementsAre($for j, [[const T$j& e$j]]) { + typedef std::tr1::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> Args; + return internal::ElementsAreMatcher(Args($for j, [[e$j]])); } ]] -// ElementsAreArray(array) -// ElementsAreArray(pointer, count) -// ElementsAreArray(vector) -// ElementsAreArray(first, last) -// -// The ElementsAreArray() functions are like ElementsAre(...), except that -// they are given a sequence of matchers or values rather than taking each -// element as a function argument. The sequence can be specified as a -// C-style array, a pointer and count, a vector, or an STL iterator range. -// -// * The array form infers the size of 'array', which must be of a -// statically-sized C-style array type. -// -// * The (pointer, count) form can take either a statically-sized C-style -// array or a pointer to a dynamically created array. It does not take -// ownership of the pointer. -// -// * The vector form can take a std::vector either of values or of matchers. -// -// * The (first, last) form can take any STL iterator range. -// -// All forms of ElementsAreArray() make a copy of the input sequence. -template -inline internal::ElementsAreArrayMatcher ElementsAreArray( - const T* first, size_t count) { - return internal::ElementsAreArrayMatcher(first, first + count); -} +// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension +// that matches n elements in any order. We support up to n=$n arguments. -template -inline internal::ElementsAreArrayMatcher ElementsAreArray( - const T (&array)[N]) { - return internal::ElementsAreArrayMatcher(array, array + N); -} +$range i 0..n +$for i [[ -template -inline internal::ElementsAreArrayMatcher ElementsAreArray( - const std::vector& vec) { - return internal::ElementsAreArrayMatcher(vec.begin(), vec.end()); -} +$range j 1..i + +$if i>0 [[ -template -inline internal::ElementsAreArrayMatcher< - typename std::iterator_traits::value_type> -ElementsAreArray(Iter first, Iter last) { - typedef typename std::iterator_traits::value_type T; - return internal::ElementsAreArrayMatcher(first, last); +template <$for j, [[typename T$j]]> +]] + +inline internal::UnorderedElementsAreMatcher< + std::tr1::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> > +UnorderedElementsAre($for j, [[const T$j& e$j]]) { + typedef std::tr1::tuple< +$for j, [[ + + typename internal::DecayArray::type]]> Args; + return internal::UnorderedElementsAreMatcher(Args($for j, [[e$j]])); } +]] // AllOf(m1, m2, ..., mk) matches any value that matches all of the given // sub-matchers. AllOf is called fully qualified to prevent ADL from firing. diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 247b19ae..18ccdca3 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -40,6 +40,7 @@ #include #include +#include #include #include // NOLINT #include @@ -106,12 +107,36 @@ class MatchResultListener { inline MatchResultListener::~MatchResultListener() { } +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + // The implementation of a matcher. template -class MatcherInterface { +class MatcherInterface : public MatcherDescriberInterface { public: - virtual ~MatcherInterface() {} - // Returns true iff the matcher matches x; also explains the match // result to 'listener' if necessary (see the next paragraph), in // the form of a non-restrictive relative clause ("which ...", @@ -145,24 +170,9 @@ class MatcherInterface { // listener->stream() may be NULL. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; - // Describes this matcher to an ostream. The function should print - // a verb phrase that describes the property a value matching this - // matcher should have. The subject of the verb phrase is the value - // being matched. For example, the DescribeTo() method of the Gt(7) - // matcher prints "is greater than 7". - virtual void DescribeTo(::std::ostream* os) const = 0; - - // Describes the negation of this matcher to an ostream. For - // example, if the description of this matcher is "is greater than - // 7", the negated description could be "is not greater than 7". - // You are not required to override this when implementing - // MatcherInterface, but it is highly advised so that your matcher - // can produce good error messages. - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "not ("; - DescribeTo(os); - *os << ")"; - } + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; }; namespace internal { @@ -234,6 +244,13 @@ class MatcherBase { MatchAndExplain(x, &listener); } + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface* GetDescriber() const { + return impl_.get(); + } + protected: MatcherBase() {} @@ -626,7 +643,7 @@ namespace internal { // If the explanation is not empty, prints it to the ostream. inline void PrintIfNotEmpty(const internal::string& explanation, - std::ostream* os) { + ::std::ostream* os) { if (explanation != "" && os != NULL) { *os << ", " << explanation; } @@ -770,6 +787,46 @@ void ExplainMatchFailureTupleTo(const MatcherTuple& matchers, matchers, values, os); } +// TransformTupleValues and its helper. +// +// TransformTupleValuesHelper hides the internal machinery that +// TransformTupleValues uses to implement a tuple traversal. +template +class TransformTupleValuesHelper { + private: + typedef typename ::std::tr1::tuple_size TupleSize; + + public: + // For each member of tuple 't', taken in order, evaluates '*out++ = f(t)'. + // Returns the final value of 'out' in case the caller needs it. + static OutIter Run(Func f, const Tuple& t, OutIter out) { + return IterateOverTuple()(f, t, out); + } + + private: + template + struct IterateOverTuple { + OutIter operator() (Func f, const Tup& t, OutIter out) const { + *out++ = f(::std::tr1::get(t)); + return IterateOverTuple()(f, t, out); + } + }; + template + struct IterateOverTuple { + OutIter operator() (Func /* f */, const Tup& /* t */, OutIter out) const { + return out; + } + }; +}; + +// Successively invokes 'f(element)' on each element of the tuple 't', +// appending each result to the 'out' iterator. Returns the final value +// of 'out'. +template +OutIter TransformTupleValues(Func f, const Tuple& t, OutIter out) { + return TransformTupleValuesHelper::Run(f, t, out); +} + // Implements A(). template class AnyMatcherImpl : public MatcherInterface { @@ -2343,9 +2400,10 @@ class WhenSortedByMatcher { virtual bool MatchAndExplain(LhsContainer lhs, MatchResultListener* listener) const { LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); - std::vector sorted_container(lhs_stl_container.begin(), - lhs_stl_container.end()); - std::sort(sorted_container.begin(), sorted_container.end(), comparator_); + ::std::vector sorted_container(lhs_stl_container.begin(), + lhs_stl_container.end()); + ::std::sort( + sorted_container.begin(), sorted_container.end(), comparator_); if (!listener->IsInterested()) { // If the listener is not interested, we do not need to @@ -2366,7 +2424,7 @@ class WhenSortedByMatcher { private: const Comparator comparator_; - const Matcher&> matcher_; + const Matcher&> matcher_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Impl); }; @@ -2416,7 +2474,7 @@ class PointwiseMatcher { // reference, as they may be expensive to copy. We must use tuple // instead of pair here, as a pair cannot hold references (C++ 98, // 20.2.2 [lib.pairs]). - typedef std::tr1::tuple InnerMatcherArg; + typedef ::std::tr1::tuple InnerMatcherArg; Impl(const TupleMatcher& tuple_matcher, const RhsStlContainer& rhs) // mono_tuple_matcher_ holds a monomorphic version of the tuple matcher. @@ -2860,7 +2918,7 @@ class ElementsAreMatcherImpl : public MatcherInterface { // 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) { + if (actual_count != 0 && listener->IsInterested()) { *listener << "which has " << Elements(actual_count); } return false; @@ -2868,7 +2926,7 @@ class ElementsAreMatcherImpl : public MatcherInterface { typename StlContainer::const_iterator it = stl_container.begin(); // explanations[i] is the explanation of the element at index i. - std::vector explanations(count()); + ::std::vector explanations(count()); for (size_t i = 0; i != count(); ++it, ++i) { StringMatchResultListener s; if (matchers_[i].MatchAndExplain(*it, &s)) { @@ -2905,26 +2963,280 @@ class ElementsAreMatcherImpl : public MatcherInterface { } size_t count() const { return matchers_.size(); } - std::vector > matchers_; + + ::std::vector > matchers_; GTEST_DISALLOW_ASSIGN_(ElementsAreMatcherImpl); }; -// Implements ElementsAre() of 0 arguments. -class ElementsAreMatcher0 { +// Connectivity matrix of (elements X matchers), in element-major order. +// Initially, there are no edges. +// Use NextGraph() to iterate over all possible edge configurations. +// Use Randomize() to generate a random edge configuration. +class GTEST_API_ MatchMatrix { + public: + MatchMatrix(size_t num_elements, size_t num_matchers) + : num_elements_(num_elements), + num_matchers_(num_matchers), + matched_(num_elements_* num_matchers_, 0) { + } + + size_t LhsSize() const { return num_elements_; } + size_t RhsSize() const { return num_matchers_; } + bool HasEdge(size_t ilhs, size_t irhs) const { + return matched_[SpaceIndex(ilhs, irhs)] == 1; + } + void SetEdge(size_t ilhs, size_t irhs, bool b) { + matched_[SpaceIndex(ilhs, irhs)] = b ? 1 : 0; + } + + // Treating the connectivity matrix as a (LhsSize()*RhsSize())-bit number, + // adds 1 to that number; returns false if incrementing the graph left it + // empty. + bool NextGraph(); + + void Randomize(); + + string DebugString() const; + + private: + size_t SpaceIndex(size_t ilhs, size_t irhs) const { + return ilhs * num_matchers_ + irhs; + } + + size_t num_elements_; + size_t num_matchers_; + + // Each element is a char interpreted as bool. They are stored as a + // flattened array in lhs-major order, use 'SpaceIndex()' to translate + // a (ilhs, irhs) matrix coordinate into an offset. + ::std::vector matched_; +}; + +typedef ::std::pair ElementMatcherPair; +typedef ::std::vector ElementMatcherPairs; + +// Returns a maximum bipartite matching for the specified graph 'g'. +// The matching is represented as a vector of {element, matcher} pairs. +GTEST_API_ ElementMatcherPairs +FindMaxBipartiteMatching(const MatchMatrix& g); + +GTEST_API_ bool FindPairing(const MatchMatrix& matrix, + MatchResultListener* listener); + +// Untyped base class for implementing UnorderedElementsAre. By +// putting logic that's not specific to the element type here, we +// reduce binary bloat and increase compilation speed. +class GTEST_API_ UnorderedElementsAreMatcherImplBase { + protected: + // A vector of matcher describers, one for each element matcher. + // Does not own the describers (and thus can be used only when the + // element matchers are alive). + typedef ::std::vector MatcherDescriberVec; + + // Describes this UnorderedElementsAre matcher. + void DescribeToImpl(::std::ostream* os) const; + + // Describes the negation of this UnorderedElementsAre matcher. + void DescribeNegationToImpl(::std::ostream* os) const; + + bool VerifyAllElementsAndMatchersAreMatched( + const ::std::vector& element_printouts, + const MatchMatrix& matrix, + MatchResultListener* listener) const; + + MatcherDescriberVec& matcher_describers() { + return matcher_describers_; + } + + static Message Elements(size_t n) { + return Message() << n << " element" << (n == 1 ? "" : "s"); + } + + private: + MatcherDescriberVec matcher_describers_; + + GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcherImplBase); +}; + +// Implements unordered ElementsAre and unordered ElementsAreArray. +template +class UnorderedElementsAreMatcherImpl + : public MatcherInterface, + public UnorderedElementsAreMatcherImplBase { + public: + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; + typedef internal::StlContainerView View; + typedef typename View::type StlContainer; + typedef typename View::const_reference StlContainerReference; + typedef typename StlContainer::const_iterator StlContainerConstIterator; + typedef typename StlContainer::value_type Element; + + // Constructs the matcher from a sequence of element values or + // element matchers. + template + UnorderedElementsAreMatcherImpl(InputIter first, InputIter last) { + for (; first != last; ++first) { + matchers_.push_back(MatcherCast(*first)); + matcher_describers().push_back(matchers_.back().GetDescriber()); + } + } + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + return UnorderedElementsAreMatcherImplBase::DescribeToImpl(os); + } + + // Describes what the negation of this matcher does. + virtual void DescribeNegationTo(::std::ostream* os) const { + return UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl(os); + } + + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { + StlContainerReference stl_container = View::ConstReference(container); + size_t actual_count = stl_container.size(); + + if (actual_count == 0 && matchers_.empty()) { + return true; + } + if (actual_count != matchers_.size()) { + // 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 && listener->IsInterested()) { + *listener << "which has " << Elements(actual_count); + } + return false; + } + + ::std::vector element_printouts; + MatchMatrix matrix = AnalyzeElements(stl_container.begin(), + stl_container.end(), + &element_printouts, + listener); + + return VerifyAllElementsAndMatchersAreMatched(element_printouts, + matrix, listener) && + FindPairing(matrix, listener); + } + + private: + typedef ::std::vector > MatcherVec; + + template + MatchMatrix AnalyzeElements(ElementIter elem_first, ElementIter elem_last, + ::std::vector* element_printouts, + MatchResultListener* listener) const { + ::std::vector did_match; + size_t num_elements = 0; + for (; elem_first != elem_last; ++num_elements, ++elem_first) { + if (listener->IsInterested()) { + element_printouts->push_back(PrintToString(*elem_first)); + } + for (size_t irhs = 0; irhs != matchers_.size(); ++irhs) { + did_match.push_back(Matches(matchers_[irhs])(*elem_first)); + } + } + + MatchMatrix matrix(num_elements, matchers_.size()); + ::std::vector::const_iterator did_match_iter = did_match.begin(); + for (size_t ilhs = 0; ilhs != num_elements; ++ilhs) { + for (size_t irhs = 0; irhs != matchers_.size(); ++irhs) { + matrix.SetEdge(ilhs, irhs, *did_match_iter++ != 0); + } + } + return matrix; + } + + MatcherVec matchers_; + + GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcherImpl); +}; + +// Functor for use in TransformTuple. +// Performs MatcherCast on an input argument of any type. +template +struct CastAndAppendTransform { + template + Matcher operator()(const Arg& a) const { + return MatcherCast(a); + } +}; + +// Implements UnorderedElementsAre. +template +class UnorderedElementsAreMatcher { public: - ElementsAreMatcher0() {} + explicit UnorderedElementsAreMatcher(const MatcherTuple& args) + : matchers_(args) {} template operator Matcher() const { typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type::value_type - Element; + typedef typename internal::StlContainerView::type View; + typedef typename View::value_type Element; + typedef ::std::vector > MatcherVec; + MatcherVec matchers; + matchers.reserve(::std::tr1::tuple_size::value); + TransformTupleValues(CastAndAppendTransform(), matchers_, + ::std::back_inserter(matchers)); + return MakeMatcher(new UnorderedElementsAreMatcherImpl( + matchers.begin(), matchers.end())); + } + + private: + const MatcherTuple matchers_; + GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcher); +}; - const Matcher* const matchers = NULL; - return MakeMatcher(new ElementsAreMatcherImpl(matchers, - matchers)); +// Implements ElementsAre. +template +class ElementsAreMatcher { + public: + explicit ElementsAreMatcher(const MatcherTuple& args) : matchers_(args) {} + + template + operator Matcher() const { + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; + typedef typename internal::StlContainerView::type View; + typedef typename View::value_type Element; + typedef ::std::vector > MatcherVec; + MatcherVec matchers; + matchers.reserve(::std::tr1::tuple_size::value); + TransformTupleValues(CastAndAppendTransform(), matchers_, + ::std::back_inserter(matchers)); + return MakeMatcher(new ElementsAreMatcherImpl( + matchers.begin(), matchers.end())); } + + private: + const MatcherTuple matchers_; + GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher); +}; + +// Implements UnorderedElementsAreArray(). +template +class UnorderedElementsAreArrayMatcher { + public: + UnorderedElementsAreArrayMatcher() {} + + template + UnorderedElementsAreArrayMatcher(Iter first, Iter last) + : matchers_(first, last) {} + + template + operator Matcher() const { + return MakeMatcher( + new UnorderedElementsAreMatcherImpl(matchers_.begin(), + matchers_.end())); + } + + private: + ::std::vector matchers_; + + GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreArrayMatcher); }; // Implements ElementsAreArray(). @@ -2941,7 +3253,7 @@ class ElementsAreArrayMatcher { } private: - const std::vector matchers_; + const ::std::vector matchers_; GTEST_DISALLOW_ASSIGN_(ElementsAreArrayMatcher); }; @@ -2957,6 +3269,88 @@ GTEST_API_ string FormatMatcherDescription(bool negation, } // namespace internal +// ElementsAreArray(first, last) +// ElementsAreArray(pointer, count) +// ElementsAreArray(array) +// ElementsAreArray(vector) +// +// The ElementsAreArray() functions are like ElementsAre(...), except that +// they are given a homogeneous sequence rather than taking each element as +// a function argument. The sequence can be specified as an array, a +// pointer and count, a vector, or an STL iterator range. In each of these +// cases, the underlying sequence can be either a sequence of values or a +// sequence of matchers. +// +// * ElementsAreArray(array) deduces the size of the array. +// +// * ElementsAreArray(pointer, count) form takes a pointer and count. +// +// * ElementsAreArray(vector) takes a std::vector. +// +// * ElementsAreArray(first, last) takes any iterator range. +// +// All forms of ElementsAreArray() make a copy of the input matcher sequence. + +template +inline internal::ElementsAreArrayMatcher< + typename ::std::iterator_traits::value_type> +ElementsAreArray(Iter first, Iter last) { + typedef typename ::std::iterator_traits::value_type T; + return internal::ElementsAreArrayMatcher(first, last); +} + +template +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const T* pointer, size_t count) { + return ElementsAreArray(pointer, pointer + count); +} + +template +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const T (&array)[N]) { + return ElementsAreArray(array, N); +} + +template +inline internal::ElementsAreArrayMatcher ElementsAreArray( + const ::std::vector& vec) { + return ElementsAreArray(vec.begin(), vec.end()); +} + +// UnorderedElementsAreArray(first, last) +// UnorderedElementsAreArray(pointer, count) +// UnorderedElementsAreArray(array) +// UnorderedElementsAreArray(vector) +// +// The UnorderedElementsAreArray() functions are like +// ElementsAreArray(...), but allow matching the elements in any order. +template +inline internal::UnorderedElementsAreArrayMatcher< + typename ::std::iterator_traits::value_type> +UnorderedElementsAreArray(Iter first, Iter last) { + typedef typename ::std::iterator_traits::value_type T; + return internal::UnorderedElementsAreArrayMatcher(first, last); +} + +template +inline internal::UnorderedElementsAreArrayMatcher +UnorderedElementsAreArray(const T* pointer, size_t count) { + return UnorderedElementsAreArray(pointer, pointer + count); +} + +template +inline internal::UnorderedElementsAreArrayMatcher +UnorderedElementsAreArray(const T (&array)[N]) { + return UnorderedElementsAreArray(array, N); +} + +template +inline internal::UnorderedElementsAreArrayMatcher +UnorderedElementsAreArray(const ::std::vector& vec) { + return UnorderedElementsAreArray(vec.begin(), vec.end()); +} + + // _ is a matcher that matches anything of any type. // // This definition is fine as: -- cgit v1.2.3