mry/rule/
behavior.rs

1use std::fmt::Debug;
2
3use parking_lot::Mutex;
4
5#[derive(Debug, PartialEq)]
6pub(crate) enum Output<O> {
7    CallsRealImpl,
8    /// called once already called
9    ErrorCalledOnce,
10    Found(O),
11}
12
13/// Behavior of mock
14pub enum Behavior<I, O> {
15    /// Behaves with a function
16    Function {
17        clone: fn(&I) -> I,
18        call: Box<dyn FnMut(I) -> O + Send + 'static>,
19    },
20    /// Returns a constant value
21    Const(Mutex<Box<dyn Iterator<Item = O> + Send + 'static>>),
22    /// Once
23    Once(Mutex<Option<O>>),
24    /// Calls real implementation instead of mock
25    CallsRealImpl,
26}
27
28impl<I: Debug, O: Debug> std::fmt::Debug for Behavior<I, O> {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        match self {
31            Self::Function { .. } => f.debug_tuple("Function(_)").finish(),
32            Self::Const(cons) => f
33                .debug_tuple("Const")
34                .field(&cons.lock().next().unwrap())
35                .finish(),
36            Self::Once(once) => f
37                .debug_tuple("Once")
38                .field(&once.lock().as_ref().unwrap())
39                .finish(),
40            Self::CallsRealImpl => write!(f, "CallsRealImpl"),
41        }
42    }
43}
44
45impl<I, O> Behavior<I, O> {
46    pub(crate) fn called(&mut self, input: &I) -> Output<O> {
47        match self {
48            Behavior::Function { clone, call } => Output::Found(call(clone(input))),
49            Behavior::Const(cons) => Output::Found(cons.get_mut().next().unwrap()),
50            Behavior::Once(once) => {
51                if let Some(ret) = once.lock().take() {
52                    Output::Found(ret)
53                } else {
54                    Output::ErrorCalledOnce
55                }
56            }
57            Behavior::CallsRealImpl => Output::CallsRealImpl,
58        }
59    }
60}
61
62mry_macros::create_behaviors!();
63
64#[cfg(test)]
65mod tests {
66    use std::iter::repeat;
67
68    use super::*;
69
70    #[test]
71    fn test_assert_send() {
72        fn assert_send<T: Send>() {}
73        assert_send::<Behavior<(), ()>>();
74    }
75
76    #[test]
77    fn function() {
78        assert_eq!(
79            Behavior::Function {
80                call: Box::new(|()| "aaa"),
81                clone: Clone::clone
82            }
83            .called(&()),
84            Output::Found("aaa")
85        );
86    }
87
88    #[test]
89    fn const_value() {
90        assert_eq!(
91            Behavior::Const(Mutex::new(Box::new(repeat("aaa")))).called(&()),
92            Output::Found("aaa")
93        );
94    }
95
96    #[test]
97    fn calls_real_impl() {
98        assert_eq!(
99            Behavior::<_, ()>::CallsRealImpl.called(&()),
100            Output::CallsRealImpl
101        );
102    }
103
104    #[test]
105    fn debug_calls_real_impl() {
106        assert_eq!(
107            format!("{:?}", Behavior::<u8, u8>::CallsRealImpl),
108            "CallsRealImpl".to_string()
109        )
110    }
111
112    #[test]
113    fn debug_const() {
114        assert_eq!(
115            format!(
116                "{:?}",
117                Behavior::<u8, u8>::Const(Mutex::new(Box::new(repeat(3))))
118            ),
119            "Const(3)".to_string()
120        )
121    }
122
123    #[test]
124    fn debug_function() {
125        assert_eq!(
126            format!(
127                "{:?}",
128                Behavior::<u8, u8>::Function {
129                    clone: Clone::clone,
130                    call: Box::new(|a| a)
131                }
132            ),
133            "Function(_)".to_string()
134        )
135    }
136}