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

Allow mocking non-'static structs #4

Closed
asomers opened this issue Jul 26, 2019 · 3 comments · Fixed by #114
Closed

Allow mocking non-'static structs #4

asomers opened this issue Jul 26, 2019 · 3 comments · Fixed by #114
Labels
enhancement New feature or request

Comments

@asomers
Copy link
Owner

asomers commented Jul 26, 2019

Mockall currently can't mock a struct or trait with a lifetime parameter. So something like this doesn't work:

#[allow(unused)]
struct GenericStruct<'a, T, V> {
    t: T,
    v: &'a V
}
#[automock]
impl<'a, T, V> GenericStruct<'a, T, V> {
    #[allow(unused)]
    fn foo(&self, _x: u32) -> i64 {
        42
    }
}

#[test]
fn returning() {
    let mut mock = MockGenericStruct::<'static, u8, i8>::new();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}
@asomers asomers added the enhancement New feature or request label Jul 26, 2019
@michaelmarconi
Copy link

michaelmarconi commented Sep 2, 2019

I think I've just run into this:

        fn create_foo<'insert>(&self, foo: &'insert NewFoo<'insert>) {
            diesel::insert_into(foo::table)
                .values(foo)
                .execute(self.connection.as_ref().unwrap())
                .expect("Failed to insert new foo");
        }

Yields: help: message: Mockall does not yet support this argument type in this position. More information may be available when mockall is built with the "nightly" feature.

I'm not using nightly.

I'm using the Diesel ORM, so require the lifetimes to cope with string insertion on a struct like this:

#[derive(Insertable)]
#[table_name = "foos"]
pub struct NewFoo<'insert> {
    pub reference: &'insert str,
}

I've got a RepositoryTrait that I'm using to create an interface to the database and for mocking with automock, with the create_foo method on it.

Can you suggest a workaround in this situation?

@asomers
Copy link
Owner Author

asomers commented Sep 2, 2019

Actually, you're running into a different problem. This issue concerns structs with lifetime parameters. Your problem is with a method with a lifetime parameter. A full solution would be different than for the struct case.

Situations like this can usually be dealt with eliminating the lifetimes when compiling in test mode. You can try something like this:

#[automock]
trait RepositoryTrait {
    #[cfg(not(test))]
    fn create_foo<'insert>(&self, foo: &'insert NewFoo<'insert>);
    #[cfg(test)]
    fn create_foo(&self, foo: &'static NewFoo<'static>);
}

Of course, that obviously imposes a new restriction on how you write your tests. Another possible workaround would be to redefine NewFoo in test mode to eliminate the lifetime parameter.

@michaelmarconi
Copy link

Thanks @asomers, that's done the trick for me!

@asomers asomers changed the title Allow lifetime parameters for generic structs Allow mocking non-'static structs Nov 16, 2019
asomers added a commit that referenced this issue Mar 29, 2020
Constructor methods are not yet supported.

Fixes #4

The gory details:
* Generics of mock structs should not include lifetimes
* deselfify before split lifetimes
* Include rlifetimes in some impl blocks
* Include some missing <> in an intermediate Generics object
* Fix deselfify with lifetimes
* Handle apparently unused lifetimes in  split_lifetimes
* Fix determination of whether a method is generic in method_types.  There was
  some leftover logic from back when all methods of generic structs were
  treated as generic methods.
* Remove lifetimes from Context objects
asomers added a commit that referenced this issue Mar 29, 2020
Constructor methods are not yet supported.

Fixes #4

The gory details:
* Generics of mock structs should not include lifetimes
* deselfify before split lifetimes
* Include rlifetimes in some impl blocks
* Include some missing <> in an intermediate Generics object
* Fix deselfify with lifetimes
* Handle apparently unused lifetimes in  split_lifetimes
* Fix determination of whether a method is generic in method_types.  There was
  some leftover logic from back when all methods of generic structs were
  treated as generic methods.
* Remove lifetimes from Context objects
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

Successfully merging a pull request may close this issue.

2 participants