Skip to content

Commit

Permalink
Add a 3-arg overload for ResultOf() matcher that takes a description …
Browse files Browse the repository at this point in the history
…string for better error messages.

PiperOrigin-RevId: 427598749
Change-Id: I8c7a5d7b2dde017641534f1c7eed8dd56c33e845
  • Loading branch information
Abseil Team authored and copybara-github committed Feb 10, 2022
1 parent 06519ce commit 0e40217
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 6 deletions.
1 change: 1 addition & 0 deletions docs/reference/matchers.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ messages, you can use:
| Matcher | Description |
| :--------------- | :------------------------------------------------ |
| `ResultOf(f, m)` | `f(argument)` matches matcher `m`, where `f` is a function or functor. |
| `ResultOf(result_description, f, m)` | The same as the two-parameter version, but provides a better error message.

## Pointer Matchers

Expand Down
43 changes: 37 additions & 6 deletions googlemock/include/gmock/gmock-matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2206,13 +2206,21 @@ template <typename Callable, typename InnerMatcher>
class ResultOfMatcher {
public:
ResultOfMatcher(Callable callable, InnerMatcher matcher)
: callable_(std::move(callable)), matcher_(std::move(matcher)) {
: ResultOfMatcher(/*result_description=*/"", std::move(callable),
std::move(matcher)) {}

ResultOfMatcher(const std::string& result_description, Callable callable,
InnerMatcher matcher)
: result_description_(result_description),
callable_(std::move(callable)),
matcher_(std::move(matcher)) {
CallableTraits<Callable>::CheckIsValid(callable_);
}

template <typename T>
operator Matcher<T>() const {
return Matcher<T>(new Impl<const T&>(callable_, matcher_));
return Matcher<T>(
new Impl<const T&>(result_description_, callable_, matcher_));
}

private:
Expand All @@ -2225,16 +2233,27 @@ class ResultOfMatcher {

public:
template <typename M>
Impl(const CallableStorageType& callable, const M& matcher)
: callable_(callable), matcher_(MatcherCast<ResultType>(matcher)) {}
Impl(const std::string& result_description,
const CallableStorageType& callable, const M& matcher)
: result_description_(result_description),
callable_(callable),
matcher_(MatcherCast<ResultType>(matcher)) {}

void DescribeTo(::std::ostream* os) const override {
*os << "is mapped by the given callable to a value that ";
if (result_description_.empty()) {
*os << "is mapped by the given callable to a value that ";
} else {
*os << "whose " << result_description_ << " ";
}
matcher_.DescribeTo(os);
}

void DescribeNegationTo(::std::ostream* os) const override {
*os << "is mapped by the given callable to a value that ";
if (result_description_.empty()) {
*os << "is mapped by the given callable to a value that ";
} else {
*os << "whose " << result_description_ << " ";
}
matcher_.DescribeNegationTo(os);
}

Expand All @@ -2250,6 +2269,7 @@ class ResultOfMatcher {
}

private:
const std::string result_description_;
// Functors often define operator() as non-const method even though
// they are actually stateless. But we need to use them even when
// 'this' is a const pointer. It's the user's responsibility not to
Expand All @@ -2259,6 +2279,7 @@ class ResultOfMatcher {
const Matcher<ResultType> matcher_;
}; // class Impl

const std::string result_description_;
const CallableStorageType callable_;
const InnerMatcher matcher_;
};
Expand Down Expand Up @@ -4422,6 +4443,16 @@ internal::ResultOfMatcher<Callable, InnerMatcher> ResultOf(
std::move(matcher));
}

// Same as ResultOf() above, but also takes a description of the `callable`
// result to provide better error messages.
template <typename Callable, typename InnerMatcher>
internal::ResultOfMatcher<Callable, InnerMatcher> ResultOf(
const std::string& result_description, Callable callable,
InnerMatcher matcher) {
return internal::ResultOfMatcher<Callable, InnerMatcher>(
result_description, std::move(callable), std::move(matcher));
}

// String matchers.

// Matches a string equal to str.
Expand Down
10 changes: 10 additions & 0 deletions googlemock/test/gmock-matchers_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4643,6 +4643,16 @@ TEST(ResultOfTest, CanDescribeItself) {
"isn't equal to \"foo\"", DescribeNegation(matcher));
}

// Tests that ResultOf() can describe itself when provided a result description.
TEST(ResultOfTest, CanDescribeItselfWithResultDescription) {
Matcher<int> matcher =
ResultOf("string conversion", &IntToStringFunction, StrEq("foo"));

EXPECT_EQ("whose string conversion is equal to \"foo\"", Describe(matcher));
EXPECT_EQ("whose string conversion isn't equal to \"foo\"",
DescribeNegation(matcher));
}

// Tests that ResultOf() can explain the match result.
int IntFunction(int input) { return input == 42 ? 80 : 90; }

Expand Down

0 comments on commit 0e40217

Please sign in to comment.