diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 19bd551a..dc93468c 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1972,6 +1972,58 @@ class ResultOfMatcher { GTEST_DISALLOW_ASSIGN_(ResultOfMatcher); }; +// Implements a matcher that checks the size of an STL-style container. +template +class SizeIsMatcher { + public: + explicit SizeIsMatcher(const SizeMatcher& size_matcher) + : size_matcher_(size_matcher) { + } + + template + operator Matcher() const { + return MakeMatcher(new Impl(size_matcher_)); + } + + template + class Impl : public MatcherInterface { + public: + typedef internal::StlContainerView< + GTEST_REMOVE_REFERENCE_AND_CONST_(Container)> ContainerView; + typedef typename ContainerView::type::size_type SizeType; + explicit Impl(const SizeMatcher& size_matcher) + : size_matcher_(MatcherCast(size_matcher)) {} + + virtual void DescribeTo(::std::ostream* os) const { + *os << "size "; + size_matcher_.DescribeTo(os); + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "size "; + size_matcher_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { + SizeType size = container.size(); + StringMatchResultListener size_listener; + const bool result = size_matcher_.MatchAndExplain(size, &size_listener); + *listener + << "whose size " << size << (result ? " matches" : " doesn't match"); + PrintIfNotEmpty(size_listener.str(), listener->stream()); + return result; + } + + private: + const Matcher size_matcher_; + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + private: + const SizeMatcher size_matcher_; + GTEST_DISALLOW_ASSIGN_(SizeIsMatcher); +}; + // 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. @@ -3079,6 +3131,18 @@ Truly(Predicate pred) { return MakePolymorphicMatcher(internal::TrulyMatcher(pred)); } +// Returns a matcher that matches the container size. The container must +// support both size() and size_type which all STL-like containers provide. +// Note that the parameter 'size' can be a value of type size_type as well as +// matcher. For instance: +// EXPECT_THAT(container, SizeIs(2)); // Checks container has 2 elements. +// EXPECT_THAT(container, SizeIs(Le(2)); // Checks container has at most 2. +template +inline internal::SizeIsMatcher +SizeIs(const SizeMatcher& size_matcher) { + return internal::SizeIsMatcher(size_matcher); +} + // 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 diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index e75b06e0..81460925 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -114,6 +114,7 @@ using testing::PolymorphicMatcher; using testing::Property; using testing::Ref; using testing::ResultOf; +using testing::SizeIs; using testing::StartsWith; using testing::StrCaseEq; using testing::StrCaseNe; @@ -3637,6 +3638,64 @@ TEST(IsEmptyTest, ExplainsResult) { EXPECT_EQ("whose size is 1", Explain(m, container)); } +TEST(SizeIsTest, ImplementsSizeIs) { + vector container; + EXPECT_THAT(container, SizeIs(0)); + EXPECT_THAT(container, Not(SizeIs(1))); + container.push_back(0); + EXPECT_THAT(container, Not(SizeIs(0))); + EXPECT_THAT(container, SizeIs(1)); + container.push_back(0); + EXPECT_THAT(container, Not(SizeIs(0))); + EXPECT_THAT(container, SizeIs(2)); +} + +TEST(SizeIsTest, WorksWithMap) { + map container; + EXPECT_THAT(container, SizeIs(0)); + EXPECT_THAT(container, Not(SizeIs(1))); + container.insert(make_pair("foo", 1)); + EXPECT_THAT(container, Not(SizeIs(0))); + EXPECT_THAT(container, SizeIs(1)); + container.insert(make_pair("bar", 2)); + EXPECT_THAT(container, Not(SizeIs(0))); + EXPECT_THAT(container, SizeIs(2)); +} + +TEST(SizeIsTest, WorksWithReferences) { + vector container; + Matcher&> m = SizeIs(1); + EXPECT_THAT(container, Not(m)); + container.push_back(0); + EXPECT_THAT(container, m); +} + +TEST(SizeIsTest, CanDescribeSelf) { + Matcher > m = SizeIs(2); + EXPECT_EQ("size is equal to 2", Describe(m)); + EXPECT_EQ("size isn't equal to 2", DescribeNegation(m)); +} + +TEST(SizeIsTest, ExplainsResult) { + Matcher > m1 = SizeIs(2); + Matcher > m2 = SizeIs(Lt(2u)); + Matcher > m3 = SizeIs(AnyOf(0, 3)); + Matcher > m4 = SizeIs(GreaterThan(1)); + vector container; + EXPECT_EQ("whose size 0 doesn't match", Explain(m1, container)); + EXPECT_EQ("whose size 0 matches", Explain(m2, container)); + EXPECT_EQ("whose size 0 matches", Explain(m3, container)); + EXPECT_EQ("whose size 0 doesn't match, which is 1 less than 1", + Explain(m4, container)); + container.push_back(0); + container.push_back(0); + EXPECT_EQ("whose size 2 matches", Explain(m1, container)); + EXPECT_EQ("whose size 2 doesn't match", Explain(m2, container)); + EXPECT_EQ("whose size 2 doesn't match", Explain(m3, container)); + EXPECT_EQ("whose size 2 matches, which is 1 more than 1", + Explain(m4, container)); +} + #if GTEST_HAS_TYPED_TEST // Tests ContainerEq with different container types, and // different element types.