From 4902ea2d7c6faed89b6facee00baa34bb108fc0d Mon Sep 17 00:00:00 2001 From: Zhanyong Wan Date: Tue, 11 Mar 2025 12:03:38 -0700 Subject: [PATCH] Clarify the polymorphic matcher concept and explain how to define a composite matcher. Many gtest users aren't aware that a polymorphic matcher is not actually a `testing::Matcher<>` and thus doesn't know how to describe itself. Clarify this. Also adds a recipe on how to define a composite matcher. In particular, explain how the composite matcher can describe itself in terms of the description(s) of its sub-matcher(s). PiperOrigin-RevId: 735840759 Change-Id: I26cff6179349aa739fc7fdd528a2f5308d18c189 --- docs/gmock_cook_book.md | 45 +++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/docs/gmock_cook_book.md b/docs/gmock_cook_book.md index 633dbc37..9e59b4cf 100644 --- a/docs/gmock_cook_book.md +++ b/docs/gmock_cook_book.md @@ -3567,10 +3567,15 @@ just based on the number of parameters). ### Writing New Monomorphic Matchers -A matcher of argument type `T` implements the matcher interface for `T` and does -two things: it tests whether a value of type `T` matches the matcher, and can -describe what kind of values it matches. The latter ability is used for -generating readable error messages when expectations are violated. +A matcher of type `testing::Matcher` implements the matcher interface for `T` +and does two things: it tests whether a value of type `T` matches the matcher, +and can describe what kind of values it matches. The latter ability is used for +generating readable error messages when expectations are violated. Some matchers +can even explain why it matches or doesn't match a certain value, which can be +helpful when the reason isn't obvious. + +Because a matcher of type `testing::Matcher` for a particular type `T` can +only be used to match a value of type `T`, we call it "monomorphic." A matcher of `T` must declare a typedef like: @@ -3662,8 +3667,16 @@ instead of `std::ostream*`. ### Writing New Polymorphic Matchers -Expanding what we learned above to *polymorphic* matchers is now just as simple -as adding templates in the right place. +Unlike a monomorphic matcher, which can only be used to match a value of a +particular type, a *polymorphic* matcher is one that can be used to match values +of multiple types. For example, `Eq(5)` is a polymorhpic matcher as it can be +used to match an `int`, a `double`, a `float`, and so on. You should think of a +polymorphic matcher as a *matcher factory* as opposed to a +`testing::Matcher` - itself is not an actual matcher, but can be +implicitly converted to a `testing::Matcher` depending on the context. + +Expanding what we learned above to polymorphic matchers is now as simple as +adding templates in the right place. ```cpp @@ -3789,6 +3802,26 @@ virtual. Like in a monomorphic matcher, you may explain the match result by streaming additional information to the `listener` argument in `MatchAndExplain()`. +### Implementing Composite Matchers {#CompositeMatchers} + +Sometimes we want to define a matcher that takes other matchers as parameters. +For example, `DistanceFrom(target, m)` is a polymorphic matcher that takes a +matcher `m` as a parameter. It tests that the distance from `target` to the +value being matched satisfies sub-matcher `m`. + +If you are implementing such a composite matcher, you'll need to generate the +description of the matcher based on the description(s) of its sub-matcher(s). +You can see the implementation of `DistanceFrom()` in +`googlemock/include/gmock/gmock-matchers.h` for an example. In particular, pay +attention to `DistanceFromMatcherImpl`. Notice that it stores the sub-matcher as +a `const Matcher distance_matcher_` instead of a polymorphic +matcher - this allows it to call `distance_matcher_.DescribeTo(os)` to describe +the sub-matcher. If the sub-matcher is stored as a polymorphic matcher instead, +it would not be possible to get its description as in general polymorphic +matchers don't know how to describe themselves - they are matcher factories +instead of actual matchers; only after being converted to `Matcher` +can they be described. + ### Writing New Cardinalities A cardinality is used in `Times()` to tell gMock how many times you expect a