Skip to main content

sofie_values/fixture/
calls.rs

1use std::sync::{Mutex, MutexGuard};
2
3use sofie_core::{Error, Result, unpoisoned};
4
5use super::{Fixture, Seed};
6
7#[derive(Default)]
8pub struct Calls {
9    state: Mutex<State>,
10}
11
12#[derive(Default)]
13struct State {
14    made: Vec<&'static str>,
15    failing: Vec<&'static str>,
16    seed: Seed,
17}
18
19impl Calls {
20    pub fn answer<T: Fixture>(&self, method: &'static str) -> Result<T> {
21        let mut state = self.state();
22        state.made.push(method);
23        if state.failing.contains(&method) {
24            return Err(Error::Unavailable(format!("the fake fails `{method}`")));
25        }
26        Ok(T::fixture(&mut state.seed))
27    }
28
29    pub fn value<T: Fixture>(&self, method: &'static str) -> T {
30        let mut state = self.state();
31        state.made.push(method);
32        T::fixture(&mut state.seed)
33    }
34
35    pub fn fail(&self, method: &'static str) {
36        self.state().failing.push(method);
37    }
38
39    #[must_use]
40    pub fn made(&self) -> Vec<&'static str> {
41        self.state().made.clone()
42    }
43
44    fn state(&self) -> MutexGuard<'_, State> {
45        unpoisoned::lock(&self.state)
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn records_each_call_and_fails_the_methods_it_is_told_to() {
55        let calls = Calls::default();
56
57        let answered: Result<i64> = calls.answer("find");
58        calls.fail("find");
59        let failed: Result<i64> = calls.answer("find");
60
61        assert!(answered.is_ok());
62        assert!(matches!(failed, Err(Error::Unavailable(_))));
63        assert_eq!(calls.made(), ["find", "find"]);
64    }
65}