unimock/
lib.rs

1//!
2//! `unimock` is a library for defining _mock implementations_ of traits.
3//!
4//! Mocking, in a broad sense, is a way to control API behaviour during test execution.
5//!
6//! The _uni_ in unimock indicates one-ness: All mockable traits are implemented by a single type, [Unimock](crate::Unimock).
7//! This design allows for a great flexibility in coding style, as will be demonstrated further down.
8//!
9//! The first code example is the smallest possible use of unimock:
10//!
11//! ```rust
12//! use unimock::*;
13//!
14//! #[unimock]
15//! trait Foo {}
16//!
17//! fn takes_foo(foo: impl Foo) {}
18//!
19//! takes_foo(Unimock::new(()));
20//! ```
21//!
22//! 1. `trait Foo` is declared with the [`#[unimock]`](crate::unimock) attribute which makes its behaviour mockable.
23//! 2. `fn takes_foo` accepts some type that implements the trait. This function adheres to zero-cost _Inversion of Control/Dependency Inversion_.
24//! 3. A mock instantiation by calling [`Unimock::new(())`](crate::Unimock::new), which crates a [`Unimock`](crate::Unimock) value which is passed into `takes_foo`.
25//!
26//! The [`new`](crate::Unimock::new) function takes an argument called `setup` (implementing [`Clause`](crate::Clause)), in this case the unit value `()`.
27//! The setup argument is _what behaviour is being mocked_, in this case nothing at all.
28//! `Foo` contains no methods, so there is no behaviour to mock.
29//!
30//! ## Methods and behaviour mocking
31//!
32//! In order to be somewhat useful, the traits we abstract over should contain some methods.
33//! In a unit test for some function, we'd like to mock the behaviour of that function's dependencies (expressed as trait bounds).
34//!
35//! Given some trait,
36//!
37//! ```rust
38//! # use unimock::*;
39//! #[unimock]
40//! trait Foo {
41//!     fn foo(&self) -> i32;
42//! }
43//! ```
44//!
45//! we would like to tell unimock what `Foo::foo`'s behaviour will be, i.e. what it will return.
46//! In order to do that, we first need to refer to the method.
47//! In Rust, trait methods aren't reified entities, they are not types nor values, so they cannot be referred to in code.
48//! We need to tell unimock to expose a separate mocking API.
49//! This API will be created in form of a new module, [which is named](#selecting-a-name-for-the-mock-api) by passing e.g. `api=TraitMock` to the unimock macro invocation.
50//!
51//! Each of the trait's original methods will get exported as mock config entrypoints through this module: For example `TraitMock::method`.
52//! `method` is a type that will implement [`MockFn`](crate::MockFn), which is the entrypoint for creating a [`Clause`](crate::Clause):
53//!
54//! ```rust
55//! # use unimock::*;
56//! #[unimock(api=FooMock)]
57//! trait Foo {
58//!     fn foo(&self) -> i32;
59//! }
60//!
61//! fn test_me(foo: impl Foo) -> i32 {
62//!     foo.foo()
63//! }
64//!
65//! let clause = FooMock::foo.each_call(matching!()).returns(1337);
66//!
67//! assert_eq!(1337, test_me(Unimock::new(clause)));
68//! ```
69//!
70//! Clause construction is a type-state machine that in this example goes through two steps:
71//!
72//! 1. [`FooMock::foo.each_call(matching!())`](crate::MockFn::each_call): Define a _call pattern_.
73//!    Each call to `Foo::foo` that matches the empty argument list (i.e. always matching, since the method is parameter-less).
74//! 2. [`.returns(1337)`](crate::build::DefineResponse::returns): Each matching call will return the value `1337`.
75//!
76//! In this example there is only one clause.
77//!
78//! ### Call patterns (matching inputs)
79//!
80//! It is common to want to control how a function will respond in relation to what input is given to it!
81//! Inputs are matched by a function that receives the inputs as a tuple, and returns whether it matched as a `bool`.
82//! A specific `MockFn` together with an input matcher is referred to as a _call pattern_ from now on.
83//!
84//! The [`matching!`](crate::matching) macro provides syntax sugar for argument matching.
85//! It has a syntax inspired by the [`std::matches`](https://doc.rust-lang.org/std/macro.matches.html) macro.
86//!
87//! Inputs being matched is a condition that needs to be fulfilled in order for the rest of the call pattern to be evaluated.
88//!
89//! ### Specifying outputs (responses)
90//! Specifying outputs can be done in several ways. The simplest one is [`returns(some_value)`](crate::build::DefineResponse::returns).
91//! Different ways of specifying outputs are found in [`build::DefineResponse`](crate::build::DefineResponse).
92//!
93//! There are different constraints acting on return values based on how the clause gets initialized:
94//!
95//! * [`some_call`](crate::MockFn::some_call) is tailored for calls that will happen once. Return values have no [Clone] constraint.
96//! * [`each_call`](crate::MockFn::each_call) is tailored for calls that are expected to happen more than once, thus requiring [Clone] on return values.
97//! * [`next_call`](crate::MockFn::next_call) is used for [verifying exact call sequences](#verifying-exact-sequence-of-calls), otherwise works similar to `some_call`.
98//!
99//! ### Mutating inputs
100//! Many traits uses the argument mutation pattern, where there are one or more `&mut` parameters.
101//!
102//! To access the `&mut` parameters (and mutate them), a function is applied to the call pattern using [`answers`](crate::build::DefineResponse::answers):
103//!
104//! ```rust
105//! # use unimock::*;
106//! let mocked = Unimock::new(
107//!     mock::core::fmt::DisplayMock::fmt
108//!         .next_call(matching!(_))
109//!         .answers(&|_, f| write!(f, "mutation!"))
110//! );
111//!
112//! assert_eq!("mutation!", format!("{mocked}"));
113//! ```
114//!
115//! The argument to `answers` is a function with the same signature as the method it mocks, including the `self` parameter.
116//!
117//! ## Combining setup clauses
118//! `Unimock::new()` accepts as argument anything that implements [Clause].
119//! Basic setup clauses can be combined into composite clauses by using _tuples_:
120//!
121//! ```rust
122//! # use unimock::*;
123//! #[unimock(api=FooMock)]
124//! trait Foo {
125//!     fn foo(&self, arg: i32) -> i32;
126//! }
127//!
128//! #[unimock(api=BarMock)]
129//! trait Bar {
130//!     fn bar(&self, arg: i32) -> i32;
131//! }
132//!
133//! fn test_me(deps: &(impl Foo + Bar), arg: i32) -> i32 {
134//!     deps.bar(deps.foo(arg))
135//! }
136//!
137//! assert_eq!(
138//!     42,
139//!     test_me(
140//!         &Unimock::new((
141//!             FooMock::foo
142//!                 .some_call(matching!(_))
143//!                 .answers(&|_, arg| arg * 3),
144//!             BarMock::bar
145//!                 .some_call(matching!((arg) if *arg > 20))
146//!                 .answers(&|_, arg| arg * 2),
147//!         )),
148//!         7
149//!     )
150//! );
151//!
152//! // alternatively, define _stubs_ for each method.
153//! // This is a nice way to group methods by introducing a closure scope:
154//! assert_eq!(
155//!     42,
156//!     test_me(
157//!         &Unimock::new((
158//!             FooMock::foo.stub(|each| {
159//!                 each.call(matching!(1337)).returns(1024);
160//!                 each.call(matching!(_)).answers(&|_, arg| arg * 3);
161//!             }),
162//!             BarMock::bar.stub(|each| {
163//!                 each.call(matching!((arg) if *arg > 20)).answers(&|_, arg| arg * 2);
164//!             }),
165//!         )),
166//!         7
167//!     )
168//! );
169//! ```
170//!
171//! In both these examples, the order in which the clauses are specified do not matter, _except for input matching_.
172//! In order for unimock to find the correct response, call patterns will be matched in the sequence they were defined.
173//!
174//! ## Interaction verifications
175//! Unimock performs interaction verifications using a declarative approach.
176//! Expected interactions are configured at construction time, using [Clause]s.
177//! Rust makes it possible to automatically verify things because of RAII and the [drop] method, which Unimock implements.
178//! When a Unimock instance goes out of scope, Rust automatically runs its verification rules.
179//!
180//! One verification is always enabled in unimock:
181//!
182//! _Each [`MockFn`](crate::MockFn) mentioned in some setup clause must be interacted with at least once._
183//!
184//! If this requirement is not met, Unimock will panic inside its Drop implementation.
185//! The reason is to help avoiding "bit rot" accumulating over time inside test code.
186//! When refactoring release code, tests should always follow along and not be overly generic.
187//!
188//! In general, clauses do not only encode what behaviour is _allowed_ to happen, but also that this behaviour necessarily _must happen_.
189//!
190//! ### Optional call count expectations in call patterns
191//! To make a call count expectation for a specific call pattern,
192//!    look at [`Quantify`](build::Quantify) or [`QuantifyReturnValue`](build::QuantifyReturnValue), which have methods like
193//!    [`once()`](build::Quantify::once),
194//!    [`n_times(n)`](build::Quantify::n_times) and
195//!    [`at_least_times(n)`](build::Quantify::at_least_times).
196//!
197//! With exact quantification in place, _output sequence_ verifications can be constructed by chaining combinators:
198//!
199//! ```rust
200//! # use unimock::*;
201//! # #[unimock(api=HiddenMock)]
202//! # trait Hidden { fn hidden(&self, arg: i32) -> i32; }
203//! # let mocked = Unimock::new((
204//! # HiddenMock::hidden.stub(|each| {
205//! each.call(matching!(_)).returns(1).n_times(2).then().returns(2);
206//! # })
207//! # ));
208//! # assert_eq!(1, mocked.hidden(42));
209//! # assert_eq!(1, mocked.hidden(42));
210//! # assert_eq!(2, mocked.hidden(42));
211//! # assert_eq!(2, mocked.hidden(42));
212//! ```
213//!
214//! The output sequence will be `[1, 1, 2, 2, 2, ..]`.
215//! A call pattern like this _must_ be matched at least 3 times.
216//! 2 times because of the first exact output sequence, then at least one time because of the [`.then()`](build::QuantifiedResponse::then) combinator.
217//!
218//! ### Verifying exact sequence of calls
219//! Exact call sequences may be expressed using _strictly ordered clauses_.
220//! Use [`next_call`](MockFn::next_call) to define this kind of call pattern.
221//!
222//! ```rust
223//! # use unimock::*;
224//! # #[unimock(api=FooMock)]
225//! # trait Foo { fn foo(&self, arg: i32) -> i32; }
226//! # #[unimock(api=BarMock)]
227//! # trait Bar { fn bar(&self, arg: i32) -> i32; }
228//! # let mocked =
229//! Unimock::new((
230//!     FooMock::foo.next_call(matching!(3)).returns(5),
231//!     BarMock::bar.next_call(matching!(8)).returns(7).n_times(2),
232//! ));
233//! # assert_eq!(5, mocked.foo(3));
234//! # assert_eq!(7, mocked.bar(8));
235//! # assert_eq!(7, mocked.bar(8));
236//! ```
237//!
238//! All clauses constructed by `next_call` are expected to be evaluated in the exact sequence they appear in the clause tuple.
239//!
240//! Order-sensitive clauses and order-insensitive clauses (like [`some_call`](MockFn::some_call)) do not interfere with each other.
241//! However, these kinds of clauses cannot be combined _for the same MockFn_ in a single Unimock value.
242//!
243//!
244//! ## Application architecture
245//!
246//! Writing larger, testable applications with unimock requires some degree of architectural discipline.
247//! We already know how to specify dependencies using trait bounds.
248//! But would this scale in practice when several layers are involved?
249//! One of the main features of unimock is that all traits are implemented by `Unimock`.
250//! This means that trait bounds can be composed, and we can use _one value_ that implements all our dependencies:
251//!
252//! ```rust
253//! # trait A {}
254//! # trait B {}
255//! # trait C {}
256//! fn some_function(deps: &(impl A + B + C), arg: i32) {
257//!     // ..
258//! }
259//! ```
260//!
261//! In a way, this function resembles a `self`-receiving function.
262//! The `deps` argument is how the function abstracts over its dependencies.
263//! Let's keep this call convention and let it scale a bit by introducing two layers:
264//!
265//! ```rust
266//! use std::any::Any;
267//!
268//! trait A {
269//!     fn a(&self, arg: i32) -> i32;
270//! }
271//!
272//! trait B {
273//!     fn b(&self, arg: i32) -> i32;
274//! }
275//!
276//! fn a(deps: &impl B, arg: i32) -> i32 {
277//!     deps.b(arg) + 1
278//! }
279//!
280//! fn b(deps: &impl Any, arg: i32) -> i32 {
281//!     arg + 1
282//! }
283//! ```
284//!
285//! The dependency from `fn a` to `fn b` is completely abstracted away, and in test mode the `deps: &impl X` gets substituted with `deps: &Unimock`.
286//! But Unimock is only concerned with the _testing_ side of the picture.
287//! The previous code snippet is at the extreme end of the loosely-coupled scale: _No coupling at all!_
288//! It shows that unimock is merely a piece in a larger picture.
289//! To wire all of this together into a full-fledged runtime solution, without too much boilerplate, reach for the _[entrait pattern](https://docs.rs/entrait)_.
290//!
291//! ### Gated mock implementation
292//! If the trait definition, the uses of the trait bound and the tests all live within the same crate, it's possible to _gate_ the macro invocation:
293//!
294//! ```rust
295//! # use unimock::*;
296//! #[cfg_attr(test, unimock(api = FooMock))]
297//! trait Foo {}
298//! ```
299//!
300//! ### Combining release code and mocks: Partial mocks
301//! Unimock can be used to create arbitrarily deep integration tests, mocking away layers only indirectly used.
302//! For that to work, unimock needs to know how to call the "real" implementation of traits.
303//!
304//! See the documentation of [`new_partial`](crate::Unimock::new_partial) to see how this works.
305//!
306//! Although this can be implemented with unimock directly, it works best with a higher-level macro like [`entrait`](https://docs.rs/entrait).
307//!
308//! ### `no_std`
309//! Unimock can be used in a `no_std` environment. The `"std"` feature is enabled by default, and can be removed to enable `no_std`.
310//!
311//! The `no_std` environment depends on [alloc](https://doc.rust-lang.org/alloc/) and requires a global allocator.
312//! Some unimock features rely on a working implementation of Mutex, and the `spin-lock` feature enables this for `no_std`.
313//! The `critical-section` feature is also required for `no_std`.
314//! These two features will likely merge into one in some future breaking release.
315//!
316//!
317//! ## Mock APIs for central crates
318//! Unimock works well when the trait being abstracted over is defined in the same code base as the once that contains the test.
319//! The Rust Orphan Rule ensures that a Unimock user cannot define a mock implementation for a trait that is upstream to their project.
320//!
321//! For this reason, Unimock has started to move in a direction where it itself defines mock APIs for central crates.
322//!
323//! These mock APIs can be found in [mock].
324//!
325//!
326//! ## Misc
327//!
328//! #### What kinds of things can be mocked with unimock?
329//! * Traits with any number of methods
330//! * Traits with generic parameters, although these cannot be lifetime constrained (i.e. need to satisfy `T: 'static`).
331//! * Traits with associated types and constants, using `#[unimock(type T = Foo; const FOO: T = value;)]` syntax.
332//! * Methods with any self receiver (`self`, `&self`, `&mut self` or arbitrary (e.g. `self: Rc<Self>`)).
333//! * Methods that take reference inputs.
334//! * Methods returning values borrowed from self.
335//! * Methods returning references to arguments.
336//! * Methods returning `Option<&T>`, `Result<&T, E>` or `Vec<&T>` for any `T` that is borrowed from `self`.
337//! * Methods returning any tuple combination of self-borrowed or owned elements up to 4 elements.
338//! * Methods returning a type containing lifetime parameters. For a mocked return they will have to be `'static`.
339//! * Generic methods using either explicit generic params or argument-position `impl Trait`.
340//! * Methods that are `async` or return `impl Future`.
341//! * `async_trait`-annotated traits.
342//!
343//! #### What kinds of traits or methods cannot be mocked?
344//! * Static methods, i.e. no `self` receiver. Static methods with a _default body_ are accepted though, but not mockable.
345//!
346//! #### Selecting a name for the mock `api`
347//! Due to [macro hygiene](https://en.wikipedia.org/wiki/Hygienic_macro),
348//!     unimock tries to avoid autogenerating any new identifiers that might accidentally create undesired namespace collisions.
349//! To avoid user confusion through conjuring up new identifier names out of thin air, the name of the mocking API therefore has to be user-supplied.
350//! Although the user is free to choose any name, unimock suggests following a naming convention.
351//!
352//! The entity being mocked is a trait, but the mocking API is a module.
353//! This introduces a conflict in naming convention style, since traits use CamelCase but modules use snake_case.
354//!
355//! _The suggested naming convention is using the name of the trait (e.g. `Trait`) postfixed with `Mock`: The resulting module should be called `TraitMock`._
356//!
357//! This will make it easier to discover the API, as it shares a common prefix with the name of the trait.
358//!
359//! #### Methods with default implementations
360//! Methods with default implementations use _delegation by default_.
361//! This means that if a default-implementation-method gets called without having been mentioned in a clause, unimock delegates to its default implementation instead of inducing a panic.
362//! Quite often, a typical default implementation will itself delegate back to a _required_ method.
363//!
364//! This means that you have control over which part of the trait API you want to mock, the high level or the low level part.
365//!
366//! #### Associated types
367//! Associated types in traits may be specified using the `type` keyword in the unimock macro:
368//!
369//! ```rust
370//! # use unimock::*;
371//! #[unimock(api = TraitMock, type A = i32; type B = String;)]
372//! trait Trait {
373//!     type A;
374//!     type B;
375//! }
376//! ```
377//!
378//! Working with associated types in a mock environment like Unimock has its limitations.
379//! The nature of associated types is that there is one type per implementation, and there is only one mock implementation, so the type must be chosen carefully.
380//!
381//! #### Associated constants
382//! Associated constants in traits may be specified using the `const` keyword in the unimock macro:
383//!
384//! ```rust
385//! # use unimock::*;
386//! #[unimock(api = TraitMock, const FOO: i32 = 42;)]
387//! trait Trait {
388//!     const FOO: i32;
389//! }
390//! ```
391//!
392//! Just like with associated types in Unimock, associated constants have the limitation where there is one value of the const per implementation,
393//! and there is only one mock implementation, so the value must be chosen carefully.
394//!
395//!
396//! ## Project goals
397//! #### Use only safe Rust
398//! Unimock respects the memory safety and soundness provided by Rust.
399//! Sometimes this fact can lead to less than optimal ergonomics.
400//!
401//! For example, in order to use `.returns(value)`, the value must (generally) implement `Clone`, `Send`, `Sync` and `'static`.
402//! If it's not all of those things, the slightly longer `.answers(&|_| value)` can be used instead.
403//!
404//! #### Keep the amount of generated code to a minimum
405//! The unimock API is mainly built around generics and traits, instead of being macro-generated.
406//! Any mocking library will likely always require _some_ degree of introspective metaprogramming (like macros),
407//!   but doing too much of that is likely to become more confusing to users, as well as taking longer to compile.
408//! The `#[unimock]` macro does the minimal things to fill out a few simple trait impls, and that's it. There are no
409//! complex functions or structs that need to be generated.
410//!
411//! There is a downside to this approach, though.
412//! Rust generics aren't infinitely flexible,
413//!   so sometimes it's possible to misconfigure a mock in a way that the type system is unable to catch up front,
414//!   resulting in runtime (or rather, test-time) failures.
415//!
416//! All things considered, this tradedoff seems sound, because this is only testing, after all.
417//!
418//! #### Use nice, readable APIs
419//! Unimock's mocking API has been designed to read like natural english sentences.
420//!
421//! This was a fun design challenge, but it arguably also has some real value.
422//! It is assumed that code is quicker (and perhaps more fun) to read and write when it resembles real language.
423//!
424
425#![no_std]
426#![forbid(unsafe_code)]
427#![warn(missing_docs)]
428#![cfg_attr(feature = "unstable-doc-cfg", feature(doc_auto_cfg))]
429
430#[cfg(not(any(feature = "std", feature = "critical-section")))]
431compile_error!("At least one of the features `std` or `critical-section` must be set.");
432
433#[cfg(feature = "std")]
434extern crate std;
435
436#[doc(hidden)]
437pub mod alloc {
438    extern crate alloc;
439
440    pub use alloc::boxed::Box;
441    pub use alloc::collections::btree_map::Entry;
442    pub use alloc::collections::BTreeMap;
443    pub use alloc::collections::BTreeSet;
444    pub use alloc::format;
445    pub use alloc::rc::Rc;
446    pub use alloc::string::String;
447    pub use alloc::string::ToString;
448    pub use alloc::sync::Arc;
449    pub use alloc::vec;
450    pub use alloc::vec::Vec;
451}
452
453/// Builder pattern types used for defining mocked behaviour.
454pub mod build;
455
456/// Function outputs.
457pub mod output;
458
459/// Traits and types used for describing the properties of various mock types.
460pub mod property;
461
462/// Mock APIs for various crates.
463pub mod mock;
464
465/// APIs used by macros, etc
466#[doc(hidden)]
467pub mod private;
468
469#[doc(hidden)]
470pub mod value_chain;
471
472#[doc(hidden)]
473pub mod polonius {
474    pub use polonius_the_crab::exit_polonius as _exit;
475    pub use polonius_the_crab::polonius as _polonius;
476    pub use polonius_the_crab::polonius_return as _return;
477}
478
479#[doc(hidden)]
480mod default_impl_delegator;
481
482mod assemble;
483mod call_pattern;
484mod clause;
485mod counter;
486mod debug;
487mod error;
488mod eval;
489mod fn_mocker;
490mod mismatch;
491mod responder;
492mod state;
493mod teardown;
494
495use core::any::Any;
496use core::any::TypeId;
497use core::fmt::Debug;
498use core::panic::RefUnwindSafe;
499use core::panic::UnwindSafe;
500
501use once_cell::sync::OnceCell;
502
503use alloc::Box;
504use assemble::MockAssembler;
505use call_pattern::DynInputMatcher;
506use debug::TraitMethodPath;
507use output::Kind;
508use private::{DefaultImplDelegator, Matching};
509
510///
511/// Autogenerate mocks for all methods in the annotated traits, and `impl` it for [Unimock].
512///
513/// Mock generation happens by declaring a new [MockFn]-implementing struct for each method.
514///
515/// # Example
516/// ```rust
517/// use unimock::*;
518///
519/// #[unimock(api=Trait1Mock)]
520/// trait Trait1 {
521///     fn a(&self) -> i32;
522///     fn b(&self) -> i32;
523/// }
524///
525/// #[unimock]
526/// trait Trait2 {
527///     fn c(&self) -> i32;
528/// }
529///
530/// fn sum(obj: impl Trait1 + Trait2) -> i32 {
531///     obj.a() + obj.b() + obj.c()
532/// }
533///
534/// fn test() {
535///     // Unimock now implements both traits:
536///     sum(Unimock::new(())); // note: panics at runtime!
537///
538///     // Mock a single method (still panics, because all 3 must be mocked:):
539///     sum(Unimock::new(Trait1Mock::a.next_call(matching!()).returns(0)));
540/// }
541/// ```
542///
543/// # Unmocking
544/// _Unmocking_ of a mocked function means falling back to a true implementation.
545///
546/// A true implementation must be a standalone function, not part of a trait,
547/// where the first parameter is generic (a `self`-replacement), and the rest of the parameters are
548/// identical to [MockFn::Inputs]:
549///
550/// ```rust
551/// # use unimock::*;
552/// #[unimock(unmock_with=[my_original(self, a)])]
553/// trait DoubleNumber {
554///     fn double_number(&self, a: i32) -> i32;
555/// }
556///
557/// // The true implementation is a regular, generic function which performs number doubling!
558/// fn my_original<T>(_: T, a: i32) -> i32 {
559///     a * 2
560/// }
561/// ```
562///
563/// The unmock feature makes sense when the reason to define a mockable trait is _solely_ for the purpose of inversion-of-control at test-time:
564///   Release code need only one way to double a number.
565///
566/// Standalone functions enables arbitrarily deep integration testing in unimock-based application architectures.
567/// When unimock calls the true implementation, it inserts itself as the generic first parameter.
568/// When this parameter is bounded by traits, the original `fn` is given capabilities to call other APIs, though only indirectly.
569/// Each method invocation happening during a test will invisibly pass through unimock, resulting in a great level of control.
570/// Consider:
571///
572/// ```rust
573/// # use unimock::*;
574/// #[unimock(api=FactorialMock, unmock_with=[my_factorial(self, input)])]
575/// trait Factorial {
576///     fn factorial(&self, input: u32) -> u32;
577/// }
578///
579/// // will it eventually panic?
580/// fn my_factorial(f: &impl Factorial, input: u32) -> u32 {
581///     f.factorial(input - 1) * input
582/// }
583///
584/// assert_eq!(
585///     120,
586///     // well, not in the test, at least!
587///     Unimock::new(
588///         FactorialMock::factorial.stub(|each| {
589///             each.call(matching!((input) if *input <= 1)).returns(1_u32); // unimock controls the API call
590///             each.call(matching!(_)).applies_unmocked();
591///         })
592///     )
593///     .factorial(5)
594/// );
595/// ```
596///
597///
598/// # Arguments
599/// The unimock macro accepts a number of comma or colon-separated key-value configuration parameters:
600///
601/// * `#[unimock(api=#ident), ]`: Export a mocking API as a module with the given name
602/// * `#[unimock(api=[method1, method2, ..], )]`: Instead of generating a module, generate top-level mock structs for the methods in the trait,
603///     with the names of those structs passed with array-like syntax in the same order as the methods appear in the trait definition.
604/// * `#[unimock(unmock_with=[a, b, _], )]`: Given there are e.g. 3 methods in the annotated trait, uses the given paths as unmock implementations.
605///     The functions are assigned to the methods in the same order as the methods are listed in the trait.
606///     A value of `_` means _no unmock support_ for that method.
607/// * `#[unimock(prefix=path, )]`: Makes unimock use a different path prefix than `::unimock`, in case the crate has been re-exported through another crate.
608/// * `#[unimock(type #ident = #assoc; )]`: Specify the value of the associated type `#ident`.
609pub use unimock_macros::unimock;
610
611///
612/// Macro to ease _call pattern_ matching for function arguments.
613/// The macro produces a closure reference expression suitable for passing to [`some_call`](MockFn::some_call), etc.
614///
615/// Its syntax takes inspiration from [std::matches] and works similarly, except that the value to match can be removed as a macro argument, since it is instead received as the closure argument.
616///
617/// Two main forms of syntaxes are supported:
618/// 1. Simple form, e.g. `matching!(1, 2)`: A single tuple pattern to match the entire input tuple.
619/// 2. Disjunctive form, e.g. `matching!((1, 2) | (3, 4) | (5, 6))`: Each operand to the `|` sigil is a standalone tuple pattern, with the behaviour that the complete pattern is matching if at least one of the standalone tuple patterns are matching.
620///
621/// `if` guards are also supported.
622///
623/// # Example
624///
625/// ```rust
626/// use unimock::*;
627/// #[unimock(api=Mock)]
628/// trait Trait {
629///     fn one(&self, a: &str);
630///     fn three(&self, a: &str, b: &str, c: &str);
631/// }
632///
633/// fn one_str() {
634///     fn args(_: &dyn Fn(&mut unimock::private::Matching<Mock::one>)) {}
635///     args(matching!("a"));
636/// }
637///
638/// fn three_strs() {
639///     fn args(_: &dyn Fn(&mut unimock::private::Matching<Mock::three>)) {}
640///     args(matching!("a", _, "c" | "C"));
641///     args(matching!(("a", "b", "c") | ("d", "e", "f" | "F")));
642///     args(matching!(("a", b, "c") if b.contains("foo")));
643/// }
644/// ```
645///
646/// # Auto-"coercions"
647///
648/// Since the input expression being matched is generated by the macro,
649///   you would normally suffer from the following problem when matching some non-`&str` function input:
650///
651/// ```compile_fail
652/// # fn test() -> bool {
653/// let string = String::new();
654/// match &string {
655///     "foo" => true, // expected struct `String`, found `str`
656///     _ => false,
657/// # }
658/// }
659/// ```
660///
661/// To help ergonomics, the `matching` macro recognizes certain literals used in the patterns,
662///   and performs appropriate type conversion at the correct places:
663///
664/// ```rust
665/// # use unimock::*;
666/// pub struct Newtype(String);
667///
668/// #[unimock(api=Mock)]
669/// trait Trait {
670///     fn interesting_args(
671///         &self,
672///         a: String,
673///         b: std::borrow::Cow<'static, str>,
674///         c: Newtype,
675///         d: i32
676///     );
677/// }
678///
679/// fn args(_: &dyn Fn(&mut unimock::private::Matching<Mock::interesting_args>)) {}
680///
681/// args(matching! {("a", _, "c", _) | (_, "b", _, 42)});
682///
683/// // Newtype works by implementing the following:
684/// impl std::convert::AsRef<str> for Newtype {
685///     fn as_ref(&self) -> &str {
686///         self.0.as_str()
687///     }
688/// }
689/// ```
690///
691/// # Matching using `Eq`
692///
693/// Since patterns in Rust are somewhat limited, the matching macro also supports matching using [Eq](std::cmp::Eq).
694///
695/// A single argument changes to `Eq` matching by enclosing that argument within `eq!(_)` or `ne!(_)`:
696///
697/// ```rust
698/// # use unimock::*;
699/// #[derive(Eq, PartialEq)]
700/// pub struct Data(Vec<i32>);
701///
702/// #[unimock(api=Mock)]
703/// trait Trait {
704///     fn func(&self, arg: Data) -> &str;
705/// }
706///
707/// let u = Unimock::new((
708///     Mock::func
709///         .each_call(matching!(eq!(&Data(vec![]))))
710///         .returns("empty"),
711///     Mock::func
712///         .each_call(matching!(ne!(&Data(vec![0]))))
713///         .returns("non-zero"),
714///     Mock::func
715///         .each_call(matching!(_))
716///         .returns("other")
717/// ));
718///
719/// assert_eq!("empty", <Unimock as Trait>::func(&u, Data(vec![])));
720/// assert_eq!("non-zero", <Unimock as Trait>::func(&u, Data(vec![42])));
721/// assert_eq!("other", <Unimock as Trait>::func(&u, Data(vec![0])));
722/// ```
723///
724pub use unimock_macros::matching;
725
726#[derive(Clone, Copy)]
727enum FallbackMode {
728    Error,
729    Unmock,
730}
731
732/// A type whose purpose is to provide mocked behaviour for the traits that it implements.
733///
734/// All traits implemented by Unimock can be considered mock implementations, except _marker traits_, [Clone] and [Drop].
735///
736/// The mock configuration is specified up front, as a constructor argument in the form of a simple or compound [Clause].
737/// After instantiation, the unimock configuration is immutable.
738///
739/// Unimock implements [Send](Send) and [Sync](Sync), and is therefore thread safe.
740///
741/// Unimock is meant to be used as a testing utility.
742/// Using it for other purposes is not recommended.
743///
744/// ## Clone semantics
745/// Calling [`clone`](Clone::clone) on unimock creates a derived object which shares internal state with the original.
746///
747/// Unimock runs post-test verifications automatically upon [`drop`](Drop::drop) (it is a RAII utility).
748/// Interaction verifications should be performed only after all expected interactions have completed.
749/// Because of this, only the _original instance_ will run any verifications upon being dropped,
750///     and when dropping the original instance, _it is an error_ if there are derived objects still alive.
751/// In a typical testing context, this scenario usually means that a spawned thread (that owns a derived Unimock) has escaped the test.
752/// Unimock will panic with an appropriate message if this is detected.
753///
754/// This detection is usually reliable.
755/// Unimock will also induce a panic if the original instance gets dropped in a thread that does not equal the creator thread.
756/// Therefore, Unimock should always be cloned before sending off to another thread.
757///
758pub struct Unimock {
759    shared_state: alloc::Arc<state::SharedState>,
760
761    // A value chain for "dumping" owned return values that
762    // a function signature needs to *borrow* instead.
763    value_chain: value_chain::ValueChain,
764
765    default_impl_delegator_cell: OnceCell<alloc::Box<DefaultImplDelegator>>,
766
767    original_instance: bool,
768    torn_down: bool,
769    verify_in_drop: bool,
770
771    // Hack when running in `no_std` mode.
772    // There is a problem with panic-in-drop if the thread is already panicking.
773    // in `no_std` there is no way to check that the current thread is panicking.
774    // Instead unimock can remember that it induced a panic during mock calls.
775    // But this only works when it's _unimock_ that induced the panic.
776    // E.g. a failing `assert!` failing will still break the test, with bad debug output.
777    #[cfg(not(feature = "std"))]
778    panicked: private::MutexIsh<bool>,
779}
780
781impl Unimock {
782    /// Construct a unimock instance which strictly adheres to the description in the passed [Clause].
783    ///
784    /// Every call hitting the instance must be declared in advance as a clause, or else panic will ensue.
785    ///
786    /// # Example
787    /// ```rust
788    /// # use unimock::*;
789    /// #[unimock(api=TraitMock)]
790    /// trait Trait {
791    ///     fn foo(&self) -> &'static str;
792    /// }
793    ///
794    /// let mocked = Unimock::new(TraitMock::foo.some_call(matching!()).returns("mocked"));
795    ///
796    /// assert_eq!("mocked", mocked.foo());
797    /// ```
798    #[track_caller]
799    pub fn new(setup: impl Clause) -> Self {
800        Self::from_assembler(
801            assemble::MockAssembler::try_from_clause(setup),
802            FallbackMode::Error,
803        )
804    }
805
806    /// Construct a unimock instance using _partial mocking_.
807    ///
808    /// In a partially mocked environment, every clause acts as an override over the default behaviour, which is to hit "real world" code.
809    /// Trait methods which support the `unmock` feature get this behaviour automatically in a partial mock, unless explicitly overridden in the passed [Clause].
810    ///
811    /// Methods that cannot be unmocked still need to be explicitly mocked with a clause.
812    ///
813    /// # Example
814    /// ```rust
815    /// # use unimock::*;
816    /// #[unimock(api=TraitMock, unmock_with=[real_foo])]
817    /// trait Trait {
818    ///     fn foo(&self) -> &'static str;
819    /// }
820    ///
821    /// fn real_foo(_: &impl std::any::Any) -> &'static str {
822    ///     "real thing"
823    /// }
824    ///
825    /// // A partial mock with no overrides:
826    /// assert_eq!("real thing", Unimock::new_partial(()).foo());
827    ///
828    /// // A partial mock that overrides the behaviour of `Trait::foo`:
829    /// let clause = TraitMock::foo.next_call(matching!()).returns("mocked");
830    /// assert_eq!("mocked", Unimock::new_partial(clause).foo());
831    /// ```
832    #[track_caller]
833    pub fn new_partial(setup: impl Clause) -> Self {
834        Self::from_assembler(
835            assemble::MockAssembler::try_from_clause(setup),
836            FallbackMode::Unmock,
837        )
838    }
839
840    /// Turn off auto-verification within [Drop::drop].
841    ///
842    /// The current use case for this is `[no_std]`. In `[no_std]` there is no thread API,
843    /// and therefore no way to check if the current thread is already panicking.
844    ///
845    /// Leaving verify-in-drop on in such circumstances (in the context of panicking unit tests)
846    /// easily leads to double panics, which are quite hard to debug.
847    pub fn no_verify_in_drop(mut self) -> Self {
848        if !self.original_instance {
849            panic!("Called no_verify_on_drop() on a cloned instance. Configure the original instance instead.");
850        }
851
852        self.verify_in_drop = false;
853        self
854    }
855
856    /// Explicitly verify this unimock instance.
857    ///
858    /// There is no need to do this explicitly unless [Self::no_verify_in_drop] has been called.
859    pub fn verify(mut self) {
860        if !self.original_instance {
861            panic!("Called verify() on a cloned instance. Verify the original instance instead.");
862        }
863
864        teardown::teardown_panic(&mut self);
865    }
866
867    /// Convert the given value into a reference.
868    ///
869    /// This can be useful when returning references from `answers` functions.
870    pub fn make_ref<T: Send + Sync + 'static>(&self, value: T) -> &T {
871        self.value_chain.push(value)
872    }
873
874    /// Convert the given value into a mutable reference.
875    ///
876    /// This can be useful when returning mutable references from `answers` functions.
877    pub fn make_mut<T: Send + Sync + 'static>(&mut self, value: T) -> &mut T {
878        self.value_chain.push_mut(value)
879    }
880}
881
882#[cfg(feature = "fragile")]
883impl Unimock {
884    /// Convert the given value into a reference.
885    ///
886    /// The value does not need to implement [Send].
887    /// Unimock will panic/abort if the instance is sent to another thread after calling this.
888    pub fn make_fragile_ref<T: 'static>(&self, value: T) -> &T {
889        self.value_chain.push_fragile(value)
890    }
891
892    /// Convert the given value into a mutable reference.
893    ///
894    /// The value does not need to implement [Send].
895    /// Unimock will panic/abort if the instance is sent to another thread after calling this.
896    pub fn make_fragile_mut<T: 'static>(&mut self, value: T) -> &mut T {
897        self.value_chain.push_fragile_mut(value)
898    }
899}
900
901impl Unimock {
902    #[track_caller]
903    fn from_assembler(
904        assembler_result: Result<MockAssembler, alloc::String>,
905        fallback_mode: FallbackMode,
906    ) -> Self {
907        let fn_mockers = match assembler_result {
908            Ok(assembler) => assembler.finish(),
909            Err(error) => panic!("{error}"),
910        };
911
912        Self {
913            shared_state: alloc::Arc::new(state::SharedState::new(fn_mockers, fallback_mode)),
914            value_chain: Default::default(),
915            default_impl_delegator_cell: Default::default(),
916            original_instance: true,
917            torn_down: false,
918            verify_in_drop: true,
919            #[cfg(not(feature = "std"))]
920            panicked: private::MutexIsh::new(false),
921        }
922    }
923
924    #[track_caller]
925    fn handle_error<T>(&self, result: Result<T, error::MockError>) -> T {
926        match result {
927            Ok(value) => value,
928            Err(error) => self.induce_panic(error),
929        }
930    }
931
932    fn induce_panic(&self, error: error::MockError) -> ! {
933        #[cfg(not(feature = "std"))]
934        {
935            self.panicked.locked(|panicked| {
936                *panicked = true;
937            });
938        }
939
940        let msg = alloc::format!("{error}");
941
942        self.shared_state.panic_reasons.locked(move |reasons| {
943            reasons.push(error);
944        });
945
946        panic!("{msg}")
947    }
948}
949
950impl Clone for Unimock {
951    fn clone(&self) -> Unimock {
952        Unimock {
953            shared_state: self.shared_state.clone(),
954            value_chain: Default::default(),
955            default_impl_delegator_cell: Default::default(),
956            original_instance: false,
957            torn_down: false,
958            verify_in_drop: self.verify_in_drop,
959            #[cfg(not(feature = "std"))]
960            panicked: private::MutexIsh::new(false),
961        }
962    }
963}
964
965impl AsRef<DefaultImplDelegator> for Unimock {
966    fn as_ref(&self) -> &DefaultImplDelegator {
967        let delegator = self
968            .default_impl_delegator_cell
969            .get_or_init(|| alloc::Box::new(DefaultImplDelegator::__from_unimock(self.clone())));
970        delegator.as_ref()
971    }
972}
973
974impl AsMut<DefaultImplDelegator> for Unimock {
975    fn as_mut(&mut self) -> &mut DefaultImplDelegator {
976        self.default_impl_delegator_cell
977            .get_or_init(|| alloc::Box::new(DefaultImplDelegator::__from_unimock(self.clone())));
978        self.default_impl_delegator_cell.get_mut().unwrap()
979    }
980}
981
982impl UnwindSafe for Unimock {}
983impl RefUnwindSafe for Unimock {}
984
985impl Drop for Unimock {
986    fn drop(&mut self) {
987        if self.torn_down {
988            return;
989        }
990
991        if self.verify_in_drop {
992            teardown::teardown_panic(self);
993        }
994    }
995}
996
997/// This implementation of `Termination` may be used for returning a Unimock instance as the result of a test:
998///
999/// ```rust
1000/// # use unimock::*;
1001/// #[test]
1002/// fn test() -> Unimock {
1003///     Unimock::new(())
1004/// }
1005/// ```
1006///
1007/// This enables a more functional test style, instead of relying on panic-in-drop.
1008///
1009/// Calling `report` prevents unimock from panicking later (in drop) on failed verifications, so _use with care_.
1010///
1011/// # Mocking
1012/// The `mock-std` feature also enables mocking of this trait through [mock::std::process::TerminationMock].
1013/// This trait mock is partial by default: Unless explicitly mocked, it behaves as specified above.
1014#[cfg(feature = "std")]
1015impl std::process::Termination for Unimock {
1016    #[cfg(feature = "mock-std")]
1017    fn report(mut self) -> std::process::ExitCode {
1018        use private::Eval;
1019
1020        match private::eval::<mock::std::process::TerminationMock::report>(&self, ()) {
1021            Eval::Return(output) => output,
1022            Eval::Continue(private::Continuation::Unmock, _) => {
1023                teardown::teardown_report(&mut self)
1024            }
1025            Eval::Continue(cont, _) => cont.report(&self),
1026        }
1027    }
1028
1029    #[cfg(not(feature = "mock-std"))]
1030    fn report(mut self) -> std::process::ExitCode {
1031        teardown::teardown_report(&mut self)
1032    }
1033}
1034
1035///
1036/// The main trait used for unimock configuration.
1037///
1038/// `MockFn` describes functional APIs that may be called via dispatch, a.k.a. _Inversion of Control_.
1039/// Virtuality should be regarded as as test-time virtuality: A virtual function is either the real deal OR it is mocked.
1040///
1041/// In Rust, the most convenient way to perform a virtualized/dispatched function call is to call a trait method.
1042///
1043/// `MockFn` only provides metadata about an API, it is not directly callable.
1044///
1045/// As this is a trait itself, it needs to be implemented to be useful. Methods are not types,
1046/// so we cannot implement `MockFn` for those. But a surrogate type can be introduced:
1047///
1048/// ```rust
1049/// trait MockMe {
1050///     fn method(&self);
1051/// }
1052///
1053/// // The method can be referred to via the following empty surrogate struct:
1054/// mod MockMeMock {
1055///     pub struct method;
1056/// }
1057///
1058/// /* impl MockFn for MockMeMock::method ... */
1059/// ```
1060///
1061pub trait MockFn: Sized + 'static {
1062    /// The inputs to a mockable function.
1063    ///
1064    /// * For a function with no parameters, the type should be the empty tuple `()`.
1065    /// * For a function with 1 parameter `T`, the type should be `T`.
1066    /// * For a function with N parameters, the type should be the tuple `(T1, T2, ..)`.
1067    type Inputs<'i>;
1068
1069    /// A type that describes how the mocked function responds.
1070    ///
1071    /// The [Kind] trait describes a type used internally to store a response value.
1072    ///
1073    /// The response value is Unimock's internal representation of the function's return value between two points it time:
1074    /// 1. The user specifies it upfront as part of a Clause.
1075    /// 2. The conversion of this value into the mocked function's final output value.
1076    type OutputKind: output::Kind;
1077
1078    /// The function type used for function application on a call pattern.
1079    type AnswerFn: ?Sized + Send + Sync;
1080
1081    /// Static information about the mocked method
1082    fn info() -> MockFnInfo;
1083
1084    /// Compute some debug representation of the inputs.
1085    #[allow(unused)]
1086    fn debug_inputs(inputs: &Self::Inputs<'_>) -> alloc::Box<[Option<alloc::String>]> {
1087        alloc::Box::new([])
1088    }
1089
1090    /// Create a stubbing clause by grouping calls.
1091    ///
1092    /// A stub sets up call patterns on a single function, that can be matched in any order.
1093    ///
1094    /// For exact order verification, reach for [MockFn::next_call] instead.
1095    #[track_caller]
1096    fn stub<E>(self, each_fn: E) -> build::Each<Self>
1097    where
1098        E: FnOnce(&mut build::Each<Self>),
1099    {
1100        let mut each = build::Each::new();
1101        each_fn(&mut each);
1102        each
1103    }
1104
1105    /// Define a stub-like call pattern directly on this [MockFn].
1106    ///
1107    /// This is a shorthand to avoid calling [MockFn::stub] if there is only one call pattern
1108    /// that needs to be specified on this MockFn.
1109    ///
1110    /// As the method name suggests, this will not only configure mock behaviour, but also functions as an assertion that the call _must happen_.
1111    ///
1112    /// This call pattern variant supports return values that do not implement [Clone],
1113    /// therefore the call pattern can only be matched a single time.
1114    fn some_call(
1115        self,
1116        matching_fn: &dyn Fn(&mut Matching<Self>),
1117    ) -> build::DefineResponse<'static, Self, property::InAnyOrder> {
1118        build::DefineResponse::with_owned_builder(
1119            DynInputMatcher::from_matching_fn(matching_fn),
1120            fn_mocker::PatternMatchMode::InAnyOrder,
1121            property::InAnyOrder,
1122        )
1123    }
1124
1125    /// Define a stub-like call pattern directly on this [MockFn].
1126    ///
1127    /// This is a shorthand to avoid calling [MockFn::stub] if there is only one call pattern
1128    /// that needs to be specified on this MockFn.
1129    ///
1130    /// This variant is specialized for functions called multiple times.
1131    fn each_call(
1132        self,
1133        matching_fn: &dyn Fn(&mut Matching<Self>),
1134    ) -> build::DefineMultipleResponses<'static, Self, property::InAnyOrder> {
1135        build::DefineMultipleResponses::with_owned_builder(
1136            DynInputMatcher::from_matching_fn(matching_fn),
1137            fn_mocker::PatternMatchMode::InAnyOrder,
1138            property::InAnyOrder,
1139        )
1140    }
1141
1142    /// Initiate a call pattern builder intended to be used as a [Clause] with exact order verification.
1143    ///
1144    /// The chain of `next_call` call-patterns _must_ be matched (called) in the exact same order as they appear
1145    /// in the clause tuple(s). Unimock will fail its post-verification step if not.
1146    ///
1147    /// The `next_call` call patterns may be interspersed with other call patterns that do not engage in exact order verification,
1148    /// as long as these are not mixed for the same trait method.
1149    ///
1150    /// # Example
1151    /// ```rust
1152    /// # use unimock::*;
1153    /// #[unimock(api=FooMock)]
1154    /// trait Foo {
1155    ///     fn foo(&self, input: i32);
1156    /// }
1157    ///
1158    /// #[unimock(api=BarMock)]
1159    /// trait Bar {
1160    ///     fn bar(&self);
1161    /// }
1162    ///
1163    /// let u = Unimock::new((
1164    ///     FooMock::foo
1165    ///         .next_call(matching!(1))
1166    ///         .returns(()),
1167    ///     BarMock::bar
1168    ///         .next_call(matching!())
1169    ///         .returns(()),
1170    ///     FooMock::foo
1171    ///         .next_call(matching!(2))
1172    ///         .returns(())
1173    /// ));
1174    ///
1175    /// // the calls must happen in this order:
1176    /// u.foo(1);
1177    /// u.bar();
1178    /// u.foo(2);
1179    /// ```
1180    fn next_call(
1181        self,
1182        matching_fn: &dyn Fn(&mut Matching<Self>),
1183    ) -> build::DefineResponse<'static, Self, property::InOrder> {
1184        build::DefineResponse::with_owned_builder(
1185            DynInputMatcher::from_matching_fn(matching_fn),
1186            fn_mocker::PatternMatchMode::InOrder,
1187            property::InOrder,
1188        )
1189    }
1190}
1191
1192/// Static information about a method
1193#[derive(Clone, Copy)]
1194pub struct MockFnInfo {
1195    type_id: TypeId,
1196    path: TraitMethodPath,
1197    has_default_impl: bool,
1198    partial_by_default: bool,
1199}
1200
1201impl MockFnInfo {
1202    /// Construct a new MockFnInfo.
1203    pub fn new<F: MockFn>() -> Self {
1204        Self::with_type_id(TypeId::of::<F>())
1205    }
1206
1207    fn with_type_id(type_id: TypeId) -> Self {
1208        Self {
1209            type_id,
1210            path: TraitMethodPath::default(),
1211            has_default_impl: false,
1212            partial_by_default: false,
1213        }
1214    }
1215
1216    /// Set the path of the method
1217    pub const fn path(self, path: &'static [&'static str; 2]) -> Self {
1218        Self {
1219            path: TraitMethodPath::from_path(path),
1220            ..self
1221        }
1222    }
1223
1224    /// Mark the method as being a default implementation
1225    pub const fn default_impl(self) -> Self {
1226        Self {
1227            has_default_impl: true,
1228            ..self
1229        }
1230    }
1231}
1232
1233/// A marker type used when Unimock is unable to represent the user's type.
1234#[derive(Debug)]
1235pub struct Impossible;
1236
1237/// A clause represents a recipe for creating a unimock instance.
1238///
1239/// Clauses may be _terminal_ (basic) and _non-terminal_ (composite).
1240/// Terminal clauses are created with unimock's builder API, non-terminals/composites are created by grouping other clauses in tuples.
1241///
1242/// ```rust
1243/// use unimock::*;
1244/// #[unimock(api=FooMock)]
1245/// trait Foo {
1246///     fn foo(&self, i: i32) -> i32;
1247/// }
1248///
1249/// #[unimock(api=BarMock)]
1250/// trait Bar {
1251///     fn bar(&self, i: i32) -> i32;
1252/// }
1253///
1254/// #[unimock(api=BazMock)]
1255/// trait Baz {
1256///     fn baz(&self, i: i32) -> i32;
1257/// }
1258///
1259/// // A reusable function returning a composite clause from two terminals, by tupling them:
1260/// fn setup_foo_and_bar() -> impl Clause {
1261///     (
1262///         FooMock::foo.some_call(matching!(_)).returns(1),
1263///         BarMock::bar.some_call(matching!(_)).returns(2),
1264///     )
1265/// }
1266///
1267/// // Basic and composite clauses may be recombined again to make new tuples:
1268/// let mocked = Unimock::new((
1269///     setup_foo_and_bar(),
1270///     BazMock::baz.some_call(matching!(_)).returns(3),
1271/// ));
1272/// assert_eq!(6, mocked.foo(0) + mocked.bar(0) + mocked.baz(0));
1273/// ```
1274#[must_use]
1275pub trait Clause {
1276    #[doc(hidden)]
1277    fn deconstruct(self, sink: &mut dyn clause::term::Sink) -> Result<(), alloc::String>;
1278}
1279
1280type AnyBox = Box<dyn Any + Send + Sync + 'static>;