Merge branch 'variant_matcher' of https://github.com/zhangxy988/googletest into variant_matcher
This commit is contained in:
commit
e1622337ae
@ -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);
|
||||
@ -3685,7 +3698,7 @@ class VariantMatcher {
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// ElementsAreArray(first, last)
|
||||
// ElementsAreArray(iterator_first, iterator_last)
|
||||
// ElementsAreArray(pointer, count)
|
||||
// ElementsAreArray(array)
|
||||
// ElementsAreArray(container)
|
||||
@ -3734,20 +3747,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>
|
||||
@ -3789,7 +3808,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>
|
||||
@ -4359,6 +4380,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.
|
||||
//
|
||||
|
@ -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;
|
||||
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;
|
||||
}
|
||||
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";
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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";
|
||||
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
|
||||
|
@ -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;
|
||||
|
@ -91,7 +91,7 @@ macro(config_compiler_and_linker)
|
||||
set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
|
||||
set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
|
||||
set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
|
||||
set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0")
|
||||
set(cxx_no_exception_flags "-EHs-c- -D_HAS_EXCEPTIONS=0")
|
||||
set(cxx_no_rtti_flags "-GR-")
|
||||
elseif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(cxx_base_flags "-Wall -Wshadow -Werror")
|
||||
|
@ -471,8 +471,11 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
|
||||
#ifndef GTEST_HAS_EXCEPTIONS
|
||||
// The user didn't tell us whether exceptions are enabled, so we need
|
||||
// to figure it out.
|
||||
# if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
|
||||
# if defined(_MSC_VER) && defined(_CPPUNWIND)
|
||||
// MSVC defines _CPPUNWIND to 1 iff exceptions are enabled.
|
||||
# define GTEST_HAS_EXCEPTIONS 1
|
||||
# elif defined(__BORLANDC__)
|
||||
// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS
|
||||
// macro to enable exceptions, so we'll do the same.
|
||||
// Assumes that exceptions are enabled by default.
|
||||
# ifndef _HAS_EXCEPTIONS
|
||||
|
Loading…
Reference in New Issue
Block a user