diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 7266fba7..688ce64f 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -1623,7 +1623,7 @@ struct CallableTraits { typedef ResType(*StorageType)(ArgType); static void CheckIsValid(ResType(*f)(ArgType)) { - GMOCK_CHECK_(f != NULL) + GTEST_CHECK_(f != NULL) << "NULL function pointer is passed into ResultOf()."; } template @@ -1934,6 +1934,94 @@ class KeyMatcher { const M matcher_for_key_; }; +// Implements Pair(first_matcher, second_matcher) for the given argument pair +// type with its two matchers. See Pair() function below. +template +class PairMatcherImpl : public MatcherInterface { + public: + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef typename RawPairType::first_type FirstType; + typedef typename RawPairType::second_type SecondType; + + template + PairMatcherImpl(FirstMatcher first_matcher, SecondMatcher second_matcher) + : first_matcher_( + testing::SafeMatcherCast(first_matcher)), + second_matcher_( + testing::SafeMatcherCast(second_matcher)) { + } + + // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second' + // matches second_matcher. + virtual bool Matches(PairType a_pair) const { + return first_matcher_.Matches(a_pair.first) && + second_matcher_.Matches(a_pair.second); + } + + // Describes what this matcher does. + virtual void DescribeTo(::std::ostream* os) const { + *os << "has a first field that "; + first_matcher_.DescribeTo(os); + *os << ", and has a second field that "; + second_matcher_.DescribeTo(os); + } + + // Describes what the negation of this matcher does. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "has a first field that "; + first_matcher_.DescribeNegationTo(os); + *os << ", or has a second field that "; + second_matcher_.DescribeNegationTo(os); + } + + // Explains why 'a_pair' matches, or doesn't match, this matcher. + virtual void ExplainMatchResultTo(PairType a_pair, + ::std::ostream* os) const { + ::std::stringstream ss1; + first_matcher_.ExplainMatchResultTo(a_pair.first, &ss1); + internal::string s1 = ss1.str(); + if (s1 != "") { + s1 = "the first field " + s1; + } + + ::std::stringstream ss2; + second_matcher_.ExplainMatchResultTo(a_pair.second, &ss2); + internal::string s2 = ss2.str(); + if (s2 != "") { + s2 = "the second field " + s2; + } + + *os << s1; + if (s1 != "" && s2 != "") { + *os << ", and "; + } + *os << s2; + } + + private: + const Matcher first_matcher_; + const Matcher second_matcher_; +}; + +// Implements polymorphic Pair(first_matcher, second_matcher). +template +class PairMatcher { + public: + PairMatcher(FirstMatcher first_matcher, SecondMatcher second_matcher) + : first_matcher_(first_matcher), second_matcher_(second_matcher) {} + + template + operator Matcher () const { + return MakeMatcher( + new PairMatcherImpl( + first_matcher_, second_matcher_)); + } + + private: + const FirstMatcher first_matcher_; + const SecondMatcher second_matcher_; +}; + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -2632,6 +2720,18 @@ inline internal::KeyMatcher Key(M inner_matcher) { return internal::KeyMatcher(inner_matcher); } +// Pair(first_matcher, second_matcher) matches a std::pair whose 'first' field +// matches first_matcher and whose 'second' field matches second_matcher. For +// example, EXPECT_THAT(map_type, ElementsAre(Pair(Ge(5), "foo"))) can be used +// to match a std::map that contains exactly one element whose key +// is >= 5 and whose value equals "foo". +template +inline internal::PairMatcher +Pair(FirstMatcher first_matcher, SecondMatcher second_matcher) { + return internal::PairMatcher( + first_matcher, second_matcher); +} + // Returns a predicate that is satisfied by anything that matches the // given matcher. template diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 6bee9966..0263491e 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -214,56 +214,6 @@ typedef ::wstring wstring; typedef ::std::wstring wstring; #endif // GTEST_HAS_GLOBAL_WSTRING -// Prints the file location in the format native to the compiler. -inline void FormatFileLocation(const char* file, int line, ::std::ostream* os) { - if (file == NULL) - file = "unknown file"; - if (line < 0) { - *os << file << ":"; - } else { -#if _MSC_VER - *os << file << "(" << line << "):"; -#else - *os << file << ":" << line << ":"; -#endif - } -} - -// INTERNAL IMPLEMENTATION - DO NOT USE. -// -// GMOCK_CHECK_ is an all mode assert. It aborts the program if the condition -// is not satisfied. -// Synopsys: -// GMOCK_CHECK_(boolean_condition); -// or -// GMOCK_CHECK_(boolean_condition) << "Additional message"; -// -// This checks the condition and if the condition is not satisfied -// it prints message about the condition violation, including the -// condition itself, plus additional message streamed into it, if any, -// and then it aborts the program. It aborts the program irrespective of -// whether it is built in the debug mode or not. - -class GMockCheckProvider { - public: - GMockCheckProvider(const char* condition, const char* file, int line) { - FormatFileLocation(file, line, &::std::cerr); - ::std::cerr << " ERROR: Condition " << condition << " failed. "; - } - ~GMockCheckProvider() { - ::std::cerr << ::std::endl; - posix::Abort(); - } - ::std::ostream& GetStream() { return ::std::cerr; } -}; -#define GMOCK_CHECK_(condition) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (condition) \ - ; \ - else \ - ::testing::internal::GMockCheckProvider(\ - #condition, __FILE__, __LINE__).GetStream() - } // namespace internal } // namespace testing diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 94ba24bb..72558658 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -203,8 +203,8 @@ class MockObjectRegistry { // This can help the user identify the leaked object. std::cout << "\n"; const MockObjectState& state = it->second; - internal::FormatFileLocation( - state.first_used_file, state.first_used_line, &std::cout); + std::cout << internal::FormatFileLocation(state.first_used_file, + state.first_used_line); std::cout << " ERROR: this mock object"; if (state.first_used_test != "") { std::cout << " (used in test " << state.first_used_test_case << "." diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 8926e944..ef878898 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -91,6 +92,7 @@ using testing::NanSensitiveFloatEq; using testing::Ne; using testing::Not; using testing::NotNull; +using testing::Pair; using testing::Pointee; using testing::PolymorphicMatcher; using testing::Property; @@ -126,6 +128,35 @@ using testing::MatchesRegex; using testing::internal::RE; #endif // GMOCK_HAS_REGEX +// For testing ExplainMatchResultTo(). +class GreaterThanMatcher : public MatcherInterface { + public: + explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} + + virtual bool Matches(int lhs) const { return lhs > rhs_; } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is greater than " << rhs_; + } + + virtual void ExplainMatchResultTo(int lhs, ::std::ostream* os) const { + const int diff = lhs - rhs_; + if (diff > 0) { + *os << "is " << diff << " more than " << rhs_; + } else if (diff == 0) { + *os << "is the same as " << rhs_; + } else { + *os << "is " << -diff << " less than " << rhs_; + } + } + private: + const int rhs_; +}; + +Matcher GreaterThan(int n) { + return MakeMatcher(new GreaterThanMatcher(n)); +} + // Returns the description of the given matcher. template string Describe(const Matcher& m) { @@ -899,6 +930,90 @@ TEST(KeyTest, InsideContainsUsingMultimap) { EXPECT_THAT(container, Not(Contains(Key(3)))); } +TEST(PairTest, Typing) { + // Test verifies the following type conversions can be compiled. + Matcher&> m1 = Pair("foo", 42); + Matcher > m2 = Pair("foo", 42); + Matcher > m3 = Pair("foo", 42); + + Matcher > m4 = Pair(25, "42"); + Matcher > m5 = Pair("25", 42); +} + +TEST(PairTest, CanDescribeSelf) { + Matcher&> m1 = Pair("foo", 42); + EXPECT_EQ("has a first field that is equal to \"foo\"" + ", and has a second field that is equal to 42", + Describe(m1)); + EXPECT_EQ("has a first field that is not equal to \"foo\"" + ", or has a second field that is not equal to 42", + DescribeNegation(m1)); + // Double and triple negation (1 or 2 times not and description of negation). + Matcher&> m2 = Not(Pair(Not(13), 42)); + EXPECT_EQ("has a first field that is not equal to 13" + ", and has a second field that is equal to 42", + DescribeNegation(m2)); +} + +TEST(PairTest, CanExplainMatchResultTo) { + const Matcher > m0 = Pair(0, 0); + EXPECT_EQ("", Explain(m0, std::make_pair(25, 42))); + + const Matcher > m1 = Pair(GreaterThan(0), 0); + EXPECT_EQ("the first field is 25 more than 0", + Explain(m1, std::make_pair(25, 42))); + + const Matcher > m2 = Pair(0, GreaterThan(0)); + EXPECT_EQ("the second field is 42 more than 0", + Explain(m2, std::make_pair(25, 42))); + + const Matcher > m3 = Pair(GreaterThan(0), GreaterThan(0)); + EXPECT_EQ("the first field is 25 more than 0" + ", and the second field is 42 more than 0", + Explain(m3, std::make_pair(25, 42))); +} + +TEST(PairTest, MatchesCorrectly) { + std::pair p(25, "foo"); + + // Both fields match. + EXPECT_THAT(p, Pair(25, "foo")); + EXPECT_THAT(p, Pair(Ge(20), HasSubstr("o"))); + + // 'first' doesnt' match, but 'second' matches. + EXPECT_THAT(p, Not(Pair(42, "foo"))); + EXPECT_THAT(p, Not(Pair(Lt(25), "foo"))); + + // 'first' matches, but 'second' doesn't match. + EXPECT_THAT(p, Not(Pair(25, "bar"))); + EXPECT_THAT(p, Not(Pair(25, Not("foo")))); + + // Neither field matches. + EXPECT_THAT(p, Not(Pair(13, "bar"))); + EXPECT_THAT(p, Not(Pair(Lt(13), HasSubstr("a")))); +} + +TEST(PairTest, SafelyCastsInnerMatchers) { + Matcher is_positive = Gt(0); + Matcher is_negative = Lt(0); + std::pair p('a', true); + EXPECT_THAT(p, Pair(is_positive, _)); + EXPECT_THAT(p, Not(Pair(is_negative, _))); + EXPECT_THAT(p, Pair(_, is_positive)); + EXPECT_THAT(p, Not(Pair(_, is_negative))); +} + +TEST(PairTest, InsideContainsUsingMap) { + std::map container; + container.insert(std::make_pair(1, "foo")); + container.insert(std::make_pair(2, "bar")); + container.insert(std::make_pair(4, "baz")); + EXPECT_THAT(container, Contains(Pair(1, "foo"))); + EXPECT_THAT(container, Contains(Pair(1, _))); + EXPECT_THAT(container, Contains(Pair(_, "foo"))); + EXPECT_THAT(container, Not(Contains(Pair(3, _)))); +} + // Tests StartsWith(s). TEST(StartsWithTest, MatchesStringWithGivenPrefix) { @@ -2150,35 +2265,6 @@ TEST(PointeeTest, CanDescribeSelf) { DescribeNegation(m)); } -// For testing ExplainMatchResultTo(). -class GreaterThanMatcher : public MatcherInterface { - public: - explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} - - virtual bool Matches(int lhs) const { return lhs > rhs_; } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "is greater than " << rhs_; - } - - virtual void ExplainMatchResultTo(int lhs, ::std::ostream* os) const { - const int diff = lhs - rhs_; - if (diff > 0) { - *os << "is " << diff << " more than " << rhs_; - } else if (diff == 0) { - *os << "is the same as " << rhs_; - } else { - *os << "is " << -diff << " less than " << rhs_; - } - } - private: - const int rhs_; -}; - -Matcher GreaterThan(int n) { - return MakeMatcher(new GreaterThanMatcher(n)); -} - TEST(PointeeTest, CanExplainMatchResult) { const Matcher m = Pointee(StartsWith("Hi")); diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index 7335405c..9a64ec33 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -36,61 +36,4 @@ #include #include -TEST(GmockCheckSyntaxTest, BehavesLikeASingleStatement) { - if (false) - GMOCK_CHECK_(false) << "This should never be executed; " - "It's a compilation test only."; - - if (true) - GMOCK_CHECK_(true); - else - ; - - if (false) - ; - else - GMOCK_CHECK_(true) << ""; -} - -TEST(GmockCheckSyntaxTest, WorksWithSwitch) { - switch (0) { - case 1: - break; - default: - GMOCK_CHECK_(true); - } - - switch(0) - case 0: - GMOCK_CHECK_(true) << "Check failed in switch case"; -} - -TEST(GmockCheckDeathTest, DiesWithCorrectOutputOnFailure) { - const bool a_false_condition = false; - // MSVC and gcc use different formats to print source file locations. - // Google Mock's failure messages use the same format as used by the - // compiler, in order for the IDE to recognize them. Therefore we look - // for different patterns here depending on the compiler. - const char regex[] = -#ifdef _MSC_VER - "gmock-port_test\\.cc\\(\\d+\\):" -#else - "gmock-port_test\\.cc:[0-9]+" -#endif // _MSC_VER - ".*a_false_condition.*Extra info"; - - EXPECT_DEATH_IF_SUPPORTED(GMOCK_CHECK_(a_false_condition) << "Extra info", - regex); -} - -#if GTEST_HAS_DEATH_TEST - -TEST(GmockCheckDeathTest, LivesSilentlyOnSuccess) { - EXPECT_EXIT({ - GMOCK_CHECK_(true) << "Extra info"; - ::std::cerr << "Success\n"; - exit(0); }, - ::testing::ExitedWithCode(0), "Success"); -} - -#endif // GTEST_HAS_DEATH_TEST +// This file intentionally contains no test at this moment.