Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mock the same generic trait twice on a concrete struct #342

Open
glueball opened this issue Oct 9, 2021 · 2 comments
Open

Mock the same generic trait twice on a concrete struct #342

glueball opened this issue Oct 9, 2021 · 2 comments
Labels
enhancement New feature or request

Comments

@glueball
Copy link

glueball commented Oct 9, 2021

First, many thanks for mockall. It's an awesome crate, it has become central to my (and my teams') development experience in Rust.

Not sure if this is possible to do, and I've missed how to do it in the documentation. If a trait has generic parameters, Rust allows a struct (or an enum) to implement multiple times for different parameter objects. How can I mock such an object?

Consider this example:

use mockall::mock;

trait MyTrait<T> {
    fn value(&self) -> T;
}

struct MyStruct {
    integer: i32,
    float: f32,
}

impl MyTrait<i32> for MyStruct {
    fn value(&self) -> i32 {
        self.integer
    }
}

impl MyTrait<f32> for MyStruct {
    fn value(&self) -> f32 {
        self.float
    }
}


mock! {
    MyStruct {}

    impl MyTrait<i32> for MyStruct {
        fn value(&self) -> i32;
    }

    impl MyTrait<f32> for MyStruct {
        fn value(&self) -> f32;
    }
}

It gives the following error:

error[E0592]: duplicate definitions with name 'expect_value'

This example is derived from my use case: a "Context" object that acts as a centralized container/factory for several entities in my project. It implements a trait of the form Builder<E: Entity> for every of such entities. But I'm assuming there will be much less exotic use cases: think, for example, the From<T> standard trait.

Is there some way to mock an object like this? If there is, could you please point me to it? If not, looks like that an (opt-in) way of manually specifying the name of the "expect_" method would be enough:

mock! {
    MyStruct {}

    impl MyTrait<i32> for MyStruct {
       #[mockall(method=expect_value_integer)]
        fn value(&self) -> i32;
    }

    impl MyTrait<f32> for MyStruct {
       #[mockall(method=expect_value_float)]
        fn value(&self) -> f32;
    }
}
@glueball
Copy link
Author

glueball commented Oct 9, 2021

Note: I'm working around this issue by adding "fake" inherent methods to the mock and then implementing the traits manually

mock! {
    MyStruct {
        fn value_integer(&self) -> i32;
        fn value_float(&self) -> f32;
    }
}

impl MyTrait<i32> for MockMyStruct {
    fn value(&self) -> i32 {
        self.value_integer()
    }
}

impl MyTrait<f32> for MockMyStruct {
    fn value(&self) -> f32 {
        self.value_float()
    }
}

However, it'd be great if there was a way (and less verbose) way of doing this.

@asomers
Copy link
Owner

asomers commented Oct 9, 2021

Currently there's no way to do it if MyStruct is concrete. If MyStruct is generic, however, then it works and requires no special syntax. Ideally Mockall could create a generic MockMyStruct::expect<T> method, where T is implemented for f32 and i32, but Rust doesn't allow such a thing. For now your workaround is the best possible.

@asomers asomers added the enhancement New feature or request label Oct 9, 2021
@asomers asomers changed the title Mock an object that implements the same (generic) trait more than once Mock the same generic trait twice on a concrete struct Oct 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants