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

Can't set simultaneous expectations of different types on generic method whose generic parameters appear neither in args nor in return type #269

Closed
twz123 opened this issue Apr 8, 2021 · 3 comments
Labels
bug Something isn't working

Comments

@twz123
Copy link

twz123 commented Apr 8, 2021

Related to #236, if generic args are neither referenced in method arguments nor in the return type, it's not possible to set expectations for different types.

I've created a test case that shows the problem. The regular_impl test shows a regular trait implementation and passes. The generic_only test uses a mock!ed trait implementation along with expectations and panics:

thread 'generic_only' panicked at 'called Result::unwrap() on an Err value: TypeMismatch { expected: "[ONLY ON NIGHTLY]", found: "[ONLY ON NIGHTLY]" }'

Following the code:

use mockall::*;

trait Bar {
    const BAZ: &'static str;
}

impl Bar for i32 {
    const BAZ: &'static str = "BAZ/i32";
}

impl Bar for u32 {
    const BAZ: &'static str = "BAZ/u32";
}

trait Foo {
    fn foo<T: Bar + 'static>(&self) -> &'static str;
}

mock! {
    MyStruct {}
    impl Foo for MyStruct {
        fn foo<T: Bar + 'static>(&self) -> &'static str;
    }
}

#[test]
fn generic_only() {
    let mut mock = MockMyStruct::new();
    mock.expect_foo::<i32>().return_const("foo/i32");
    mock.expect_foo::<u32>().return_const("foo/u32");
    assert_eq!("foo/i32", mock.foo::<i32>());
    assert_eq!("foo/u32", mock.foo::<u32>());
}

#[test]
fn regular_impl() {
    struct RegularFoo {}
    impl Foo for RegularFoo {
        fn foo<T: Bar>(&self) -> &'static str {
            T::BAZ
        }
    }

    let regular_foo = RegularFoo {};
    assert_eq!("BAZ/i32", regular_foo.foo::<i32>());
    assert_eq!("BAZ/u32", regular_foo.foo::<u32>());
}
@asomers
Copy link
Owner

asomers commented Apr 8, 2021

Wow! That bug title's a mouthful. First of all, your panic message will be more informative if you build mockall with the nightly crate feature. Secondly, from Mockall's perspective that method isn't really generic at all. So the fact that mock.expect_foo::<T> even compiles indicates a bug. The expectation should be concrete. I'll fix it.

@asomers asomers added the bug Something isn't working label Apr 10, 2021
asomers added a commit that referenced this issue Apr 18, 2021
If the function's generic parameters appeared in neither input nor
return type, the Expectations object would not be parameterized on the
functions generic parameters.  This wasn't really by design; it was
actually an artifact of Mockall's second incarnation, which used a
macro_rules! macro to generate the mock objects.

Fixing the problem is easy.  It's a matter of removing the code that
tried to guess the generic parameters based on the functions arguments
and return types.

Fixes #269
@asomers
Copy link
Owner

asomers commented Apr 18, 2021

@twz123 could you please test your application using Mockall at 274a539 ? And expect_foo isn't concrete after all; it should be generic just the way you wrote it.

@twz123
Copy link
Author

twz123 commented Apr 19, 2021

@asomers Works as expected! Thanks for fixing 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants