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

Changed the syntax for mocking foreign functions. #201

Merged
merged 1 commit into from
Sep 6, 2020
Merged
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
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added

- `#[automock]` now works on modules even without the `nightly` feature, and no
longer requires `#[feature(proc_macro_hygiene)]`
longer requires `#[feature(proc_macro_hygiene)]`.
([#198](https://github.com/asomers/mockall/pull/198))

### Changed

- Changed the syntax for mocking foreign functions. Instead of using
`#[automock]` directly on the `extern` block, you must wrap the `extern`
block in a module, and `#[automock]` that module. The old method is
deprecated.
([#201](https://github.com/asomers/mockall/pull/201))

### Fixed

- Fixed Clippy warnings for mocked methods with `Vec` or `String` arguments.
Expand Down
76 changes: 38 additions & 38 deletions mockall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
//! * [`Multiple and inherited traits`](#multiple-and-inherited-traits)
//! * [`External traits`](#external-traits)
//! * [`Static methods`](#static-methods)
//! * [`Foreign functions`](#foreign-functions)
//! * [`Modules`](#modules)
//! * [`Foreign functions`](#foreign-functions)
//! * [`Async Traits`](#async-traits)
//! * [`Crate features`](#crate-features)
//! * [`Examples`](#examples)
Expand Down Expand Up @@ -909,91 +909,91 @@
//! every mock struct. But it *won't* do that when mocking a struct that
//! already has a method named `new`.
//!
//! ## Foreign functions
//! ## Modules
//!
//! Mockall can also mock foreign functions. Like static methods, the
//! expectations are global. And like mocking structs, you'll probably have to
//! fiddle with your imports to make the mock function accessible. Finally,
//! like associated types, you'll need to provide some extra info to
//! [`#[automock]`](attr.automock.html)
//! to make it work.
//! In addition to mocking types, Mockall can also derive mocks for
//! entire modules of Rust functions. Mockall will generate a new module named
//! "mock_xxx", if "xxx" is the original module's name.
//!
//! ```no_run
//! ```
//! # use mockall::*;
//! # use cfg_if::cfg_if;
//! mod ffi {
//! mod outer {
//! use mockall::automock;
//! #[automock(mod mock;)]
//! extern "C" {
//! pub fn foo(x: u32) -> i64;
//! #[automock()]
//! pub(super) mod inner {
//! pub fn bar(x: u32) -> i64 {
//! // ...
//! # 4
//! }
//! }
//! }
//!
//! cfg_if! {
//! if #[cfg(test)] {
//! use self::ffi::mock::foo;
//! use outer::mock_inner as inner;
//! } else {
//! use self::ffi::foo;
//! use outer::inner;
//! }
//! }
//!
//! fn do_stuff() -> i64 {
//! unsafe{ foo(42) }
//! }
//!
//! #[cfg(test)]
//! mod t {
//! use super::*;
//!
//! #[test]
//! fn test_foo() {
//! let ctx = ffi::mock::foo_context();
//! fn test_foo_bar() {
//! let ctx = inner::bar_context();
//! ctx.expect()
//! .returning(|x| i64::from(x + 1));
//! assert_eq!(43, do_stuff());
//! assert_eq!(5, inner::bar(4));
//! }
//! }
//! # fn main() {}
//! ```
//!
//! ## Modules
//! ### Foreign functions
//!
//! In addition to mocking foreign functions, Mockall can also derive mocks for
//! entire modules of Rust functions. Usage is the same as when mocking foreign
//! functions, except that the mock module name is automatically derived.
//! One reason to mock modules is when working with foreign functions. Modules
//! may contain foreign functions, even though structs and traits may not. Like
//! static methods, the expectations are global. Like mocking structs, you'll
//! probably have to fiddle with your imports to make the mock function
//! accessible.
//!
//! ```
//! # use mockall::*;
//! # use cfg_if::cfg_if;
//! mod outer {
//! use mockall::automock;
//! #[automock()]
//! pub(super) mod inner {
//! pub fn bar(x: u32) -> i64 {
//! // ...
//! # 4
//! # use mockall::*;
//! #[automock]
//! pub mod ffi {
//! extern "C" {
//! pub fn foo(x: u32) -> i64;
//! }
//! }
//! }
//!
//! cfg_if! {
//! if #[cfg(test)] {
//! use outer::mock_inner as inner;
//! use outer::mock_ffi as ffi;
//! } else {
//! use outer::inner;
//! use outer::ffi;
//! }
//! }
//!
//! fn do_stuff() -> i64 {
//! unsafe{ ffi::foo(42) }
//! }
//!
//! #[cfg(test)]
//! mod t {
//! use super::*;
//!
//! #[test]
//! fn test_foo_bar() {
//! let ctx = inner::bar_context();
//! fn test_foo() {
//! let ctx = ffi::foo_context();
//! ctx.expect()
//! .returning(|x| i64::from(x + 1));
//! assert_eq!(5, inner::bar(4));
//! assert_eq!(43, do_stuff());
//! }
//! }
//! # fn main() {}
Expand Down
18 changes: 10 additions & 8 deletions mockall/tests/automock_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ impl A {
#[cfg(not(target_os = "multics"))] pub fn bar(&self, _x: i32) -> i32 {0}
}

#[automock(mod mock_ffi;)]
extern "C" {
// mock_ffi::baz should not be defined
#[cfg(target_os = "multics")]
fn baz(x: DoesNotExist) -> i64;
// mock_ffi::bean should be defined
#[cfg(not(target_os = "multics"))]
fn bean(x: u32) -> i64;
#[automock]
mod ffi {
extern "C" {
// mock_ffi::baz should not be defined
#[cfg(target_os = "multics")]
pub fn baz(x: DoesNotExist) -> i64;
// mock_ffi::bean should be defined
#[cfg(not(target_os = "multics"))]
pub fn bean(x: u32) -> i64;
}
}

#[test]
Expand Down
25 changes: 17 additions & 8 deletions mockall/tests/automock_foreign_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,23 @@

use mockall::*;

#[automock(mod mock_ffi;)]
extern "C" {
#[allow(unused)]
fn foo(x: u32) -> i64;
// Every should_panic method needs to operate on a separate method so it
// doesn't poison other tests
#[allow(unused)]
fn foo1(x: u32) -> i64;
#[automock]
mod ffi {
extern "C" {
pub(super) fn foo(x: u32) -> i64;
// Every should_panic method needs to operate on a separate method so it
// doesn't poison other tests
#[allow(unused)]
pub(super) fn foo1(x: u32) -> i64;
}
}

// Ensure we can still use the original mocked function
#[allow(dead_code)]
fn normal_usage() {
unsafe {
ffi::foo(42);
}
}

#[test]
Expand Down
19 changes: 0 additions & 19 deletions mockall/tests/automock_foreign_c_returning_unit.rs

This file was deleted.

33 changes: 33 additions & 0 deletions mockall/tests/automock_foreign_extern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// vim: tw=80
//! automock can work directly on extern blocks, though it's deprecated
#![allow(deprecated)]
#![deny(warnings)]

use mockall::*;

#[automock(mod mock_ffi;)]
extern "C" {
#[allow(unused)]
fn foo(x: u32) -> i64;
// Every should_panic method needs to operate on a separate method so it
// doesn't poison other tests
#[allow(unused)]
fn foo1(x: u32) -> i64;
}

#[test]
#[should_panic(expected = "mock_ffi::foo1: No matching expectation found")]
fn with_no_matches() {
let ctx = mock_ffi::foo1_context();
ctx.expect()
.with(predicate::eq(4))
.returning(i64::from);
unsafe{ mock_ffi::foo1(5) };
}

#[test]
fn returning() {
let ctx = mock_ffi::foo_context();
ctx.expect().returning(i64::from);
assert_eq!(42, unsafe{mock_ffi::foo(42)});
}
59 changes: 0 additions & 59 deletions mockall/tests/automock_foreign_nonpub.rs

This file was deleted.

10 changes: 6 additions & 4 deletions mockall/tests/automock_foreign_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

use mockall::*;

#[automock(mod mock_ffi;)]
extern "Rust" {
#[allow(unused)]
fn foo(x: u32) -> i64;
#[automock]
mod ffi {
extern "Rust" {
#[allow(unused)]
pub fn foo(x: u32) -> i64;
}
}

#[test]
Expand Down
Loading