mockall icon indicating copy to clipboard operation
mockall copied to clipboard

Initial support for trait-variant

Open lasantosr opened this issue 10 months ago • 4 comments

This PR aims to fix #639

Feel free to update the readme, as English is not my primary language

lasantosr avatar Feb 11 '25 19:02 lasantosr

@asomers I think the nightly is failing because some sort of new lints unrelated to this PR, would you like me to fix those also here?

lasantosr avatar Feb 23 '25 15:02 lasantosr

@asomers I think the nightly is failing because some sort of new lints unrelated to this PR, would you like me to fix those also here?

It's already fixed on master. You just need to rebase.

asomers avatar Feb 23 '25 15:02 asomers

Great! It looks like it's ready now

lasantosr avatar Feb 23 '25 15:02 lasantosr

I think the tests could really benefit from some kind of assertion to check that they actually implement the additional trait. That might be hard to do with Send, but what about something like this?

trait Foo {}
#[automock]
#[trait_variant::make(Foo)]
pub trait Bar {
    ...
}
#[test]
fn some_test_method_name() {
    let mock = MockBar::new();
    let p: Box<dyn Foo> = Box::new(mock);   // Ensures that MockBar implements Foo
    ...
}

Also, with this change, does the #[trait_variant::make(OtherTraitName: Foo)] syntax work?

I'm not that familiar with the codebase to implement all of those changes.

On your first example, automock would not implement Foo trait for MockBar, because it might have any arbitrary number of unrelated methods, but it could be manually implemented:

trait Foo {}
#[automock]
#[trait_variant::make(Foo)]
pub trait Bar {
    ...
}
impl Foo for MockBar {}

The most common use case is to mark your trait (and async method futures) Send, and mocks are already Send so that's covered.

As for the second example, the syntax already works, but we would be mocking the initial trait only (Bar), not the other variant (OtherTraitName). With that syntax you're actually defining two different traits.

The main goal of this PR is to have feature parity with async_trait, other improvements could be added later.

As mentioend on #639 the async_trait annotation can be located before or after the automock annotation, and that means you need to return the actual pinned future or just the future's output on the mocks expectations.

With this PR we can do the same for trait_variant, so that the migration is painless.

lasantosr avatar Feb 23 '25 16:02 lasantosr

@asomers can this PR be merged as is to allow initial basic support for trait_variant?

Other improvements can be added later, when needed

lasantosr avatar Mar 22 '25 14:03 lasantosr

We need to decide what do do about the #[trait_variant::make(IntFactory: Send)] syntax. It might just work. Have you tried it?

@asomers It was already working but it mocks the original trait (not the variant)

On this example, #[automock] mocks LocalFoo, generating MockLocalFoo:

#[automock]
#[trait_variant::make(Foo: Send)]
pub trait LocalFoo {
    async fn foo(&self) -> u32;
    async fn bar() -> u32;
}

I've extended automock to allow mocking the variant as well (I've included examples and updated automock documentation)

On this example, #[automock(target = Foo)] mocks Foo, generating MockFoo:

#[automock(target = Foo)]
#[trait_variant::make(Foo: Send)]
pub trait LocalFoo {
    async fn foo(&self) -> u32;
    async fn bar() -> u32;
}

Note: trait-variant automatically generates a blanket impl for any type implementing Foo to also implement LocalFoo, so the resulting MockFoo can be used anywhere expecting both LocalFoo or Foo

All of the other comments have been resolved, except for the static assertion which is not required. If you still want me to include it let me know.

lasantosr avatar Apr 04 '25 17:04 lasantosr

@asomers It should be ready now! Thanks for the review

lasantosr avatar Apr 26 '25 15:04 lasantosr

@asomers There's already a changelog entry, let me know if you would like another sentence.

lasantosr avatar Apr 29 '25 06:04 lasantosr

@asomers There's already a changelog entry, let me know if you would like another sentence.

Of course you did. But yesterday I was only viewing "changes since your last review" so I didn't see it. My bad.

asomers avatar Apr 29 '25 13:04 asomers