Skip to content

Commit

Permalink
Allow mocking methods with complicated receivers like self: Box<Self>
Browse files Browse the repository at this point in the history
Fixes #150
Fixes #109
  • Loading branch information
asomers committed Aug 23, 2020
1 parent db0dc91 commit a6e44ae
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 2 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased] - ReleaseDate
### Added
- Support mocking methods with arbitrary receives like `self: Box<Self`
([#176](https://github.com/asomers/mockall/pull/176))

- Support mocking methods with trait object arguments that use implicit
lifetimes
lifetimes.
([#174](https://github.com/asomers/mockall/pull/174))

### Changed
Expand Down
67 changes: 67 additions & 0 deletions mockall/tests/mock_box_self.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// vim: tw=80
//! Methods that take receivers like Box<Self> 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<Self>);
fn baz(mut self: Box<Self>);
fn bar(self: Box<Self>);
fn bean(self: Arc<Self>);
fn booz(self: Pin<Box<Self>>);
fn blez(self: Rc<Self>);
}
}

#[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();
}
13 changes: 12 additions & 1 deletion mockall_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ fn declosurefy(gen: &Generics, args: &Punctuated<FnArg, Token![,]>) ->
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))
Expand Down Expand Up @@ -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" {
Expand Down
5 changes: 5 additions & 0 deletions mockall_derive/src/mock_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self>`
is_static = false;
continue;
}
let aty = supersuperfy(&pt.ty, self.levels);
if let Type::Reference(ref tr) = aty {
predexprs.push(quote!(#argname));
Expand Down

0 comments on commit a6e44ae

Please sign in to comment.