Implements ContainerEq.
This commit is contained in:
		@@ -38,6 +38,7 @@
 | 
				
			|||||||
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
 | 
					#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
 | 
				
			||||||
#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
 | 
					#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
#include <ostream>  // NOLINT
 | 
					#include <ostream>  // NOLINT
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
@@ -1635,6 +1636,73 @@ void ExplainMatchResultTo(const ResultOfMatcher<Callable>& matcher,
 | 
				
			|||||||
  matcher.ExplainMatchResultTo(obj, os);
 | 
					  matcher.ExplainMatchResultTo(obj, os);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Implements an equality matcher for any STL-style container whose elements
 | 
				
			||||||
 | 
					// support ==. This matcher is like Eq(), but its failure explanations provide
 | 
				
			||||||
 | 
					// more detailed information that is useful when the container is used as a set.
 | 
				
			||||||
 | 
					// The failure message reports elements that are in one of the operands but not
 | 
				
			||||||
 | 
					// the other. The failure messages do not report duplicate or out-of-order
 | 
				
			||||||
 | 
					// elements in the containers (which don't properly matter to sets, but can
 | 
				
			||||||
 | 
					// occur if the containers are vectors or lists, for example).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Uses the container's const_iterator, value_type, operator ==,
 | 
				
			||||||
 | 
					// begin(), and end().
 | 
				
			||||||
 | 
					template <typename Container>
 | 
				
			||||||
 | 
					class ContainerEqMatcher {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  explicit ContainerEqMatcher(const Container& rhs) : rhs_(rhs) {}
 | 
				
			||||||
 | 
					  bool Matches(const Container& lhs) const { return lhs == rhs_; }
 | 
				
			||||||
 | 
					  void DescribeTo(::std::ostream* os) const {
 | 
				
			||||||
 | 
					    *os << "equals ";
 | 
				
			||||||
 | 
					    UniversalPrinter<Container>::Print(rhs_, os);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void DescribeNegationTo(::std::ostream* os) const {
 | 
				
			||||||
 | 
					    *os << "does not equal ";
 | 
				
			||||||
 | 
					    UniversalPrinter<Container>::Print(rhs_, os);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void ExplainMatchResultTo(const Container& lhs,
 | 
				
			||||||
 | 
					                            ::std::ostream* os) const {
 | 
				
			||||||
 | 
					    // Something is different. Check for missing values first.
 | 
				
			||||||
 | 
					    bool printed_header = false;
 | 
				
			||||||
 | 
					    for (typename Container::const_iterator it = lhs.begin();
 | 
				
			||||||
 | 
					         it != lhs.end(); ++it) {
 | 
				
			||||||
 | 
					      if (std::find(rhs_.begin(), rhs_.end(), *it) == rhs_.end()) {
 | 
				
			||||||
 | 
					        if (printed_header) {
 | 
				
			||||||
 | 
					          *os << ", ";
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          *os << "Only in actual: ";
 | 
				
			||||||
 | 
					          printed_header = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        UniversalPrinter<typename Container::value_type>::Print(*it, os);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Now check for extra values.
 | 
				
			||||||
 | 
					    bool printed_header2 = false;
 | 
				
			||||||
 | 
					    for (typename Container::const_iterator it = rhs_.begin();
 | 
				
			||||||
 | 
					         it != rhs_.end(); ++it) {
 | 
				
			||||||
 | 
					      if (std::find(lhs.begin(), lhs.end(), *it) == lhs.end()) {
 | 
				
			||||||
 | 
					        if (printed_header2) {
 | 
				
			||||||
 | 
					          *os << ", ";
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          *os << (printed_header ? "; not" : "Not") << " in actual: ";
 | 
				
			||||||
 | 
					          printed_header2 = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        UniversalPrinter<typename Container::value_type>::Print(*it, os);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  const Container rhs_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Container>
 | 
				
			||||||
 | 
					void ExplainMatchResultTo(const ContainerEqMatcher<Container>& matcher,
 | 
				
			||||||
 | 
					                          const Container& lhs,
 | 
				
			||||||
 | 
					                          ::std::ostream* os) {
 | 
				
			||||||
 | 
					  matcher.ExplainMatchResultTo(lhs, os);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace internal
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Implements MatcherCast().
 | 
					// Implements MatcherCast().
 | 
				
			||||||
@@ -2073,6 +2141,16 @@ Truly(Predicate pred) {
 | 
				
			|||||||
  return MakePolymorphicMatcher(internal::TrulyMatcher<Predicate>(pred));
 | 
					  return MakePolymorphicMatcher(internal::TrulyMatcher<Predicate>(pred));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns a matcher that matches an equal container.
 | 
				
			||||||
 | 
					// This matcher behaves like Eq(), but in the event of mismatch lists the
 | 
				
			||||||
 | 
					// values that are included in one container but not the other. (Duplicate
 | 
				
			||||||
 | 
					// values and order differences are not explained.)
 | 
				
			||||||
 | 
					template <typename Container>
 | 
				
			||||||
 | 
					inline PolymorphicMatcher<internal::ContainerEqMatcher<Container> >
 | 
				
			||||||
 | 
					    ContainerEq(const Container& rhs) {
 | 
				
			||||||
 | 
					  return MakePolymorphicMatcher(internal::ContainerEqMatcher<Container>(rhs));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Returns a predicate that is satisfied by anything that matches the
 | 
					// Returns a predicate that is satisfied by anything that matches the
 | 
				
			||||||
// given matcher.
 | 
					// given matcher.
 | 
				
			||||||
template <typename M>
 | 
					template <typename M>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,8 +37,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <string>
 | 
					#include <list>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <set>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
#include <gmock/gmock.h>
 | 
					#include <gmock/gmock.h>
 | 
				
			||||||
#include <gtest/gtest.h>
 | 
					#include <gtest/gtest.h>
 | 
				
			||||||
#include <gtest/gtest-spi.h>
 | 
					#include <gtest/gtest-spi.h>
 | 
				
			||||||
@@ -2625,5 +2629,145 @@ TEST(ByRefTest, AllowsNotCopyableValueInMatchers) {
 | 
				
			|||||||
  EXPECT_TRUE(m.Matches(n2));
 | 
					  EXPECT_TRUE(m.Matches(n2));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests ContainerEq with different container types, and
 | 
				
			||||||
 | 
					// different element types.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					class ContainerEqTest : public testing::Test {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef testing::Types<
 | 
				
			||||||
 | 
					    std::set<int>,
 | 
				
			||||||
 | 
					    std::vector<size_t>,
 | 
				
			||||||
 | 
					    std::multiset<size_t>,
 | 
				
			||||||
 | 
					    std::list<int> >
 | 
				
			||||||
 | 
					    ContainerEqTestTypes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TYPED_TEST_CASE(ContainerEqTest, ContainerEqTestTypes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests that the filled container is equal to itself.
 | 
				
			||||||
 | 
					TYPED_TEST(ContainerEqTest, EqualsSelf) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  TypeParam my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  const Matcher<TypeParam> m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  EXPECT_TRUE(m.Matches(my_set));
 | 
				
			||||||
 | 
					  EXPECT_EQ("", Explain(m, my_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests that missing values are reported.
 | 
				
			||||||
 | 
					TYPED_TEST(ContainerEqTest, ValueMissing) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  static const int test_vals[] = {2, 1, 8, 5};
 | 
				
			||||||
 | 
					  TypeParam my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  TypeParam test_set(test_vals, test_vals + 4);
 | 
				
			||||||
 | 
					  const Matcher<TypeParam> m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(test_set));
 | 
				
			||||||
 | 
					  EXPECT_EQ("Not in actual: 3", Explain(m, test_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests that added values are reported.
 | 
				
			||||||
 | 
					TYPED_TEST(ContainerEqTest, ValueAdded) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  static const int test_vals[] = {1, 2, 3, 5, 8, 46};
 | 
				
			||||||
 | 
					  TypeParam my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  TypeParam test_set(test_vals, test_vals + 6);
 | 
				
			||||||
 | 
					  const Matcher<const TypeParam&> m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(test_set));
 | 
				
			||||||
 | 
					  EXPECT_EQ("Only in actual: 46", Explain(m, test_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests that added and missing values are reported together.
 | 
				
			||||||
 | 
					TYPED_TEST(ContainerEqTest, ValueAddedAndRemoved) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  static const int test_vals[] = {1, 2, 3, 8, 46};
 | 
				
			||||||
 | 
					  TypeParam my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  TypeParam test_set(test_vals, test_vals + 5);
 | 
				
			||||||
 | 
					  const Matcher<TypeParam> m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(test_set));
 | 
				
			||||||
 | 
					  EXPECT_EQ("Only in actual: 46; not in actual: 5", Explain(m, test_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests duplicated value -- expect no explanation.
 | 
				
			||||||
 | 
					TYPED_TEST(ContainerEqTest, DuplicateDifference) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  static const int test_vals[] = {1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  TypeParam my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  TypeParam test_set(test_vals, test_vals + 5);
 | 
				
			||||||
 | 
					  const Matcher<const TypeParam&> m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  // Depending on the container, match may be true or false
 | 
				
			||||||
 | 
					  // But in any case there should be no explanation.
 | 
				
			||||||
 | 
					  EXPECT_EQ("", Explain(m, test_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests that mutliple missing values are reported.
 | 
				
			||||||
 | 
					// Using just vector here, so order is predicatble.
 | 
				
			||||||
 | 
					TEST(ContainerEqExtraTest, MultipleValuesMissing) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  static const int test_vals[] = {2, 1, 5};
 | 
				
			||||||
 | 
					  std::vector<int> my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  std::vector<int> test_set(test_vals, test_vals + 3);
 | 
				
			||||||
 | 
					  const Matcher<std::vector<int> > m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(test_set));
 | 
				
			||||||
 | 
					  EXPECT_EQ("Not in actual: 3, 8", Explain(m, test_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests that added values are reported.
 | 
				
			||||||
 | 
					// Using just vector here, so order is predicatble.
 | 
				
			||||||
 | 
					TEST(ContainerEqExtraTest, MultipleValuesAdded) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  static const int test_vals[] = {1, 2, 92, 3, 5, 8, 46};
 | 
				
			||||||
 | 
					  std::list<size_t> my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  std::list<size_t> test_set(test_vals, test_vals + 7);
 | 
				
			||||||
 | 
					  const Matcher<const std::list<size_t>&> m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(test_set));
 | 
				
			||||||
 | 
					  EXPECT_EQ("Only in actual: 92, 46", Explain(m, test_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests that added and missing values are reported together.
 | 
				
			||||||
 | 
					TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  static const int test_vals[] = {1, 2, 3, 92, 46};
 | 
				
			||||||
 | 
					  std::list<size_t> my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  std::list<size_t> test_set(test_vals, test_vals + 5);
 | 
				
			||||||
 | 
					  const Matcher<const std::list<size_t> > m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(test_set));
 | 
				
			||||||
 | 
					  EXPECT_EQ("Only in actual: 92, 46; not in actual: 5, 8",
 | 
				
			||||||
 | 
					            Explain(m, test_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests to see that duplicate elements are detected,
 | 
				
			||||||
 | 
					// but (as above) not reported in the explanation.
 | 
				
			||||||
 | 
					TEST(ContainerEqExtraTest, MultiSetOfIntDuplicateDifference) {
 | 
				
			||||||
 | 
					  static const int vals[] = {1, 1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  static const int test_vals[] = {1, 2, 3, 5, 8};
 | 
				
			||||||
 | 
					  std::vector<int> my_set(vals, vals + 6);
 | 
				
			||||||
 | 
					  std::vector<int> test_set(test_vals, test_vals + 5);
 | 
				
			||||||
 | 
					  const Matcher<std::vector<int> > m = ContainerEq(my_set);
 | 
				
			||||||
 | 
					  EXPECT_TRUE(m.Matches(my_set));
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(test_set));
 | 
				
			||||||
 | 
					  // There is nothing to report when both sets contain all the same values.
 | 
				
			||||||
 | 
					  EXPECT_EQ("", Explain(m, test_set));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tests that ContainerEq works for non-trivial associative containers,
 | 
				
			||||||
 | 
					// like maps.
 | 
				
			||||||
 | 
					TEST(ContainerEqExtraTest, WorksForMaps) {
 | 
				
			||||||
 | 
					  std::map<int, std::string> my_map;
 | 
				
			||||||
 | 
					  my_map[0] = "a";
 | 
				
			||||||
 | 
					  my_map[1] = "b";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::map<int, std::string> test_map;
 | 
				
			||||||
 | 
					  test_map[0] = "aa";
 | 
				
			||||||
 | 
					  test_map[1] = "b";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Matcher<const std::map<int, std::string>&> m = ContainerEq(my_map);
 | 
				
			||||||
 | 
					  EXPECT_TRUE(m.Matches(my_map));
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(test_map));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_EQ("Only in actual: (0, \"aa\"); not in actual: (0, \"a\")",
 | 
				
			||||||
 | 
					            Explain(m, test_map));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace gmock_matchers_test
 | 
					}  // namespace gmock_matchers_test
 | 
				
			||||||
}  // namespace testing
 | 
					}  // namespace testing
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user