Skip to content

Commit

Permalink
Fix mocking trait methods whose return values have lifetime parameters
Browse files Browse the repository at this point in the history
Must staticize return values for trait methods with generic arguments,
as long as the mock object itself is not generic.

This was a regression introduced by PR #274, and released in v0.10.0. It
only affects trait methods, not struct methods.

Fixes #298
  • Loading branch information
asomers committed Jul 2, 2021
1 parent d8e2ec3 commit 6bbac62
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [ Unreleased ] - ReleaseDate

## Fixed

- Fix mocking trait methods whose return values have lifetime parameters, a
regression sine v0.10.0.
([#301](https://github.com/asomers/mockall/pull/301))

## [ 0.10.0 ] - 2021-06-27

### Added
Expand Down
48 changes: 48 additions & 0 deletions mockall/tests/mock_generic_method_returning_nonstatic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ use mockall::*;
#[derive(Clone)]
struct X<'a>(&'a u32);

trait Bong {
fn trait_foo<'a>(&self) -> X<'a>;
fn trait_baz<'a>(&self) -> &X<'a>;
}

mock! {
Thing {
fn foo<'a>(&self) -> X<'a>;
Expand All @@ -29,6 +34,11 @@ mock! {
// std::any::Any, which means they must be 'static.
//fn bean<'a, T: 'static>(&self, t: T) -> X<'a>;
}
// The same types of methods should work if they are Trait methods.
impl Bong for Thing {
fn trait_foo<'a>(&self) -> X<'a>;
fn trait_baz<'a>(&self) -> &X<'a>;
}
}

#[test]
Expand Down Expand Up @@ -67,3 +77,41 @@ fn return_nonstatic() {

assert_eq!(42u32, *thing.foo().0);
}

mod trait_methods {
use super::*;

#[test]
fn return_static() {
const D: u32 = 42;
let x = X(&D);
let mut thing = MockThing::new();
thing.expect_trait_foo()
.return_const(x);

assert_eq!(42u32, *thing.trait_foo().0);
}

#[test]
fn return_static_ref() {
const D: u32 = 42;
let x = X(&D);
let mut thing = MockThing::new();
thing.expect_trait_baz()
.return_const(x);

assert_eq!(42u32, *(*thing.trait_baz()).0);
}

#[test]
fn return_nonstatic() {
let d = 42u32;
let x = X(&d);
let xstatic: X<'static> = unsafe{ std::mem::transmute(x) };
let mut thing = MockThing::new();
thing.expect_trait_foo()
.returning(move || xstatic.clone());

assert_eq!(42u32, *thing.trait_foo().0);
}
}
4 changes: 2 additions & 2 deletions mockall_derive/src/mock_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,10 +619,10 @@ impl MockFunction {
-> impl ToTokens
{
let inner_mod_ident = self.inner_mod_ident();
if let Some(sa) = self_args {
if let Some(PathArguments::AngleBracketed(abga)) = self_args {
assert!(!self.is_method_generic(),
"specific impls with generic methods are TODO");
quote!(#inner_mod_ident::Expectation #sa)
quote!(#inner_mod_ident::Expectation #abga)
} else {
// staticize any lifetimes. This is necessary for methods that
// return non-static types, because the Expectation itself must be
Expand Down

0 comments on commit 6bbac62

Please sign in to comment.