Skip to content

Commit

Permalink
Fix the circular crate dependency by fooling rustdoc
Browse files Browse the repository at this point in the history
mockall depends on mockall_derive, because it reexports its macros.  But
mockall_derive has a dev dependency on mockall, because of its doc
tests.  This makes publishing new versions to crates.io painful, and it
recently broke mockall_derive's docs on docs.rs.

This commit moves all of mockall_derive's doc tests into mockall by
fooling rustdoc.  When #[cfg(rustdoc)] is set, mockall doesn't reexport
anything from mockall_derive.  Instead it defines some empty macros and
documents those instead.  It's not perfect, but it'll have to do until
there's a better solution for
rust-lang/rust#49553 .

CC @jasongrlicky
  • Loading branch information
asomers committed Aug 10, 2019
1 parent b7f9bc3 commit 82360ec
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 165 deletions.
215 changes: 192 additions & 23 deletions mockall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
//! # Usage
//!
//! There are two ways to use Mockall. The easiest is to use
//! [`#[automock]`](https://docs.rs/mockall_derive/latest/mockall_derive/attr.automock.html).
//! It can mock most
//! traits, or structs that only have a single `impl` block. For things it
//! can't handle, there is
//! [`mock!`](https://docs.rs/mockall_derive/latest/mockall_derive/macro.mock.html).
//! [`#[automock]`](macro.automock.html). It can mock most traits, or structs
//! that only have a single `impl` block. For things it can't handle, there is
//! [`mock!`].
//!
//! Whichever method is used, the basic idea is the same.
//! * Create a mock struct. It's name will be the same as the original, with
Expand Down Expand Up @@ -577,7 +575,7 @@
//! because it has a different name. The solution is to alter import paths
//! during test. The [`cfg-if`] crate helps.
//!
//! [`#[automock]`](https://docs.rs/mockall_derive/latest/mockall_derive/attr.automock.html)
//! [`#[automock]`](macro.automock.html)
//! works for structs that have a single `impl` block:
//! ```no_run
//! # use mockall::*;
Expand Down Expand Up @@ -619,8 +617,7 @@
//! }
//! # fn main() {}
//! ```
//! For structs with more than one `impl` block, see
//! [`mock!`](https://docs.rs/mockall_derive/latest/mockall_derive/macro.mock.html)
//! For structs with more than one `impl` block, see [`mock!`]
//! instead.
//!
//! ## Generic methods
Expand Down Expand Up @@ -676,8 +673,7 @@
//! Traits with associated types can be mocked too. Unlike generic traits, the
//! mock struct will not be generic. Instead, you must specify the associated
//! types when defining the mock struct. They're specified as metaitems to the
//! [`#[automock]`](https://docs.rs/mockall_derive/latest/mockall_derive/attr.automock.html)
//! attribute.
//! [`#[automock]`](macro.automock.html) attribute.
//!
//! ```
//! # use mockall::*;
Expand All @@ -697,10 +693,8 @@
//! ## Multiple and inherited traits
//!
//! Creating a mock struct that implements multiple traits, whether inherited or
//! not, requires using the
//! [`mock!`](https://docs.rs/mockall_derive/latest/mockall_derive/macro.mock.html)
//! macro. But once created, using it is just the same as using any other mock
//! object
//! not, requires using the [`mock!`] macro. But once created,
//! using it is just the same as using any other mock object
//!
//! ```
//! # use mockall::*;
Expand Down Expand Up @@ -736,10 +730,8 @@
//! ## External traits
//!
//! Mockall can mock traits and structs defined in external crates that are
//! beyond your control, but you must use
//! [`mock!`](https://docs.rs/mockall_derive/latest/mockall_derive/macro.mock.html)
//! instead of [`#[automock]`](https://docs.rs/mockall_derive/latest/mockall_derive/attr.automock.html).
//! Mock an external trait like this:
//! beyond your control, but you must use [`mock!`] instead of
//! [`#[automock]`](macro.automock.html). Mock an external trait like this:
//!
//! ```
//! # use mockall::*;
Expand Down Expand Up @@ -837,7 +829,7 @@
//! 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]`](https://docs.rs/mockall_derive/latest/mockall_derive/attr.automock.html)
//! [`#[automock]`](macro.automock.html)
//! to make it work.
//!
//! ```no_run
Expand Down Expand Up @@ -963,6 +955,7 @@
//! [`predicates`]: predicate/index.html
#![cfg_attr(feature = "nightly", feature(specialization))]
#![cfg_attr(feature = "nightly", feature(doc_cfg))]
#![deny(intra_doc_link_resolution_failure)]

use downcast::*;
Expand All @@ -978,15 +971,191 @@ use std::{
thread
};

pub use mockall_derive::{mock, automock};
/// For mocking static methods
#[doc(hidden)]
pub use lazy_static::lazy_static;

pub use predicates::{
boolean::PredicateBooleanExt,
prelude::{Predicate, predicate}
};

