Skip to content

Commit

Permalink
Fix an issue with generic methods whose only generic type is the return
Browse files Browse the repository at this point in the history
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
  • Loading branch information
asomers committed Dec 22, 2020
1 parent 0fcd9c4 commit 96ee7e8
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
4 changes: 3 additions & 1 deletion mockall/tests/mock_generic_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mock! {
#[test]
fn returning() {
let mut mock = MockFoo::new();
mock.expect_foo::<i32>().return_const(42);
mock.expect_foo::<i32>().return_const(42i32);
mock.expect_foo::<u16>().return_const(69u16);
assert_eq!(42i32, mock.foo());
assert_eq!(69u16, mock.foo());
}
11 changes: 7 additions & 4 deletions mockall_derive/src/mock_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Expectations #tg>()
.unwrap())
Expand Down Expand Up @@ -1326,6 +1327,7 @@ impl<'a> ToTokens for GenericExpectationGuard<'a> {
egenerics.gt_token.get_or_insert(<Token![>]>::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!(
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 {
Expand All @@ -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::<Expectations #tg>()
.unwrap()
Expand All @@ -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::<Expectations #tg>()
.unwrap()
Expand Down

0 comments on commit 96ee7e8

Please sign in to comment.