From 96ee7e806b0347483215c80179ab4da6b286baf0 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 21 Dec 2020 17:48:10 -0700 Subject: [PATCH] Fix an issue with generic methods whose only generic type is the return The return type was not being used to index into the Expectations object. Probably I didn't do that to allow generic methods returning references, because older versions of Mockall didn't already determine the owned form of the return type. Fixes #236 --- CHANGELOG.md | 4 ++++ mockall/tests/mock_generic_return.rs | 4 +++- mockall_derive/src/mock_function.rs | 11 +++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 574e935b..4852fcc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +- Fixed setting multiple expectations on generic methods whose only generic + type is the return. + ([#238](https://github.com/asomers/mockall/pull/238)) + - Fixed mocking generic structs with generic methods whose only generic types are lifetimes. This is useful for mocking generic structs that implement traits like `Future` and `Stream`. diff --git a/mockall/tests/mock_generic_return.rs b/mockall/tests/mock_generic_return.rs index 1d79adff..8fd2a0a5 100644 --- a/mockall/tests/mock_generic_return.rs +++ b/mockall/tests/mock_generic_return.rs @@ -12,6 +12,8 @@ mock! { #[test] fn returning() { let mut mock = MockFoo::new(); - mock.expect_foo::().return_const(42); + mock.expect_foo::().return_const(42i32); + mock.expect_foo::().return_const(69u16); assert_eq!(42i32, mock.foo()); + assert_eq!(69u16, mock.foo()); } diff --git a/mockall_derive/src/mock_function.rs b/mockall_derive/src/mock_function.rs index e8a8a456..ee8f6540 100644 --- a/mockall_derive/src/mock_function.rs +++ b/mockall_derive/src/mock_function.rs @@ -1085,11 +1085,12 @@ impl<'a> ToTokens for ExpectationGuardCommonMethods<'a> { let argnames = &self.f.argnames; let argty = &self.f.argty; + let oo = &self.f.owned_output; let (_, tg, _) = self.f.egenerics.split_for_impl(); let expectations = if self.f.is_expectation_generic() { quote!(self.guard .store - .get_mut(&::mockall::Key::new::<(#(#argty, )*)>()) + .get_mut(&::mockall::Key::new::<(#oo, #(#argty, )*)>()) .unwrap() .downcast_mut::() .unwrap()) @@ -1326,6 +1327,7 @@ impl<'a> ToTokens for GenericExpectationGuard<'a> { egenerics.gt_token.get_or_insert(]>::default()); let (e_ig, e_tg, e_wc) = egenerics.split_for_impl(); let fn_params = &self.f.fn_params; + let oo = &self.f.owned_output; let tbf = tg.as_turbofish(); let v = &self.f.privmod_vis; quote!( @@ -1354,7 +1356,7 @@ impl<'a> ToTokens for GenericExpectationGuard<'a> { { let __mockall_ee: &mut Expectations #tg = __mockall_guard.store.entry( - ::mockall::Key::new::<(#(#argty, )*)>() + ::mockall::Key::new::<(#oo, #(#argty, )*)>() ).or_insert_with(|| Box::new(Expectations #tbf ::new())) .downcast_mut() @@ -2291,6 +2293,7 @@ impl<'a> ToTokens for StaticGenericExpectations<'a> { send_syncify(&mut any_wc, self.f.owned_output.clone()); } let tbf = tg.as_turbofish(); + let oo = &self.f.owned_output; let output = &self.f.output; let v = &self.f.privmod_vis; let (call, get, self_, downcast) = if self.f.return_refmut { @@ -2311,7 +2314,7 @@ impl<'a> ToTokens for StaticGenericExpectations<'a> { #v fn #call #ig (#self_, #(#argnames: #argty, )* ) -> Option<#output> #wc { - self.store.#get(&::mockall::Key::new::<(#(#argty, )*)>()) + self.store.#get(&::mockall::Key::new::<(#oo, #(#argty, )*)>()) .map(|__mockall_e| { __mockall_e.#downcast::() .unwrap() @@ -2322,7 +2325,7 @@ impl<'a> ToTokens for StaticGenericExpectations<'a> { /// Create a new Expectation. #v fn expect #ig (&mut self) -> &mut Expectation #tg #any_wc { - self.store.entry(::mockall::Key::new::<(#(#argty, )*)>()) + self.store.entry(::mockall::Key::new::<(#oo, #(#argty, )*)>()) .or_insert_with(|| Box::new(Expectations #tbf::new())) .downcast_mut::() .unwrap()