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>;