diff --git a/Makefile.am b/Makefile.am index 8e9b61c3..f0aa5c5c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -137,9 +137,7 @@ EXTRA_DIST += include/gmock/gmock-generated-actions.h.pump \ include/gmock/internal/gmock-generated-internal-utils.h.pump # Script for fusing Google Mock and Google Test source files. -EXTRA_DIST += \ - scripts/fuse_gmock_files.py \ - scripts/test/Makefile +EXTRA_DIST += scripts/fuse_gmock_files.py # The Google Mock Generator tool from the cppclean project. EXTRA_DIST += \ diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 66efecd4..7ca2f007 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1947,9 +1947,9 @@ class ContainerEqMatcher { GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); }; -// Implements Contains(element_matcher) for the given argument type Container. +// Holds the logic common to ContainsMatcherImpl and EachMatcherImpl. template -class ContainsMatcherImpl : public MatcherInterface { +class QuantifierMatcherImpl : public MatcherInterface { public: typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer; typedef StlContainerView View; @@ -1958,44 +1958,97 @@ class ContainsMatcherImpl : public MatcherInterface { typedef typename StlContainer::value_type Element; template - explicit ContainsMatcherImpl(InnerMatcher inner_matcher) + explicit QuantifierMatcherImpl(InnerMatcher inner_matcher) : inner_matcher_( - testing::SafeMatcherCast(inner_matcher)) {} + testing::SafeMatcherCast(inner_matcher)) {} - // Describes what this matcher does. - virtual void DescribeTo(::std::ostream* os) const { - *os << "contains at least one element that "; - inner_matcher_.DescribeTo(os); - } - - // Describes what the negation of this matcher does. - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "doesn't contain any element that "; - inner_matcher_.DescribeTo(os); - } - - virtual bool MatchAndExplain(Container container, - MatchResultListener* listener) const { + // Checks whether: + // * All elements in the container match, if all_elements_should_match. + // * Any element in the container matches, if !all_elements_should_match. + bool MatchAndExplainImpl(bool all_elements_should_match, + Container container, + MatchResultListener* listener) const { StlContainerReference stl_container = View::ConstReference(container); size_t i = 0; for (typename StlContainer::const_iterator it = stl_container.begin(); it != stl_container.end(); ++it, ++i) { StringMatchResultListener inner_listener; - if (inner_matcher_.MatchAndExplain(*it, &inner_listener)) { - *listener << "whose element #" << i << " matches"; + const bool matches = inner_matcher_.MatchAndExplain(*it, &inner_listener); + + if (matches != all_elements_should_match) { + *listener << "whose element #" << i + << (matches ? " matches" : " doesn't match"); PrintIfNotEmpty(inner_listener.str(), listener->stream()); - return true; + return !all_elements_should_match; } } - return false; + return all_elements_should_match; + } + + protected: + const Matcher inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(QuantifierMatcherImpl); +}; + +// Implements Contains(element_matcher) for the given argument type Container. +// Symmetric to EachMatcherImpl. +template +class ContainsMatcherImpl : public QuantifierMatcherImpl { + public: + template + explicit ContainsMatcherImpl(InnerMatcher inner_matcher) + : QuantifierMatcherImpl(inner_matcher) {} + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + *os << "contains at least one element that "; + this->inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't contain any element that "; + this->inner_matcher_.DescribeTo(os); + } + + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { + return this->MatchAndExplainImpl(false, container, listener); } private: - const Matcher inner_matcher_; - GTEST_DISALLOW_ASSIGN_(ContainsMatcherImpl); }; +// Implements Each(element_matcher) for the given argument type Container. +// Symmetric to ContainsMatcherImpl. +template +class EachMatcherImpl : public QuantifierMatcherImpl { + public: + template + explicit EachMatcherImpl(InnerMatcher inner_matcher) + : QuantifierMatcherImpl(inner_matcher) {} + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + *os << "only contains elements that "; + this->inner_matcher_.DescribeTo(os); + } + + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "contains some element that "; + this->inner_matcher_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { + return this->MatchAndExplainImpl(true, container, listener); + } + + private: + GTEST_DISALLOW_ASSIGN_(EachMatcherImpl); +}; + // Implements polymorphic Contains(element_matcher). template class ContainsMatcher { @@ -2013,6 +2066,23 @@ class ContainsMatcher { GTEST_DISALLOW_ASSIGN_(ContainsMatcher); }; +// Implements polymorphic Each(element_matcher). +template +class EachMatcher { + public: + explicit EachMatcher(M m) : inner_matcher_(m) {} + + template + operator Matcher() const { + return MakeMatcher(new EachMatcherImpl(inner_matcher_)); + } + + private: + const M inner_matcher_; + + GTEST_DISALLOW_ASSIGN_(EachMatcher); +}; + // Implements Key(inner_matcher) for the given argument pair type. // Key(inner_matcher) matches an std::pair whose 'first' field matches // inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an @@ -2855,6 +2925,38 @@ inline internal::ContainsMatcher Contains(M matcher) { return internal::ContainsMatcher(matcher); } +// Matches an STL-style container or a native array that contains only +// elements matching the given value or matcher. +// +// Each(m) is semantically equivalent to Not(Contains(Not(m))). Only +// the messages are different. +// +// Examples: +// ::std::set page_ids; +// // Each(m) matches an empty container, regardless of what m is. +// EXPECT_THAT(page_ids, Each(Eq(1))); +// EXPECT_THAT(page_ids, Each(Eq(77))); +// +// page_ids.insert(3); +// EXPECT_THAT(page_ids, Each(Gt(0))); +// EXPECT_THAT(page_ids, Not(Each(Gt(4)))); +// page_ids.insert(1); +// EXPECT_THAT(page_ids, Not(Each(Lt(2)))); +// +// ::std::map page_lengths; +// page_lengths[1] = 100; +// page_lengths[2] = 200; +// page_lengths[3] = 300; +// EXPECT_THAT(page_lengths, Not(Each(Pair(1, 100)))); +// EXPECT_THAT(page_lengths, Each(Key(Le(3)))); +// +// const char* user_ids[] = { "joe", "mike", "tom" }; +// EXPECT_THAT(user_ids, Not(Each(Eq(::std::string("tom"))))); +template +inline internal::EachMatcher Each(M matcher) { + return internal::EachMatcher(matcher); +} + // Key(inner_matcher) matches an std::pair whose 'first' field matches // inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an // std::map that contains at least one element whose key is >= 5. diff --git a/scripts/test/Makefile b/scripts/test/Makefile deleted file mode 100644 index 8edaea06..00000000 --- a/scripts/test/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# A Makefile for fusing Google Mock and building a sample test against it. -# -# SYNOPSIS: -# -# make [all] - makes everything. -# make TARGET - makes the given target. -# make check - makes everything and runs the built sample test. -# make clean - removes all files generated by make. - -# Points to the root of fused Google Mock, relative to where this file is. -FUSED_GMOCK_DIR = output - -# Paths to the fused gmock files. -FUSED_GTEST_H = $(FUSED_GMOCK_DIR)/gtest/gtest.h -FUSED_GMOCK_H = $(FUSED_GMOCK_DIR)/gmock/gmock.h -FUSED_GMOCK_GTEST_ALL_CC = $(FUSED_GMOCK_DIR)/gmock-gtest-all.cc - -# Where to find the gmock_test.cc. -GMOCK_TEST_CC = ../../test/gmock_test.cc - -# Where to find gmock_main.cc. -GMOCK_MAIN_CC = ../../src/gmock_main.cc - -# Flags passed to the preprocessor. -CPPFLAGS += -I$(FUSED_GMOCK_DIR) - -# Flags passed to the C++ compiler. -CXXFLAGS += -g - -all : gmock_test - -check : all - ./gmock_test - -clean : - rm -rf $(FUSED_GMOCK_DIR) gmock_test *.o - -$(FUSED_GTEST_H) : - ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) - -$(FUSED_GMOCK_H) : - ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) - -$(FUSED_GMOCK_GTEST_ALL_CC) : - ../fuse_gmock_files.py $(FUSED_GMOCK_DIR) - -gmock-gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(FUSED_GMOCK_GTEST_ALL_CC) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GMOCK_GTEST_ALL_CC) - -gmock_main.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(GMOCK_MAIN_CC) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_MAIN_CC) - -gmock_test.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(GMOCK_TEST_CC) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_TEST_CC) - -gmock_test : gmock_test.o gmock-gtest-all.o gmock_main.o - $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 6d784f16..a7c217d4 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -65,8 +65,10 @@ using std::make_pair; using std::map; using std::multimap; using std::pair; +using std::set; using std::stringstream; using std::tr1::make_tuple; +using std::vector; using testing::A; using testing::AllArgs; using testing::AllOf; @@ -363,20 +365,20 @@ TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) { // Tests that MakePolymorphicMatcher() can construct a polymorphic // matcher from its implementation using the old API. -const int bar = 1; +const int g_bar = 1; class ReferencesBarOrIsZeroImpl { public: template bool MatchAndExplain(const T& x, MatchResultListener* /* listener */) const { const void* p = &x; - return p == &bar || x == 0; + return p == &g_bar || x == 0; } - void DescribeTo(::std::ostream* os) const { *os << "bar or zero"; } + void DescribeTo(::std::ostream* os) const { *os << "g_bar or zero"; } void DescribeNegationTo(::std::ostream* os) const { - *os << "doesn't reference bar and is not zero"; + *os << "doesn't reference g_bar and is not zero"; } }; @@ -391,15 +393,15 @@ TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingOldAPI) { Matcher m1 = ReferencesBarOrIsZero(); EXPECT_TRUE(m1.Matches(0)); // Verifies that the identity of a by-reference argument is preserved. - EXPECT_TRUE(m1.Matches(bar)); + EXPECT_TRUE(m1.Matches(g_bar)); EXPECT_FALSE(m1.Matches(1)); - EXPECT_EQ("bar or zero", Describe(m1)); + EXPECT_EQ("g_bar or zero", Describe(m1)); // Using a polymorphic matcher to match a value type. Matcher m2 = ReferencesBarOrIsZero(); EXPECT_TRUE(m2.Matches(0.0)); EXPECT_FALSE(m2.Matches(0.1)); - EXPECT_EQ("bar or zero", Describe(m2)); + EXPECT_EQ("g_bar or zero", Describe(m2)); } // Tests implementing a polymorphic matcher using MatchAndExplain(). @@ -3984,5 +3986,91 @@ TEST(MatcherTupleTest, ExplainsMatchFailure) { // explanation. } +// Tests Each(). + +TEST(EachTest, ExplainsMatchResultCorrectly) { + set a; // empty + + Matcher > m = Each(2); + EXPECT_EQ("", Explain(m, a)); + + Matcher n = Each(1); + + const int b[1] = { 1 }; + EXPECT_EQ("", Explain(n, b)); + + n = Each(3); + EXPECT_EQ("whose element #0 doesn't match", Explain(n, b)); + + a.insert(1); + a.insert(2); + a.insert(3); + m = Each(GreaterThan(0)); + EXPECT_EQ("", Explain(m, a)); + + m = Each(GreaterThan(10)); + EXPECT_EQ("whose element #0 doesn't match, which is 9 less than 10", + Explain(m, a)); +} + +TEST(EachTest, DescribesItselfCorrectly) { + Matcher > m = Each(1); + EXPECT_EQ("only contains elements that is equal to 1", Describe(m)); + + Matcher > m2 = Not(m); + EXPECT_EQ("contains some element that isn't equal to 1", Describe(m2)); +} + +TEST(EachTest, MatchesVectorWhenAllElementsMatch) { + vector some_vector; + EXPECT_THAT(some_vector, Each(1)); + some_vector.push_back(3); + EXPECT_THAT(some_vector, Not(Each(1))); + EXPECT_THAT(some_vector, Each(3)); + some_vector.push_back(1); + some_vector.push_back(2); + EXPECT_THAT(some_vector, Not(Each(3))); + EXPECT_THAT(some_vector, Each(Lt(3.5))); + + vector another_vector; + another_vector.push_back("fee"); + EXPECT_THAT(another_vector, Each(string("fee"))); + another_vector.push_back("fie"); + another_vector.push_back("foe"); + another_vector.push_back("fum"); + EXPECT_THAT(another_vector, Not(Each(string("fee")))); +} + +TEST(EachTest, MatchesMapWhenAllElementsMatch) { + map my_map; + const char* bar = "a string"; + my_map[bar] = 2; + EXPECT_THAT(my_map, Each(make_pair(bar, 2))); + + map another_map; + EXPECT_THAT(another_map, Each(make_pair(string("fee"), 1))); + another_map["fee"] = 1; + EXPECT_THAT(another_map, Each(make_pair(string("fee"), 1))); + another_map["fie"] = 2; + another_map["foe"] = 3; + another_map["fum"] = 4; + EXPECT_THAT(another_map, Not(Each(make_pair(string("fee"), 1)))); + EXPECT_THAT(another_map, Not(Each(make_pair(string("fum"), 1)))); + EXPECT_THAT(another_map, Each(Pair(_, Gt(0)))); +} + +TEST(EachTest, AcceptsMatcher) { + const int a[] = { 1, 2, 3 }; + EXPECT_THAT(a, Each(Gt(0))); + EXPECT_THAT(a, Not(Each(Gt(1)))); +} + +TEST(EachTest, WorksForNativeArrayAsTuple) { + const int a[] = { 1, 2 }; + const int* const pointer = a; + EXPECT_THAT(make_tuple(pointer, 2), Each(Gt(0))); + EXPECT_THAT(make_tuple(pointer, 2), Not(Each(Gt(1)))); +} + } // namespace gmock_matchers_test } // namespace testing