@@ -19,24 +19,22 @@ use crate::internal::source_location::SourceLocation;
19
19
use crate :: internal:: test_outcome:: TestAssertionFailure ;
20
20
use crate :: matchers:: __internal_unstable_do_not_depend_on_these:: ConjunctionMatcher ;
21
21
use crate :: matchers:: __internal_unstable_do_not_depend_on_these:: DisjunctionMatcher ;
22
+ pub use googletest_macro:: MatcherExt ;
22
23
use std:: fmt:: Debug ;
23
24
24
25
/// An interface for checking an arbitrary condition on a datum.
25
26
///
26
27
/// This trait is automatically implemented for a reference of any type
27
28
/// implementing `Matcher`. This simplifies reusing a matcher in different
28
29
/// assertions.
29
- pub trait Matcher {
30
- /// The type against which this matcher matches.
31
- type ActualT : Debug + ?Sized ;
32
-
30
+ pub trait Matcher < ActualT : Debug + ?Sized > {
33
31
/// Returns whether the condition matches the datum `actual`.
34
32
///
35
33
/// The trait implementation defines what it means to "match". Often the
36
34
/// matching condition is based on data stored in the matcher. For example,
37
35
/// `eq` matches when its stored expected value is equal (in the sense of
38
36
/// the `==` operator) to the value `actual`.
39
- fn matches ( & self , actual : & Self :: ActualT ) -> MatcherResult ;
37
+ fn matches ( & self , actual : & ActualT ) -> MatcherResult ;
40
38
41
39
/// Returns a description of `self` or a negative description if
42
40
/// `matcher_result` is `DoesNotMatch`.
@@ -137,10 +135,22 @@ pub trait Matcher {
137
135
/// .nested(self.expected.explain_match(actual.deref()))
138
136
/// }
139
137
/// ```
140
- fn explain_match ( & self , actual : & Self :: ActualT ) -> Description {
138
+ fn explain_match ( & self , actual : & ActualT ) -> Description {
141
139
format ! ( "which {}" , self . describe( self . matches( actual) ) ) . into ( )
142
140
}
141
+ }
143
142
143
+ /// Trait extension for matchers. It is highly recommended to implement it for
144
+ /// each type implementing `Matcher`.
145
+ // The `and` and `or` functions cannot be part of the `Matcher` traits since it
146
+ // is parametric. Consider that `and` and `or` are part of the `Matcher` trait
147
+ // and `MyMatcher` implements both `Matcher<A>` and `Matcher<B>`.
148
+ // Then `MyMatcher{...}.and(...)` can be either:
149
+ // * `Matcher::<A>::and(MyMatcher{...}, ...)` or
150
+ // * `Matcher::<B>::and(MyMatcher{...}, ...)`.
151
+ // Moving the `and` and `or` functions in a non-generic trait remove this
152
+ // confusion by making `and` and `or` unique for a given type.
153
+ pub trait MatcherExt {
144
154
/// Constructs a matcher that matches both `self` and `right`.
145
155
///
146
156
/// ```
@@ -164,10 +174,7 @@ pub trait Matcher {
164
174
// TODO(b/264518763): Replace the return type with impl Matcher and reduce
165
175
// visibility of ConjunctionMatcher once impl in return position in trait
166
176
// methods is stable.
167
- fn and < Right : Matcher < ActualT = Self :: ActualT > > (
168
- self ,
169
- right : Right ,
170
- ) -> ConjunctionMatcher < Self , Right >
177
+ fn and < Right > ( self , right : Right ) -> ConjunctionMatcher < Self , Right >
171
178
where
172
179
Self : Sized ,
173
180
{
@@ -194,10 +201,7 @@ pub trait Matcher {
194
201
// TODO(b/264518763): Replace the return type with impl Matcher and reduce
195
202
// visibility of DisjunctionMatcher once impl in return position in trait
196
203
// methods is stable.
197
- fn or < Right : Matcher < ActualT = Self :: ActualT > > (
198
- self ,
199
- right : Right ,
200
- ) -> DisjunctionMatcher < Self , Right >
204
+ fn or < Right > ( self , right : Right ) -> DisjunctionMatcher < Self , Right >
201
205
where
202
206
Self : Sized ,
203
207
{
@@ -215,7 +219,7 @@ const PRETTY_PRINT_LENGTH_THRESHOLD: usize = 60;
215
219
/// The parameter `actual_expr` contains the expression which was evaluated to
216
220
/// obtain `actual`.
217
221
pub ( crate ) fn create_assertion_failure < T : Debug + ?Sized > (
218
- matcher : & impl Matcher < ActualT = T > ,
222
+ matcher : & impl Matcher < T > ,
219
223
actual : & T ,
220
224
actual_expr : & ' static str ,
221
225
source_location : SourceLocation ,
@@ -273,18 +277,18 @@ impl MatcherResult {
273
277
}
274
278
}
275
279
276
- impl < M : Matcher > Matcher for & M {
277
- type ActualT = M :: ActualT ;
280
+ impl < M : ?Sized + MatcherExt > MatcherExt for & M { }
278
281
279
- fn matches ( & self , actual : & Self :: ActualT ) -> MatcherResult {
282
+ impl < T : Debug + ?Sized , M : Matcher < T > > Matcher < T > for & M {
283
+ fn matches ( & self , actual : & T ) -> MatcherResult {
280
284
( * self ) . matches ( actual)
281
285
}
282
286
283
287
fn describe ( & self , matcher_result : MatcherResult ) -> Description {
284
288
( * self ) . describe ( matcher_result)
285
289
}
286
290
287
- fn explain_match ( & self , actual : & Self :: ActualT ) -> Description {
291
+ fn explain_match ( & self , actual : & T ) -> Description {
288
292
( * self ) . explain_match ( actual)
289
293
}
290
294
}
0 commit comments