Skip to content

Commit 4b67c37

Browse files
committed
Make ActualT in Matcher a generic type parameter.
1 parent 72cf9b2 commit 4b67c37

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+539
-700
lines changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,7 @@ struct MyEqMatcher<T> {
156156
expected: T,
157157
}
158158

159-
impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
160-
type ActualT = T;
161-
159+
impl<T: PartialEq + Debug> Matcher<T> for MyEqMatcher<T> {
162160
fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
163161
(self.expected == *actual).into()
164162
}
@@ -179,7 +177,7 @@ impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
179177
It is recommended to expose a function which constructs the matcher:
180178

181179
```rust
182-
pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<ActualT = T> {
180+
pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<T> {
183181
MyEqMatcher { expected }
184182
}
185183
```

googletest/crate_docs.md

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -206,20 +206,19 @@ The following matchers are provided in GoogleTest Rust:
206206

207207
One can extend the library by writing additional matchers. To do so, create
208208
a struct holding the matcher's data and have it implement the trait
209-
[`Matcher`]:
209+
[`Matcher`] (and optionally the [`MatcherExt`] trait):
210210

211211
```no_run
212-
use googletest::{description::Description, matcher::{Matcher, MatcherResult}};
212+
use googletest::{description::Description, matcher::{Matcher, MatcherExt, MatcherResult}};
213213
use std::fmt::Debug;
214214
215+
#[derive(MatcherExt)]
215216
struct MyEqMatcher<T> {
216217
expected: T,
217218
}
218219
219-
impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
220-
type ActualT = T;
221-
222-
fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
220+
impl<T: PartialEq + Debug> Matcher<T> for MyEqMatcher<T> {
221+
fn matches(&self, actual: &T) -> MatcherResult {
223222
if self.expected == *actual {
224223
MatcherResult::Match
225224
} else {
@@ -243,17 +242,15 @@ impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
243242
It is recommended to expose a function which constructs the matcher:
244243

245244
```no_run
246-
# use googletest::{description::Description, matcher::{Matcher, MatcherResult}};
245+
# use googletest::{description::Description, matcher::{Matcher, MatcherExt, MatcherResult}};
247246
# use std::fmt::Debug;
248-
#
247+
# #[derive(MatcherExt)]
249248
# struct MyEqMatcher<T> {
250249
# expected: T,
251250
# }
252251
#
253-
# impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
254-
# type ActualT = T;
255-
#
256-
# fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
252+
# impl<T: PartialEq + Debug> Matcher<T> for MyEqMatcher<T> {
253+
# fn matches(&self, actual: &T) -> MatcherResult {
257254
# if self.expected == *actual {
258255
# MatcherResult::Match
259256
# } else {
@@ -273,7 +270,7 @@ impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
273270
# }
274271
# }
275272
#
276-
pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<ActualT = T> {
273+
pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<T> {
277274
MyEqMatcher { expected }
278275
}
279276
```
@@ -282,17 +279,15 @@ impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
282279

283280
```
284281
# use googletest::prelude::*;
285-
# use googletest::{description::Description, matcher::{Matcher, MatcherResult}};
282+
# use googletest::{description::Description, matcher::{Matcher, MatcherExt, MatcherResult}};
286283
# use std::fmt::Debug;
287-
#
284+
# #[derive(MatcherExt)]
288285
# struct MyEqMatcher<T> {
289286
# expected: T,
290287
# }
291288
#
292-
# impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
293-
# type ActualT = T;
294-
#
295-
# fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
289+
# impl<T: PartialEq + Debug> Matcher<T> for MyEqMatcher<T> {
290+
# fn matches(&self, actual: &T) -> MatcherResult {
296291
# if self.expected == *actual {
297292
# MatcherResult::Match
298293
# } else {
@@ -312,7 +307,7 @@ impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
312307
# }
313308
# }
314309
#
315-
# pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<ActualT = T> {
310+
# pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<T> {
316311
# MyEqMatcher { expected }
317312
# }
318313
# /* The attribute macro would prevent the function from being compiled in a doctest.
@@ -493,3 +488,4 @@ through the `?` operator as the example above shows.
493488
[`and_log_failure()`]: GoogleTestSupport::and_log_failure
494489
[`into_test_result()`]: IntoTestResult::into_test_result
495490
[`Matcher`]: matcher::Matcher
491+
[`MatcherExt`]: matcher::MatcherExt

googletest/src/assertions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ pub mod internal {
499499
#[must_use = "The assertion result must be evaluated to affect the test result."]
500500
pub fn check_matcher<T: Debug + ?Sized>(
501501
actual: &T,
502-
expected: impl Matcher<ActualT = T>,
502+
expected: impl Matcher<T>,
503503
actual_expr: &'static str,
504504
source_location: SourceLocation,
505505
) -> Result<(), TestAssertionFailure> {

googletest/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub mod matchers;
4242
/// }
4343
/// ```
4444
pub mod prelude {
45-
pub use super::matcher::Matcher;
45+
pub use super::matcher::{Matcher, MatcherExt};
4646
pub use super::matchers::*;
4747
pub use super::verify_current_test_outcome;
4848
pub use super::GoogleTestSupport;

googletest/src/matcher.rs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,22 @@ use crate::internal::source_location::SourceLocation;
1919
use crate::internal::test_outcome::TestAssertionFailure;
2020
use crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher;
2121
use crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher;
22+
pub use googletest_macro::MatcherExt;
2223
use std::fmt::Debug;
2324

2425
/// An interface for checking an arbitrary condition on a datum.
2526
///
2627
/// This trait is automatically implemented for a reference of any type
2728
/// implementing `Matcher`. This simplifies reusing a matcher in different
2829
/// 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> {
3331
/// Returns whether the condition matches the datum `actual`.
3432
///
3533
/// The trait implementation defines what it means to "match". Often the
3634
/// matching condition is based on data stored in the matcher. For example,
3735
/// `eq` matches when its stored expected value is equal (in the sense of
3836
/// the `==` operator) to the value `actual`.
39-
fn matches(&self, actual: &Self::ActualT) -> MatcherResult;
37+
fn matches(&self, actual: &ActualT) -> MatcherResult;
4038

4139
/// Returns a description of `self` or a negative description if
4240
/// `matcher_result` is `DoesNotMatch`.
@@ -137,10 +135,22 @@ pub trait Matcher {
137135
/// .nested(self.expected.explain_match(actual.deref()))
138136
/// }
139137
/// ```
140-
fn explain_match(&self, actual: &Self::ActualT) -> Description {
138+
fn explain_match(&self, actual: &ActualT) -> Description {
141139
format!("which {}", self.describe(self.matches(actual))).into()
142140
}
141+
}
143142

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 {
144154
/// Constructs a matcher that matches both `self` and `right`.
145155
///
146156
/// ```
@@ -164,10 +174,7 @@ pub trait Matcher {
164174
// TODO(b/264518763): Replace the return type with impl Matcher and reduce
165175
// visibility of ConjunctionMatcher once impl in return position in trait
166176
// 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>
171178
where
172179
Self: Sized,
173180
{
@@ -194,10 +201,7 @@ pub trait Matcher {
194201
// TODO(b/264518763): Replace the return type with impl Matcher and reduce
195202
// visibility of DisjunctionMatcher once impl in return position in trait
196203
// 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>
201205
where
202206
Self: Sized,
203207
{
@@ -215,7 +219,7 @@ const PRETTY_PRINT_LENGTH_THRESHOLD: usize = 60;
215219
/// The parameter `actual_expr` contains the expression which was evaluated to
216220
/// obtain `actual`.
217221
pub(crate) fn create_assertion_failure<T: Debug + ?Sized>(
218-
matcher: &impl Matcher<ActualT = T>,
222+
matcher: &impl Matcher<T>,
219223
actual: &T,
220224
actual_expr: &'static str,
221225
source_location: SourceLocation,
@@ -273,18 +277,18 @@ impl MatcherResult {
273277
}
274278
}
275279

276-
impl<M: Matcher> Matcher for &M {
277-
type ActualT = M::ActualT;
280+
impl<M: ?Sized + MatcherExt> MatcherExt for &M {}
278281

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 {
280284
(*self).matches(actual)
281285
}
282286

283287
fn describe(&self, matcher_result: MatcherResult) -> Description {
284288
(*self).describe(matcher_result)
285289
}
286290

287-
fn explain_match(&self, actual: &Self::ActualT) -> Description {
291+
fn explain_match(&self, actual: &T) -> Description {
288292
(*self).explain_match(actual)
289293
}
290294
}

googletest/src/matchers/all_matcher.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
/// ```
3939
///
4040
/// Using this macro is equivalent to using the
41-
/// [`and`][crate::matcher::Matcher::and] method:
41+
/// [`and`][crate::matcher::MatcherExt::and] method:
4242
///
4343
/// ```
4444
/// # use googletest::prelude::*;
@@ -78,12 +78,12 @@ mod tests {
7878

7979
#[test]
8080
fn description_shows_more_than_one_matcher() -> Result<()> {
81-
let first_matcher: StrMatcher<String, _> = starts_with("A");
81+
let first_matcher = starts_with("A");
8282
let second_matcher = ends_with("string");
8383
let matcher = all!(first_matcher, second_matcher);
8484

8585
verify_that!(
86-
matcher.describe(MatcherResult::Match),
86+
Matcher::<String>::describe(&matcher, MatcherResult::Match),
8787
displays_as(eq(indoc!(
8888
"
8989
has all the following properties:
@@ -95,19 +95,19 @@ mod tests {
9595

9696
#[test]
9797
fn description_shows_one_matcher_directly() -> Result<()> {
98-
let first_matcher: StrMatcher<String, _> = starts_with("A");
98+
let first_matcher = starts_with("A");
9999
let matcher = all!(first_matcher);
100100

101101
verify_that!(
102-
matcher.describe(MatcherResult::Match),
102+
Matcher::<String>::describe(&matcher, MatcherResult::Match),
103103
displays_as(eq("starts with prefix \"A\""))
104104
)
105105
}
106106

107107
#[test]
108108
fn mismatch_description_shows_which_matcher_failed_if_more_than_one_constituent() -> Result<()>
109109
{
110-
let first_matcher: StrMatcher<str, _> = starts_with("Another");
110+
let first_matcher = starts_with("Another");
111111
let second_matcher = ends_with("string");
112112
let matcher = all!(first_matcher, second_matcher);
113113

googletest/src/matchers/any_matcher.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/// ```
4141
///
4242
/// Using this macro is equivalent to using the
43-
/// [`or`][crate::matcher::Matcher::or] method:
43+
/// [`or`][crate::matcher::MatcherExt::or] method:
4444
///
4545
/// ```
4646
/// # use googletest::prelude::*;
@@ -80,12 +80,12 @@ mod tests {
8080

8181
#[test]
8282
fn description_shows_more_than_one_matcher() -> Result<()> {
83-
let first_matcher: StrMatcher<String, &str> = starts_with("A");
83+
let first_matcher = starts_with("A");
8484
let second_matcher = ends_with("string");
8585
let matcher = any!(first_matcher, second_matcher);
8686

8787
verify_that!(
88-
matcher.describe(MatcherResult::Match),
88+
Matcher::<String>::describe(&matcher, MatcherResult::Match),
8989
displays_as(eq(indoc!(
9090
"
9191
has at least one of the following properties:
@@ -97,11 +97,11 @@ mod tests {
9797

9898
#[test]
9999
fn description_shows_one_matcher_directly() -> Result<()> {
100-
let first_matcher: StrMatcher<String, &str> = starts_with("A");
100+
let first_matcher = starts_with("A");
101101
let matcher = any!(first_matcher);
102102

103103
verify_that!(
104-
matcher.describe(MatcherResult::Match),
104+
Matcher::<String>::describe(&matcher, MatcherResult::Match),
105105
displays_as(eq("starts with prefix \"A\""))
106106
)
107107
}

googletest/src/matchers/anything_matcher.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
use crate::{
1616
description::Description,
17-
matcher::{Matcher, MatcherResult},
17+
matcher::{Matcher, MatcherExt, MatcherResult},
1818
};
19-
use std::{fmt::Debug, marker::PhantomData};
19+
use std::fmt::Debug;
2020

2121
/// Matches anything. This matcher always succeeds.
2222
///
@@ -32,15 +32,14 @@ use std::{fmt::Debug, marker::PhantomData};
3232
/// # }
3333
/// # should_pass().unwrap();
3434
/// ```
35-
pub fn anything<T: Debug + ?Sized>() -> impl Matcher<ActualT = T> {
36-
Anything::<T>(Default::default())
35+
pub fn anything() -> Anything {
36+
Anything
3737
}
3838

39-
struct Anything<T: ?Sized>(PhantomData<T>);
40-
41-
impl<T: Debug + ?Sized> Matcher for Anything<T> {
42-
type ActualT = T;
39+
#[derive(MatcherExt)]
40+
pub struct Anything;
4341

42+
impl<T: Debug + ?Sized> Matcher<T> for Anything {
4443
fn matches(&self, _: &T) -> MatcherResult {
4544
MatcherResult::Match
4645
}

0 commit comments

Comments
 (0)