1mod log;
2use std::{iter::repeat, sync::Arc};
3
4pub use log::*;
5
6use parking_lot::Mutex;
7
8use crate::{times::Times, Behavior, Matcher, MockableRet, Output, Rule};
9
10pub struct Mock<I, O> {
11 pub name: &'static str,
12 pub log: Logs<I>,
13 rules: Vec<Rule<I, O>>,
14}
15
16impl<I, O> Mock<I, O> {
17 pub fn new(name: &'static str) -> Self {
18 Self {
19 name,
20 log: Default::default(),
21 rules: Default::default(),
22 }
23 }
24}
25
26impl<I, O> Mock<I, O> {
27 pub(crate) fn returns_with(
28 &mut self,
29 matcher: Arc<Mutex<Matcher<I>>>,
30 behavior: Behavior<I, O>,
31 ) {
32 self.rules.push(Rule { matcher, behavior });
33 }
34
35 pub(crate) fn returns_once(&mut self, matcher: Arc<Mutex<Matcher<I>>>, ret: O) {
36 self.returns_with(matcher, Behavior::Once(Mutex::new(Some(ret))))
37 }
38
39 pub(crate) fn calls_real_impl(&mut self, matcher: Arc<Mutex<Matcher<I>>>) {
40 self.rules.push(Rule {
41 matcher,
42 behavior: Behavior::CallsRealImpl,
43 })
44 }
45}
46
47impl<I, O> Mock<I, O> {
48 #[track_caller]
49 pub(crate) fn assert_called(&self, matcher: &Matcher<I>, times: Times) {
50 self.log.assert_called(self.name, matcher, times);
51 }
52
53 pub(crate) fn record_call(&mut self, input: Arc<Mutex<I>>) {
54 self.log.push(input);
55 }
56}
57
58impl<I, O> Mock<I, O> {
59 #[track_caller]
60 pub(crate) fn find_mock_output(&mut self, input: &I) -> Option<O> {
61 for rule in &mut self.rules {
62 if !rule.matches(input) {
63 continue;
64 }
65 return match rule.call_behavior(input) {
66 Output::Found(output) => Some(output),
67 Output::CallsRealImpl => None,
68 Output::ErrorCalledOnce => {
69 panic!("{} was called more than once", self.name)
70 }
71 };
72 }
73 panic!("mock not found for {}", self.name)
74 }
75}
76
77impl<I, O> Mock<I, O>
78where
79 O: MockableRet + Clone,
80{
81 pub(crate) fn returns(&mut self, matcher: Arc<Mutex<Matcher<I>>>, ret: O) {
82 self.returns_with(matcher, Behavior::Const(Mutex::new(Box::new(repeat(ret)))))
83 }
84}
85
86#[cfg(test)]
87mod test {
88 use super::*;
89 use crate::Behavior1;
90
91 #[test]
92 fn returns_with() {
93 let mut mock = Mock::<(usize,), String>::new("a");
94 mock.returns_with(
95 Matcher::any().wrapped(),
96 Behavior1::from(|a| "a".repeat(a)).into(),
97 );
98
99 assert_eq!(mock.find_mock_output(&(3,)), "aaa".to_string().into());
100 }
101
102 #[test]
103 fn returns() {
104 let mut mock = Mock::<(usize,), String>::new("a");
105 mock.returns(Matcher::any().wrapped(), "a".repeat(3));
106
107 assert_eq!(mock.find_mock_output(&(3,)), "aaa".to_string().into());
108
109 assert_eq!(mock.find_mock_output(&(3,)), "aaa".to_string().into());
111 }
112
113 #[test]
114 #[should_panic(expected = "mock not found for a")]
115 fn returns_with_never() {
116 let mut mock = Mock::<(usize,), String>::new("a");
117 mock.returns_with(
118 Matcher::never().wrapped(),
119 Behavior1::from(|a| "a".repeat(a)).into(),
120 );
121
122 mock.find_mock_output(&(3,));
123 }
124
125 #[test]
126 fn returns_with_always() {
127 let mut mock = Mock::<(usize,), String>::new("a");
128 mock.returns_with(
129 Matcher::any().wrapped(),
130 Behavior1::from(|a| "a".repeat(a)).into(),
131 );
132
133 assert_eq!(mock.find_mock_output(&(3,)), "aaa".to_string().into());
134 }
135
136 #[test]
137 #[should_panic(expected = "mock not found for a")]
138 fn returns_never() {
139 let mut mock = Mock::<(usize,), String>::new("a");
140 mock.returns(Matcher::never().wrapped(), "a".repeat(3));
141
142 mock.find_mock_output(&(3,));
143 }
144
145 #[test]
146 fn returns_always() {
147 let mut mock = Mock::<(usize,), String>::new("a");
148 mock.returns(Matcher::any().wrapped(), "a".repeat(3));
149
150 assert_eq!(mock.find_mock_output(&(3,)), "aaa".to_string().into());
151 }
152
153 #[test]
154 fn calls_real_impl() {
155 let mut mock = Mock::<(usize,), String>::new("a");
156 mock.calls_real_impl(Arc::new(Mutex::new(Matcher::new_eq((3,)))));
157
158 assert_eq!(mock.find_mock_output(&(3,)), None);
159 }
160
161 #[test]
162 #[should_panic(expected = "mock not found for a")]
163 fn calls_real_impl_never() {
164 let mut mock = Mock::<(usize,), String>::new("a");
165 mock.calls_real_impl(Arc::new(Mutex::new(Matcher::new_eq((3,)))));
166
167 mock.find_mock_output(&(2,));
168 }
169
170 #[test]
171 #[should_panic(expected = "a was called more than once")]
172 fn panic_on_once_called_multiple_time() {
173 let mut mock = Mock::<(usize,), String>::new("a");
174 mock.returns_once(Matcher::any().wrapped(), "a".repeat(3));
175
176 mock.find_mock_output(&(3,));
177 mock.find_mock_output(&(3,));
178 }
179}