Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for trait-variant #640

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mockall/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ predicates-tree = "1.0"
mockall_derive = { version = "=0.13.1", path = "../mockall_derive" }

[dev-dependencies]
trait-variant = "0.1.2"
async-trait = "0.1.38"
auto_enums = "0.8.5"
futures = "0.3.7"
Expand Down
20 changes: 11 additions & 9 deletions mockall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,15 +1067,17 @@
//!
//! ## Async Traits
//!
//! Async traits aren't yet (as of 1.47.0) a part of the Rust language. But
//! they're available from the
//! [`async_trait`](https://docs.rs/async-trait/0.1.38/async_trait/) crate.
//! Mockall is compatible with this crate, with two important limitations:
//!
//! * The `#[automock]` attribute must appear _before_ the `#[async_trait]`
//! attribute.
//!
//! * The `#[async_trait]` macro must be imported with its canonical name.
//! Partial support for async traits was introduced in the Rust language since
//! 1.75.0.
//! Mockall is compatible with them, as well as both
//! [`async_trait`](https://docs.rs/async-trait/latest/async_trait/) and
//! [`trait_variant`](https://docs.rs/trait-variant/latest/trait_variant/)
//! crates, with an important limitation:
//!
//! * The `#[automock]` attribute must appear _before_ the crate's attribute.
//!
//! * The `#[async_trait]` and `#[trait_variant::make]` macros must be
//! imported with their canonical name.
//!
//! ```
//! # use async_trait::async_trait;
Expand Down
29 changes: 29 additions & 0 deletions mockall/tests/automock_trait_variant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// vim: tw=80
//! A native async trait with trait_variant, for use with Futures
#![deny(warnings)]

use futures::executor::block_on;
use mockall::*;

#[automock]
#[trait_variant::make(Send)]
pub trait Foo {
async fn foo(&self) -> u32;
async fn bar() -> u32;
}

#[test]
fn return_const() {
let mut mock = MockFoo::new();
mock.expect_foo()
.return_const(42u32);
assert_eq!(block_on(mock.foo()), 42);
}

#[test]
fn static_method() {
let ctx = MockFoo::bar_context();
ctx.expect()
.return_const(42u32);
assert_eq!(block_on(MockFoo::bar()), 42);
}
27 changes: 27 additions & 0 deletions mockall/tests/mock_trait_variant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// vim: tw=80
//! A native async trait with trait_variant, for use with Futures
#![deny(warnings)]

use futures::executor::block_on;
use mockall::*;

#[trait_variant::make(Send)]
pub trait Foo {
async fn foo(&self) -> u32;
}

mock! {
pub Bar { }
#[trait_variant::make(Send)]
impl Foo for Bar {
async fn foo(&self) -> u32;
}
}

#[test]
fn return_const() {
let mut mock = MockBar::new();
mock.expect_foo()
.return_const(42u32);
assert_eq!(block_on(mock.foo()), 42);
}
9 changes: 9 additions & 0 deletions mockall_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ fn find_lifetimes(ty: &Type) -> HashSet<Lifetime> {
struct AttrFormatter<'a>{
attrs: &'a [Attribute],
async_trait: bool,
trait_variant: bool,
doc: bool,
must_use: bool,
}
Expand All @@ -783,6 +784,7 @@ impl<'a> AttrFormatter<'a> {
Self {
attrs,
async_trait: true,
trait_variant: false,
doc: true,
must_use: false,
}
Expand All @@ -793,6 +795,11 @@ impl<'a> AttrFormatter<'a> {
self
}

fn trait_variant(&mut self, allowed: bool) -> &mut Self {
self.trait_variant = allowed;
self
}

fn doc(&mut self, allowed: bool) -> &mut Self {
self.doc = allowed;
self
Expand Down Expand Up @@ -823,6 +830,8 @@ impl<'a> AttrFormatter<'a> {
self.doc
} else if *i.as_ref().unwrap() == "async_trait" {
self.async_trait
} else if *i.as_ref().unwrap() == "make" {
self.trait_variant
} else if *i.as_ref().unwrap() == "expect" {
// This probably means that there's a lint that needs to be
// surpressed for the real code, but not for the mock code.
Expand Down
1 change: 1 addition & 0 deletions mockall_derive/src/mockable_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ impl From<(Attrs, ItemTrait)> for MockableStruct {
let mut attrs = AttrFormatter::new(&trait_.attrs)
.doc(true)
.async_trait(true)
.trait_variant(true)
.must_use(false)
.format();
attrs.push(derive_debug());
Expand Down