Adds IsInterested() to MatchResultListener; clarifies the format of matcher description and match result explanation; renames the free function MatchAndExplain() to ExplainMatchResult() to avoid it being hidden inside a MATCHER* definition.

This commit is contained in:
zhanyong.wan 2010-03-15 21:23:04 +00:00
parent 34b034c21e
commit a862f1de30
2 changed files with 61 additions and 11 deletions

View File

@ -90,6 +90,12 @@ class MatchResultListener {
// Returns the underlying ostream.
::std::ostream* stream() { return stream_; }
// Returns true iff the listener is interested in an explanation of
// the match result. A matcher's MatchAndExplain() method can use
// this information to avoid generating the explanation when no one
// intends to hear it.
bool IsInterested() const { return stream_ != NULL; }
private:
::std::ostream* const stream_;
@ -106,7 +112,10 @@ class MatcherInterface {
virtual ~MatcherInterface() {}
// Returns true iff the matcher matches x; also explains the match
// result to 'listener'.
// result to 'listener', in the form of a non-restrictive relative
// clause ("which ...", "whose ...", etc) that describes x. For
// example, the MatchAndExplain() method of the Pointee(...) matcher
// should generate an explanation like "which points to ...".
//
// You should override this method when defining a new matcher.
//
@ -118,7 +127,11 @@ class MatcherInterface {
// listener->stream() may be NULL.
virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0;
// Describes this matcher to an ostream.
// Describes this matcher to an ostream. The function should print
// a verb phrase that describes the property a value matching this
// matcher should have. The subject of the verb phrase is the value
// being matched. For example, the DescribeTo() method of the Gt(7)
// matcher prints "is greater than 7".
virtual void DescribeTo(::std::ostream* os) const = 0;
// Describes the negation of this matcher to an ostream. For
@ -2853,7 +2866,7 @@ inline bool Value(const T& value, M matcher) {
// Matches the value against the given matcher and explains the match
// result to listener.
template <typename T, typename M>
inline bool MatchAndExplain(
inline bool ExplainMatchResult(
M matcher, const T& value, MatchResultListener* listener) {
return SafeMatcherCast<const T&>(matcher).MatchAndExplain(value, listener);
}

View File

@ -37,6 +37,7 @@
#include <string.h>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <set>
@ -88,7 +89,7 @@ using testing::Matcher;
using testing::MatcherCast;
using testing::MatcherInterface;
using testing::Matches;
using testing::MatchAndExplain;
using testing::ExplainMatchResult;
using testing::MatchResultListener;
using testing::NanSensitiveDoubleEq;
using testing::NanSensitiveFloatEq;
@ -110,6 +111,7 @@ using testing::Truly;
using testing::TypedEq;
using testing::Value;
using testing::_;
using testing::internal::DummyMatchResultListener;
using testing::internal::FloatingEqMatcher;
using testing::internal::FormatMatcherDescriptionSyntaxError;
using testing::internal::GetParamIndex;
@ -117,6 +119,7 @@ using testing::internal::Interpolation;
using testing::internal::Interpolations;
using testing::internal::JoinAsTuple;
using testing::internal::SkipPrefix;
using testing::internal::StreamMatchResultListener;
using testing::internal::String;
using testing::internal::Strings;
using testing::internal::StringMatchResultListener;
@ -187,6 +190,31 @@ string Explain(const MatcherType& m, const Value& x) {
return ss.str();
}
TEST(MatchResultListenerTest, StreamingWorks) {
StringMatchResultListener listener;
listener << "hi" << 5;
EXPECT_EQ("hi5", listener.str());
// Streaming shouldn't crash when the underlying ostream is NULL.
DummyMatchResultListener dummy;
dummy << "hi" << 5;
}
TEST(MatchResultListenerTest, CanAccessUnderlyingStream) {
EXPECT_TRUE(DummyMatchResultListener().stream() == NULL);
EXPECT_TRUE(StreamMatchResultListener(NULL).stream() == NULL);
EXPECT_EQ(&std::cout, StreamMatchResultListener(&std::cout).stream());
}
TEST(MatchResultListenerTest, IsInterestedWorks) {
EXPECT_TRUE(StringMatchResultListener().IsInterested());
EXPECT_TRUE(StreamMatchResultListener(&std::cout).IsInterested());
EXPECT_FALSE(DummyMatchResultListener().IsInterested());
EXPECT_FALSE(StreamMatchResultListener(NULL).IsInterested());
}
// Makes sure that the MatcherInterface<T> interface doesn't
// change.
class EvenMatcherImpl : public MatcherInterface<int> {
@ -205,7 +233,8 @@ class EvenMatcherImpl : public MatcherInterface<int> {
// two methods is optional.
};
TEST(MatcherInterfaceTest, CanBeImplementedUsingDeprecatedAPI) {
// Makes sure that the MatcherInterface API doesn't change.
TEST(MatcherInterfaceTest, CanBeImplementedUsingPublishedAPI) {
EvenMatcherImpl m;
}
@ -2049,28 +2078,36 @@ TEST(ValueTest, WorksWithMonomorphicMatcher) {
EXPECT_FALSE(Value(1, ref_n));
}
TEST(MatchAndExplainTest, WorksWithPolymorphicMatcher) {
TEST(ExplainMatchResultTest, WorksWithPolymorphicMatcher) {
StringMatchResultListener listener1;
EXPECT_TRUE(MatchAndExplain(PolymorphicIsEven(), 42, &listener1));
EXPECT_TRUE(ExplainMatchResult(PolymorphicIsEven(), 42, &listener1));
EXPECT_EQ("% 2 == 0", listener1.str());
StringMatchResultListener listener2;
EXPECT_FALSE(MatchAndExplain(Ge(42), 1.5, &listener2));
EXPECT_FALSE(ExplainMatchResult(Ge(42), 1.5, &listener2));
EXPECT_EQ("", listener2.str());
}
TEST(MatchAndExplainTest, WorksWithMonomorphicMatcher) {
TEST(ExplainMatchResultTest, WorksWithMonomorphicMatcher) {
const Matcher<int> is_even = PolymorphicIsEven();
StringMatchResultListener listener1;
EXPECT_TRUE(MatchAndExplain(is_even, 42, &listener1));
EXPECT_TRUE(ExplainMatchResult(is_even, 42, &listener1));
EXPECT_EQ("% 2 == 0", listener1.str());
const Matcher<const double&> is_zero = Eq(0);
StringMatchResultListener listener2;
EXPECT_FALSE(MatchAndExplain(is_zero, 1.5, &listener2));
EXPECT_FALSE(ExplainMatchResult(is_zero, 1.5, &listener2));
EXPECT_EQ("", listener2.str());
}
MATCHER_P(Really, inner_matcher, "") {
return ExplainMatchResult(inner_matcher, arg, result_listener);
}
TEST(ExplainMatchResultTest, WorksInsideMATCHER) {
EXPECT_THAT(0, Really(Eq(0)));
}
TEST(AllArgsTest, WorksForTuple) {
EXPECT_THAT(make_tuple(1, 2L), AllArgs(Lt()));
EXPECT_THAT(make_tuple(2L, 1), Not(AllArgs(Lt())));