faux/
mock.rs

1pub mod stub;
2
3mod store;
4mod unchecked;
5
6use std::{
7    fmt::{self, Formatter},
8    sync::Mutex,
9};
10
11pub use self::{store::Store, stub::Stub};
12
13/// A function mock
14///
15/// Stores information about a mock, such as its stubs, with its
16/// inputs and output typed.
17pub struct Mock<'stub, I, O> {
18    fn_name: &'static str,
19    stubs: Vec<Mutex<Stub<'stub, I, O>>>,
20}
21
22impl<'stub, I, O> Mock<'stub, I, O> {
23    /// Creates an empty mock
24    pub fn new(fn_name: &'static str) -> Self {
25        Self {
26            fn_name,
27            stubs: vec![],
28        }
29    }
30
31    /// Attempts to invoke the mock
32    ///
33    /// Checks the given input against the stored stubs, invoking the
34    /// first stub whose invocation matcher suceeds for the
35    /// inputs. The stubs are checked in reverse insertion order such
36    /// that the last inserted stub is the first attempted
37    /// one. Returns an error if no stub is found for the given input.
38    pub fn call(&self, mut input: I) -> Result<O, InvocationError> {
39        let mut errors = vec![];
40
41        for stub in self.stubs.iter().rev() {
42            match stub.lock().unwrap().call(input) {
43                Err((i, e)) => {
44                    errors.push(e);
45                    input = i
46                }
47                Ok(o) => return Ok(o),
48            }
49        }
50
51        Err(if errors.is_empty() {
52            InvocationError::NeverStubbed
53        } else {
54            InvocationError::Stub(errors)
55        })
56    }
57
58    /// Adds a new stub for the mocked function
59    pub fn add_stub(&mut self, stub: Stub<'stub, I, O>) {
60        self.stubs.push(Mutex::new(stub))
61    }
62
63    pub fn name(&self) -> &'static str {
64        self.fn_name
65    }
66}
67
68#[derive(Debug)]
69pub enum InvocationError {
70    NeverStubbed,
71    Stub(Vec<stub::Error>),
72}
73
74impl<I, O> fmt::Debug for Mock<'_, I, O> {
75    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
76        f.debug_struct("Mock").field("stubs", &self.stubs).finish()
77    }
78}