diff --git a/CHANGELOG.md b/CHANGELOG.md index 0621d98c..a7fec30c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Support mocking methods with arbitrary receivers like `self: Box instead of &self +#![deny(warnings)] + +use mockall::*; +use std::sync::Arc; +use std::pin::Pin; +use std::rc::Rc; + +mock! { + Foo { + fn foo(self: &Box); + fn baz(mut self: Box); + fn bar(self: Box); + fn bean(self: Arc); + fn booz(self: Pin>); + fn blez(self: Rc); + } +} + +#[test] +fn arc() { + let mut mock = MockFoo::new(); + mock.expect_bean() + .returning(|| ()); + Arc::new(mock).bean(); +} + +#[test] +fn pin() { + let mut mock = MockFoo::new(); + mock.expect_booz() + .returning(|| ()); + Pin::new(Box::new(mock)).booz(); +} + +#[test] +fn rc() { + let mut mock = MockFoo::new(); + mock.expect_blez() + .returning(|| ()); + Rc::new(mock).blez(); +} + +#[test] +fn ref_box() { + let mut mock = Box::new(MockFoo::new()); + mock.expect_foo() + .returning(|| ()); + mock.foo(); +} + +#[test] +fn mutable() { + let mut mock = Box::new(MockFoo::new()); + mock.expect_baz() + .returning(|| ()); + mock.baz(); +} + +#[test] +fn owned() { + let mut mock = Box::new(MockFoo::new()); + mock.expect_bar() + .returning(|| ()); + mock.bar(); +} diff --git a/mockall_derive/src/lib.rs b/mockall_derive/src/lib.rs index fde5b15b..9ec212ae 100644 --- a/mockall_derive/src/lib.rs +++ b/mockall_derive/src/lib.rs @@ -163,7 +163,9 @@ fn declosurefy(gen: &Generics, args: &Punctuated) -> let mut pt2 = pt.clone(); demutify_arg(&mut pt2); let pat = &pt2.pat; - if hm.contains_key(&pt.ty) { + if pat_is_self(pat) { + None + } else if hm.contains_key(&pt.ty) { Some(quote!(Box::new(#pat))) } else { Some(quote!(#pat)) @@ -452,6 +454,15 @@ fn format_attrs(attrs: &[syn::Attribute], include_docs: bool) -> TokenStream { out } +/// Determine if this Pat is any kind of `self` binding +fn pat_is_self(pat: &Pat) -> bool { + if let Pat::Ident(pi) = pat { + pi.ident == "self" + } else { + false + } +} + fn supersuperfy_path(path: &mut Path, levels: i32) { if let Some(t) = path.segments.first() { if t.ident == "super" { diff --git a/mockall_derive/src/mock_function.rs b/mockall_derive/src/mock_function.rs index 145223fa..fd1610d1 100644 --- a/mockall_derive/src/mock_function.rs +++ b/mockall_derive/src/mock_function.rs @@ -139,6 +139,11 @@ impl<'a> Builder<'a> { for fa in declosured_inputs.iter() { if let FnArg::Typed(pt) = fa { let argname = (*pt.pat).clone(); + if pat_is_self(&argname) { + // A weird receiver like `Box` + is_static = false; + continue; + } let aty = supersuperfy(&pt.ty, self.levels); if let Type::Reference(ref tr) = aty { predexprs.push(quote!(#argname));