Closed
Description
This is something I've dreamed of having in the C++ googletest library. The difference is in Rust this seems possible!
#[googletest::StructMatcher]
struct MyType {
field_1: i32,
field_2: String,
...
}
This attribute macro would generate something akin to:
#[cfg(test)]
struct MyTypeStructMatcher {
field_1: Option<Box<dyn Matcher<ActualT = i32>>>,
field_2: Option<Box<dyn Matcher<ActualT = String>>>,
...
}
#[cfg(test)]
impl googletest::matcher::Matcher for MyTypeStructMatcher {
type ActualT = MyType;
fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
if let Some(field_1) = &self.field_1 {
if field_1.matches(&actual.field_1).is_no_match() {
return MatcherResult::NoMatch;
}
}
...
}
}
(A supporting enum in googletest code to make it easier to construct the field matcher)
pub enum StructFieldMatcher<ActualT> {
None,
Matcher(Box<dyn Matcher<ActualT = ActualT>>)
}
impl<M: Matcher + 'static> From<M> for StructFieldMatcher<<M as Matcher>::ActualT> {
fn from(value: M) -> Self {
Self::Matcher(Box::new(value))
}
}
This enables usage similar to the following:
#[googletest::test]
fn my_test() {
let value = MyType {
field_1: 3,
field_2: "helloworld".into(),
...
};
expect_that!(value, MyTypeStructMatcher{
field_1: lt(3).into(),
field_2: contains_substring("llow").into(),
});
}
Disadvantages
We need to make googletest
(or some related crate) a public dependency of crates. Thankfully the #[cfg(test)]
attribute should prune the code gen for the entire implementation, but we do still pay the cost of the procedural macro.
Metadata
Metadata
Assignees
Labels
No labels