diff options
-rw-r--r-- | googlemock/include/gmock/gmock-matchers.h | 231 | ||||
-rw-r--r-- | googlemock/src/gmock-matchers.cc | 196 | ||||
-rw-r--r-- | googlemock/test/gmock_link_test.h | 24 |
3 files changed, 328 insertions, 123 deletions
diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index fc3fe3a..3d2d617 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -514,7 +514,7 @@ template <typename T, typename M> class MatcherCastImpl { public: static Matcher<T> Cast(const M& polymorphic_matcher_or_value) { - // M can be a polymorhic matcher, in which case we want to use + // M can be a polymorphic matcher, in which case we want to use // its conversion operator to create Matcher<T>. Or it can be a value // that should be passed to the Matcher<T>'s constructor. // @@ -3303,14 +3303,23 @@ typedef ::std::vector<ElementMatcherPair> ElementMatcherPairs; GTEST_API_ ElementMatcherPairs FindMaxBipartiteMatching(const MatchMatrix& g); -GTEST_API_ bool FindPairing(const MatchMatrix& matrix, - MatchResultListener* listener); +struct UnorderedMatcherRequire { + enum Flags { + Superset = 1 << 0, + Subset = 1 << 1, + ExactMatch = Superset | Subset, + }; +}; // 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: + explicit UnorderedElementsAreMatcherImplBase( + UnorderedMatcherRequire::Flags matcher_flags) + : match_flags_(matcher_flags) {} + // 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). @@ -3322,9 +3331,12 @@ class GTEST_API_ UnorderedElementsAreMatcherImplBase { // Describes the negation of this UnorderedElementsAre matcher. void DescribeNegationToImpl(::std::ostream* os) const; - bool VerifyAllElementsAndMatchersAreMatched( - const ::std::vector<std::string>& element_printouts, - const MatchMatrix& matrix, MatchResultListener* listener) const; + bool VerifyMatchMatrix(const ::std::vector<std::string>& element_printouts, + const MatchMatrix& matrix, + MatchResultListener* listener) const; + + bool FindPairing(const MatchMatrix& matrix, + MatchResultListener* listener) const; MatcherDescriberVec& matcher_describers() { return matcher_describers_; @@ -3334,13 +3346,17 @@ class GTEST_API_ UnorderedElementsAreMatcherImplBase { return Message() << n << " element" << (n == 1 ? "" : "s"); } + UnorderedMatcherRequire::Flags match_flags() const { return match_flags_; } + private: + UnorderedMatcherRequire::Flags match_flags_; MatcherDescriberVec matcher_describers_; GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcherImplBase); }; -// Implements unordered ElementsAre and unordered ElementsAreArray. +// Implements UnorderedElementsAre, UnorderedElementsAreArray, IsSubsetOf, and +// IsSupersetOf. template <typename Container> class UnorderedElementsAreMatcherImpl : public MatcherInterface<Container>, @@ -3353,10 +3369,10 @@ class UnorderedElementsAreMatcherImpl 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 <typename InputIter> - UnorderedElementsAreMatcherImpl(InputIter first, InputIter last) { + UnorderedElementsAreMatcherImpl(UnorderedMatcherRequire::Flags matcher_flags, + InputIter first, InputIter last) + : UnorderedElementsAreMatcherImplBase(matcher_flags) { for (; first != last; ++first) { matchers_.push_back(MatcherCast<const Element&>(*first)); matcher_describers().push_back(matchers_.back().GetDescriber()); @@ -3377,34 +3393,32 @@ class UnorderedElementsAreMatcherImpl MatchResultListener* listener) const { StlContainerReference stl_container = View::ConstReference(container); ::std::vector<std::string> element_printouts; - MatchMatrix matrix = AnalyzeElements(stl_container.begin(), - stl_container.end(), - &element_printouts, - listener); + MatchMatrix matrix = + AnalyzeElements(stl_container.begin(), stl_container.end(), + &element_printouts, listener); - const size_t actual_count = matrix.LhsSize(); - if (actual_count == 0 && matchers_.empty()) { + if (matrix.LhsSize() == 0 && matrix.RhsSize() == 0) { 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); + + if (match_flags() == UnorderedMatcherRequire::ExactMatch) { + if (matrix.LhsSize() != matrix.RhsSize()) { + // 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 (matrix.LhsSize() != 0 && listener->IsInterested()) { + *listener << "which has " << Elements(matrix.LhsSize()); + } + return false; } - return false; } - return VerifyAllElementsAndMatchersAreMatched(element_printouts, - matrix, listener) && + return VerifyMatchMatrix(element_printouts, matrix, listener) && FindPairing(matrix, listener); } private: - typedef ::std::vector<Matcher<const Element&> > MatcherVec; - template <typename ElementIter> MatchMatrix AnalyzeElements(ElementIter elem_first, ElementIter elem_last, ::std::vector<std::string>* element_printouts, @@ -3431,7 +3445,7 @@ class UnorderedElementsAreMatcherImpl return matrix; } - MatcherVec matchers_; + ::std::vector<Matcher<const Element&> > matchers_; GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcherImpl); }; @@ -3464,7 +3478,7 @@ class UnorderedElementsAreMatcher { TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_, ::std::back_inserter(matchers)); return MakeMatcher(new UnorderedElementsAreMatcherImpl<Container>( - matchers.begin(), matchers.end())); + UnorderedMatcherRequire::ExactMatch, matchers.begin(), matchers.end())); } private: @@ -3497,24 +3511,23 @@ class ElementsAreMatcher { GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher); }; -// Implements UnorderedElementsAreArray(). +// Implements UnorderedElementsAreArray(), IsSubsetOf(), and IsSupersetOf(). template <typename T> class UnorderedElementsAreArrayMatcher { public: - UnorderedElementsAreArrayMatcher() {} - template <typename Iter> - UnorderedElementsAreArrayMatcher(Iter first, Iter last) - : matchers_(first, last) {} + UnorderedElementsAreArrayMatcher(UnorderedMatcherRequire::Flags match_flags, + Iter first, Iter last) + : match_flags_(match_flags), matchers_(first, last) {} template <typename Container> operator Matcher<Container>() const { - return MakeMatcher( - new UnorderedElementsAreMatcherImpl<Container>(matchers_.begin(), - matchers_.end())); + return MakeMatcher(new UnorderedElementsAreMatcherImpl<Container>( + match_flags_, matchers_.begin(), matchers_.end())); } private: + UnorderedMatcherRequire::Flags match_flags_; ::std::vector<T> matchers_; GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreArrayMatcher); @@ -3625,7 +3638,7 @@ GTEST_API_ std::string FormatMatcherDescription(bool negation, } // namespace internal -// ElementsAreArray(first, last) +// ElementsAreArray(iterator_first, iterator_last) // ElementsAreArray(pointer, count) // ElementsAreArray(array) // ElementsAreArray(container) @@ -3674,20 +3687,26 @@ ElementsAreArray(::std::initializer_list<T> xs) { } #endif -// UnorderedElementsAreArray(first, last) +// UnorderedElementsAreArray(iterator_first, iterator_last) // UnorderedElementsAreArray(pointer, count) // UnorderedElementsAreArray(array) // UnorderedElementsAreArray(container) // UnorderedElementsAreArray({ e1, e2, ..., en }) // -// The UnorderedElementsAreArray() functions are like -// ElementsAreArray(...), but allow matching the elements in any order. +// UnorderedElementsAreArray() verifies that a bijective mapping onto a +// collection of matchers exists. +// +// The matchers can be specified as an array, a pointer and count, a container, +// an initializer list, or an STL iterator range. In each of these cases, the +// underlying matchers can be either values or matchers. + template <typename Iter> inline internal::UnorderedElementsAreArrayMatcher< typename ::std::iterator_traits<Iter>::value_type> UnorderedElementsAreArray(Iter first, Iter last) { typedef typename ::std::iterator_traits<Iter>::value_type T; - return internal::UnorderedElementsAreArrayMatcher<T>(first, last); + return internal::UnorderedElementsAreArrayMatcher<T>( + internal::UnorderedMatcherRequire::ExactMatch, first, last); } template <typename T> @@ -3729,7 +3748,9 @@ UnorderedElementsAreArray(::std::initializer_list<T> xs) { const internal::AnythingMatcher _ = {}; // Creates a matcher that matches any value of the given type T. template <typename T> -inline Matcher<T> A() { return MakeMatcher(new internal::AnyMatcherImpl<T>()); } +inline Matcher<T> A() { + return Matcher<T>(new internal::AnyMatcherImpl<T>()); +} // Creates a matcher that matches any value of the given type T. template <typename T> @@ -4299,6 +4320,128 @@ inline internal::ContainsMatcher<M> Contains(M matcher) { return internal::ContainsMatcher<M>(matcher); } +// IsSupersetOf(iterator_first, iterator_last) +// IsSupersetOf(pointer, count) +// IsSupersetOf(array) +// IsSupersetOf(container) +// IsSupersetOf({e1, e2, ..., en}) +// +// IsSupersetOf() verifies that a surjective partial mapping onto a collection +// of matchers exists. In other words, a container matches +// IsSupersetOf({e1, ..., en}) if and only if there is a permutation +// {y1, ..., yn} of some of the container's elements where y1 matches e1, +// ..., and yn matches en. Obviously, the size of the container must be >= n +// in order to have a match. Examples: +// +// - {1, 2, 3} matches IsSupersetOf({Ge(3), Ne(0)}), as 3 matches Ge(3) and +// 1 matches Ne(0). +// - {1, 2} doesn't match IsSupersetOf({Eq(1), Lt(2)}), even though 1 matches +// both Eq(1) and Lt(2). The reason is that different matchers must be used +// for elements in different slots of the container. +// - {1, 1, 2} matches IsSupersetOf({Eq(1), Lt(2)}), as (the first) 1 matches +// Eq(1) and (the second) 1 matches Lt(2). +// - {1, 2, 3} matches IsSupersetOf(Gt(1), Gt(1)), as 2 matches (the first) +// Gt(1) and 3 matches (the second) Gt(1). +// +// The matchers can be specified as an array, a pointer and count, a container, +// an initializer list, or an STL iterator range. In each of these cases, the +// underlying matchers can be either values or matchers. + +template <typename Iter> +inline internal::UnorderedElementsAreArrayMatcher< + typename ::std::iterator_traits<Iter>::value_type> +IsSupersetOf(Iter first, Iter last) { + typedef typename ::std::iterator_traits<Iter>::value_type T; + return internal::UnorderedElementsAreArrayMatcher<T>( + internal::UnorderedMatcherRequire::Superset, first, last); +} + +template <typename T> +inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf( + const T* pointer, size_t count) { + return IsSupersetOf(pointer, pointer + count); +} + +template <typename T, size_t N> +inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf( + const T (&array)[N]) { + return IsSupersetOf(array, N); +} + +template <typename Container> +inline internal::UnorderedElementsAreArrayMatcher< + typename Container::value_type> +IsSupersetOf(const Container& container) { + return IsSupersetOf(container.begin(), container.end()); +} + +#if GTEST_HAS_STD_INITIALIZER_LIST_ +template <typename T> +inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf( + ::std::initializer_list<T> xs) { + return IsSupersetOf(xs.begin(), xs.end()); +} +#endif + +// IsSubsetOf(iterator_first, iterator_last) +// IsSubsetOf(pointer, count) +// IsSubsetOf(array) +// IsSubsetOf(container) +// IsSubsetOf({e1, e2, ..., en}) +// +// IsSubsetOf() verifies that an injective mapping onto a collection of matchers +// exists. In other words, a container matches IsSubsetOf({e1, ..., en}) if and +// only if there is a subset of matchers {m1, ..., mk} which would match the +// container using UnorderedElementsAre. Obviously, the size of the container +// must be <= n in order to have a match. Examples: +// +// - {1} matches IsSubsetOf({Gt(0), Lt(0)}), as 1 matches Gt(0). +// - {1, -1} matches IsSubsetOf({Lt(0), Gt(0)}), as 1 matches Gt(0) and -1 +// matches Lt(0). +// - {1, 2} doesn't matches IsSubsetOf({Gt(0), Lt(0)}), even though 1 and 2 both +// match Gt(0). The reason is that different matchers must be used for +// elements in different slots of the container. +// +// The matchers can be specified as an array, a pointer and count, a container, +// an initializer list, or an STL iterator range. In each of these cases, the +// underlying matchers can be either values or matchers. + +template <typename Iter> +inline internal::UnorderedElementsAreArrayMatcher< + typename ::std::iterator_traits<Iter>::value_type> +IsSubsetOf(Iter first, Iter last) { + typedef typename ::std::iterator_traits<Iter>::value_type T; + return internal::UnorderedElementsAreArrayMatcher<T>( + internal::UnorderedMatcherRequire::Subset, first, last); +} + +template <typename T> +inline internal::UnorderedElementsAreArrayMatcher<T> IsSubsetOf( + const T* pointer, size_t count) { + return IsSubsetOf(pointer, pointer + count); +} + +template <typename T, size_t N> +inline internal::UnorderedElementsAreArrayMatcher<T> IsSubsetOf( + const T (&array)[N]) { + return IsSubsetOf(array, N); +} + +template <typename Container> +inline internal::UnorderedElementsAreArrayMatcher< + typename Container::value_type> +IsSubsetOf(const Container& container) { + return IsSubsetOf(container.begin(), container.end()); +} + +#if GTEST_HAS_STD_INITIALIZER_LIST_ +template <typename T> +inline internal::UnorderedElementsAreArrayMatcher<T> IsSubsetOf( + ::std::initializer_list<T> xs) { + return IsSubsetOf(xs.begin(), xs.end()); +} +#endif + // Matches an STL-style container or a native array that contains only // elements matching the given value or matcher. // diff --git a/googlemock/src/gmock-matchers.cc b/googlemock/src/gmock-matchers.cc index f37d5c2..88e4008 100644 --- a/googlemock/src/gmock-matchers.cc +++ b/googlemock/src/gmock-matchers.cc @@ -38,6 +38,7 @@ #include "gmock/gmock-generated-matchers.h" #include <string.h> +#include <iostream> #include <sstream> #include <string> @@ -181,8 +182,7 @@ class MaxBipartiteMatchState { explicit MaxBipartiteMatchState(const MatchMatrix& graph) : graph_(&graph), left_(graph_->LhsSize(), kUnused), - right_(graph_->RhsSize(), kUnused) { - } + right_(graph_->RhsSize(), kUnused) {} // Returns the edges of a maximal match, each in the form {left, right}. ElementMatcherPairs Compute() { @@ -239,10 +239,8 @@ class MaxBipartiteMatchState { // bool TryAugment(size_t ilhs, ::std::vector<char>* seen) { for (size_t irhs = 0; irhs < graph_->RhsSize(); ++irhs) { - if ((*seen)[irhs]) - continue; - if (!graph_->HasEdge(ilhs, irhs)) - continue; + if ((*seen)[irhs]) continue; + if (!graph_->HasEdge(ilhs, irhs)) continue; // There's an available edge from ilhs to irhs. (*seen)[irhs] = 1; // Next a search is performed to determine whether @@ -285,8 +283,7 @@ class MaxBipartiteMatchState { const size_t MaxBipartiteMatchState::kUnused; -GTEST_API_ ElementMatcherPairs -FindMaxBipartiteMatching(const MatchMatrix& g) { +GTEST_API_ ElementMatcherPairs FindMaxBipartiteMatching(const MatchMatrix& g) { return MaxBipartiteMatchState(g).Compute(); } @@ -295,7 +292,7 @@ static void LogElementMatcherPairVec(const ElementMatcherPairs& pairs, typedef ElementMatcherPairs::const_iterator Iter; ::std::ostream& os = *stream; os << "{"; - const char *sep = ""; + const char* sep = ""; for (Iter it = pairs.begin(); it != pairs.end(); ++it) { os << sep << "\n (" << "element #" << it->first << ", " @@ -305,38 +302,6 @@ static void LogElementMatcherPairVec(const ElementMatcherPairs& pairs, os << "\n}"; } -// Tries to find a pairing, and explains the result. -GTEST_API_ bool FindPairing(const MatchMatrix& matrix, - MatchResultListener* listener) { - ElementMatcherPairs matches = FindMaxBipartiteMatching(matrix); - - size_t max_flow = matches.size(); - bool result = (max_flow == matrix.RhsSize()); - - if (!result) { - if (listener->IsInterested()) { - *listener << "where no permutation of the elements can " - "satisfy all matchers, and the closest match is " - << max_flow << " of " << matrix.RhsSize() - << " matchers with the pairings:\n"; - LogElementMatcherPairVec(matches, listener->stream()); - } - return false; - } - - if (matches.size() > 1) { - if (listener->IsInterested()) { - const char *sep = "where:\n"; - for (size_t mi = 0; mi < matches.size(); ++mi) { - *listener << sep << " - element #" << matches[mi].first - << " is matched by matcher #" << matches[mi].second; - sep = ",\n"; - } - } - } - return true; -} - bool MatchMatrix::NextGraph() { for (size_t ilhs = 0; ilhs < LhsSize(); ++ilhs) { for (size_t irhs = 0; irhs < RhsSize(); ++irhs) { @@ -362,7 +327,7 @@ void MatchMatrix::Randomize() { std::string MatchMatrix::DebugString() const { ::std::stringstream ss; - const char *sep = ""; + const char* sep = ""; for (size_t i = 0; i < LhsSize(); ++i) { ss << sep; for (size_t j = 0; j < RhsSize(); ++j) { @@ -375,44 +340,83 @@ std::string MatchMatrix::DebugString() const { void UnorderedElementsAreMatcherImplBase::DescribeToImpl( ::std::ostream* os) const { - if (matcher_describers_.empty()) { - *os << "is empty"; - return; - } - if (matcher_describers_.size() == 1) { - *os << "has " << Elements(1) << " and that element "; - matcher_describers_[0]->DescribeTo(os); - return; + switch (match_flags()) { + case UnorderedMatcherRequire::ExactMatch: + if (matcher_describers_.empty()) { + *os << "is empty"; + return; + } + if (matcher_describers_.size() == 1) { + *os << "has " << Elements(1) << " and that element "; + matcher_describers_[0]->DescribeTo(os); + return; + } + *os << "has " << Elements(matcher_describers_.size()) + << " and there exists some permutation of elements such that:\n"; + break; + case UnorderedMatcherRequire::Superset: + *os << "a surjection from elements to requirements exists such that:\n"; + break; + case UnorderedMatcherRequire::Subset: + *os << "an injection from elements to requirements exists such that:\n"; + break; } - *os << "has " << Elements(matcher_describers_.size()) - << " and there exists some permutation of elements such that:\n"; + const char* sep = ""; for (size_t i = 0; i != matcher_describers_.size(); ++i) { - *os << sep << " - element #" << i << " "; + *os << sep; + if (match_flags() == UnorderedMatcherRequire::ExactMatch) { + *os << " - element #" << i << " "; + } else { + *os << " - an element "; + } matcher_describers_[i]->DescribeTo(os); - sep = ", and\n"; + if (match_flags() == UnorderedMatcherRequire::ExactMatch) { + sep = ", and\n"; + } else { + sep = "\n"; + } } } void UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl( ::std::ostream* os) const { - if (matcher_describers_.empty()) { - *os << "isn't empty"; - return; - } - if (matcher_describers_.size() == 1) { - *os << "doesn't have " << Elements(1) - << ", or has " << Elements(1) << " that "; - matcher_describers_[0]->DescribeNegationTo(os); - return; + switch (match_flags()) { + case UnorderedMatcherRequire::ExactMatch: + if (matcher_describers_.empty()) { + *os << "isn't empty"; + return; + } + if (matcher_describers_.size() == 1) { + *os << "doesn't have " << Elements(1) << ", or has " << Elements(1) + << " that "; + matcher_describers_[0]->DescribeNegationTo(os); + return; + } + *os << "doesn't have " << Elements(matcher_describers_.size()) + << ", or there exists no permutation of elements such that:\n"; + break; + case UnorderedMatcherRequire::Superset: + *os << "no surjection from elements to requirements exists such that:\n"; + break; + case UnorderedMatcherRequire::Subset: + *os << "no injection from elements to requirements exists such that:\n"; + break; } - *os << "doesn't have " << Elements(matcher_describers_.size()) - << ", or there exists no permutation of elements such that:\n"; const char* sep = ""; for (size_t i = 0; i != matcher_describers_.size(); ++i) { - *os << sep << " - element #" << i << " "; + *os << sep; + if (match_flags() == UnorderedMatcherRequire::ExactMatch) { + *os << " - element #" << i << " "; + } else { + *os << " - an element "; + } matcher_describers_[i]->DescribeTo(os); - sep = ", and\n"; + if (match_flags() == UnorderedMatcherRequire::ExactMatch) { + sep = ", and\n"; + } else { + sep = "\n"; + } } } @@ -421,10 +425,9 @@ void UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl( // and better error reporting. // Returns false, writing an explanation to 'listener', if and only // if the success criteria are not met. -bool UnorderedElementsAreMatcherImplBase:: - VerifyAllElementsAndMatchersAreMatched( - const ::std::vector<std::string>& element_printouts, - const MatchMatrix& matrix, MatchResultListener* listener) const { +bool UnorderedElementsAreMatcherImplBase::VerifyMatchMatrix( + const ::std::vector<std::string>& element_printouts, + const MatchMatrix& matrix, MatchResultListener* listener) const { bool result = true; ::std::vector<char> element_matched(matrix.LhsSize(), 0); ::std::vector<char> matcher_matched(matrix.RhsSize(), 0); @@ -437,12 +440,11 @@ bool UnorderedElementsAreMatcherImplBase:: } } - { + if (match_flags() & UnorderedMatcherRequire::Superset) { const char* sep = "where the following matchers don't match any elements:\n"; for (size_t mi = 0; mi < matcher_matched.size(); ++mi) { - if (matcher_matched[mi]) - continue; + if (matcher_matched[mi]) continue; result = false; if (listener->IsInterested()) { *listener << sep << "matcher #" << mi << ": "; @@ -452,7 +454,7 @@ bool UnorderedElementsAreMatcherImplBase:: } } - { + if (match_flags() & UnorderedMatcherRequire::Subset) { const char* sep = "where the following elements don't match any matchers:\n"; const char* outer_sep = ""; @@ -460,8 +462,7 @@ bool UnorderedElementsAreMatcherImplBase:: outer_sep = "\nand "; } for (size_t ei = 0; ei < element_matched.size(); ++ei) { - if (element_matched[ei]) - continue; + if (element_matched[ei]) continue; result = false; if (listener->IsInterested()) { *listener << outer_sep << sep << "element #" << ei << ": " @@ -474,5 +475,46 @@ bool UnorderedElementsAreMatcherImplBase:: return result; } +bool UnorderedElementsAreMatcherImplBase::FindPairing( + const MatchMatrix& matrix, MatchResultListener* listener) const { + ElementMatcherPairs matches = FindMaxBipartiteMatching(matrix); + + size_t max_flow = matches.size(); + if ((match_flags() & UnorderedMatcherRequire::Superset) && + max_flow < matrix.RhsSize()) { + if (listener->IsInterested()) { + *listener << "where no permutation of the elements can satisfy all " + "matchers, and the closest match is " + << max_flow << " of " << matrix.RhsSize() + << " matchers with the pairings:\n"; + LogElementMatcherPairVec(matches, listener->stream()); + } + return false; + } + if ((match_flags() & UnorderedMatcherRequire::Subset) && + max_flow < matrix.LhsSize()) { + if (listener->IsInterested()) { + *listener + << "where not all elements can be matched, and the closest match is " + << max_flow << " of " << matrix.RhsSize() + << " matchers with the pairings:\n"; + LogElementMatcherPairVec(matches, listener->stream()); + } + return false; + } + + if (matches.size() > 1) { + if (listener->IsInterested()) { + const char* sep = "where:\n"; + for (size_t mi = 0; mi < matches.size(); ++mi) { + *listener << sep << " - element #" << matches[mi].first + << " is matched by matcher #" << matches[mi].second; + sep = ",\n"; + } + } + } + return true; +} + } // namespace internal } // namespace testing diff --git a/googlemock/test/gmock_link_test.h b/googlemock/test/gmock_link_test.h index 1f55f5b..5f855d1 100644 --- a/googlemock/test/gmock_link_test.h +++ b/googlemock/test/gmock_link_test.h @@ -120,13 +120,15 @@ # include <errno.h> #endif -#include "gmock/internal/gmock-port.h" -#include "gtest/gtest.h" #include <iostream> #include <vector> +#include "gtest/gtest.h" +#include "gtest/internal/gtest-port.h" + using testing::_; using testing::A; +using testing::Action; using testing::AllOf; using testing::AnyOf; using testing::Assign; @@ -148,6 +150,8 @@ using testing::Invoke; using testing::InvokeArgument; using testing::InvokeWithoutArgs; using testing::IsNull; +using testing::IsSubsetOf; +using testing::IsSupersetOf; using testing::Le; using testing::Lt; using testing::Matcher; @@ -592,6 +596,22 @@ TEST(LinkTest, TestMatcherElementsAreArray) { ON_CALL(mock, VoidFromVector(ElementsAreArray(arr))).WillByDefault(Return()); } +// Tests the linkage of the IsSubsetOf matcher. +TEST(LinkTest, TestMatcherIsSubsetOf) { + Mock mock; + char arr[] = {'a', 'b'}; + + ON_CALL(mock, VoidFromVector(IsSubsetOf(arr))).WillByDefault(Return()); +} + +// Tests the linkage of the IsSupersetOf matcher. +TEST(LinkTest, TestMatcherIsSupersetOf) { + Mock mock; + char arr[] = {'a', 'b'}; + + ON_CALL(mock, VoidFromVector(IsSupersetOf(arr))).WillByDefault(Return()); +} + // Tests the linkage of the ContainerEq matcher. TEST(LinkTest, TestMatcherContainerEq) { Mock mock; |