/// For mocking static methods
#[doc(hidden)]
pub use lazy_static::lazy_static;
::cfg_if::cfg_if! {
if #[cfg(any(not(feature = "nightly"), not(rustdoc)))] {
pub use mockall_derive::{mock, automock};
} else {
// mockall_derive can't use mockall in its doc tests, because that would
// create a circular dependency between the two crates. And we can't
// add docs directly to the reexport item, for reasons I know not why.
// So, when building the docs, we create fake items to document in place
// of the reexports.
// https://github.com/rust-lang/rust/issues/49553
/// Automatically generate mock types for structs and traits.
///
/// This is by far the easiest way to use Mockall. It works on almost
/// all traits, and almost all structs that have a single `impl` block.
/// In either case, it will generate a mock struct whose name is the
/// name of the mocked struct/trait prepended with "Mock". For each
/// method of the original, the mock struct will have a method named
/// `expect_whatever` that allows you to set expectations. There will
/// also be one `checkpoint` method that calls
/// [`checkpoint`] for every single mocked method.
///
/// # Examples
///
/// The simplest use case is mocking a no-frills trait
/// ```
/// # use mockall_derive::*;
/// #[automock]
/// pub trait Foo {
/// fn foo(&self, key: i16);
/// }
///
/// let mock = MockFoo::new();
/// ```
///
/// Mocking a structure:
/// ```
/// # use mockall_derive::*;
/// struct Foo {}
/// #[automock]
/// impl Foo {
/// fn foo(&self) -> u32 {
/// // ...
/// # unimplemented!()
/// }
/// }
/// ```
///
/// Mocking a trait with associated types requires adding a metaitem to
/// the attribute:
/// ```
/// # use mockall_derive::*;
/// #[automock(type Item=u32;)]
/// trait Foo {
/// type Item;
/// fn foo(&self) -> Self::Item;
/// }
/// ```
///
/// Finally, `#[automock]` can also mock foreign functions. This
/// requires another metaitem to specify the mock module name.
///
/// ```
/// # use mockall_derive::*;
/// #[automock(mod mock_ffi;)]
/// extern "C" {
/// pub fn foo() -> u32;
/// }
/// ```
///
/// [`checkpoint`]: ../mockall/index.html#checkpoints
///
/// # Limitations
///
/// `#[automock]` can't handle everything. There are some cases where
/// you will need to use [`mock`] instead:
/// * Mocking a struct that has multiple `impl` blocks, including
/// structs that implement traits.
/// * Mocking a struct or trait defined in another crate.
/// * Mocking a trait with trait bounds.
/// * If the autogenerated "MockFoo" name isn't acceptable, and you want
/// to choose your own name for the mock structure.
#[macro_export]
macro_rules! automock {() => {}}

/// Manually mock a structure.
///
/// Sometimes `automock` can't be used. In those cases you can use
/// `mock!`, which basically involves repeating the struct's or trait's
/// definitions.
///
/// The format is:
///
/// * Optional visibility specifier
/// * Real structure name and generics fields
/// * 0 or more methods of the structure, written without bodies,
/// enclosed in a {} block
/// * 0 or more traits to implement for the structure, written like
/// normal traits
///
/// # Examples
///
/// Mock a trait. This is the simplest use case.
/// ```
/// # use mockall_derive::mock;
/// trait Foo {
/// fn foo(&self, x: u32);
/// }
/// mock!{
/// pub MyStruct<T: Clone + 'static> {
/// fn bar(&self) -> u8;
/// }
/// trait Foo {
/// fn foo(&self, x: u32);
/// }
/// }
/// # fn main() {}
/// ```
///
/// When mocking a generic struct's implementation of a generic trait,
/// use the same namespace for their generic parameters. For example,
/// if you wanted to mock `Rc`, do
/// ```
/// # use mockall_derive::mock;
/// mock!{
/// pub Rc<T: 'static> {}
/// trait AsRef<T> {
/// fn as_ref(&self) -> &T;
/// }
/// }
/// # fn main() {}
/// ```
/// *not*
/// ```compile_fail
/// # use mockall_derive::mock;
/// mock!{
/// pub Rc<Q: 'static> {}
/// trait AsRef<T: 'static> {
/// fn as_ref(&self) -> &T;
/// }
/// }
/// # fn main() {}
/// ```
/// Associated types can easily be mocked by specifying a concrete type
/// in the `mock!{}` invocation. But be careful not to reference the
/// associated type in the signatures of any of the trait's methods;
/// repeat the concrete type instead. For example, do:
/// ```
/// # use mockall_derive::mock;
/// mock!{
/// MyIter {}
/// trait Iterator {
/// type Item=u32;
///
/// fn next(&mut self) -> Option<u32>;
/// }
/// }
/// # fn main() {}
/// ```
/// *not*
/// ```compile_fail
/// # use mockall_derive::mock;
/// mock!{
/// MyIter {}
/// trait Iterator {
/// type Item=u32;
///
/// fn next(&mut self) -> Option<<Self as Iterator>::Item>;
/// }
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! mock {() => {}}
}
}


#[doc(hidden)]
pub trait AnyExpectations : Any + Send + Sync {}
Expand Down
1 change: 0 additions & 1 deletion mockall_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,5 @@ syn = { version = "0.15", features = ["extra-traits", "full"] }
[dev-dependencies]
downcast = "0.10"
fragile = "0.3"
mockall = { version = "0.2.0", path = "../mockall" }
predicates-tree = "1.0"
pretty_assertions = "0.5"
Loading

0 comments on commit 82360ec

Please sign in to comment.