From 6bbac6276939153df7a0b33e2e589bcf26493946 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 29 Jun 2021 20:19:45 -0600 Subject: [PATCH] Fix mocking trait methods whose return values have lifetime parameters 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 --- CHANGELOG.md | 8 ++++ ...mock_generic_method_returning_nonstatic.rs | 48 +++++++++++++++++++ mockall_derive/src/mock_function.rs | 4 +- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a664b660..8c371eba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/mockall/tests/mock_generic_method_returning_nonstatic.rs b/mockall/tests/mock_generic_method_returning_nonstatic.rs index 865e2862..5fc5fe3f 100644 --- a/mockall/tests/mock_generic_method_returning_nonstatic.rs +++ b/mockall/tests/mock_generic_method_returning_nonstatic.rs @@ -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>; @@ -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] @@ -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); + } +} diff --git a/mockall_derive/src/mock_function.rs b/mockall_derive/src/mock_function.rs index 25755429..849ddbb2 100644 --- a/mockall_derive/src/mock_function.rs +++ b/mockall_derive/src/mock_function.rs @@ -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