1use armature_core::Provider;
4use std::sync::{Arc, Mutex};
5
6#[derive(Clone)]
8pub struct MockService<T> {
9 calls: Arc<Mutex<Vec<String>>>,
10 return_value: Arc<Mutex<Option<T>>>,
11}
12
13impl<T> MockService<T> {
14 pub fn new() -> Self {
16 Self {
17 calls: Arc::new(Mutex::new(Vec::new())),
18 return_value: Arc::new(Mutex::new(None)),
19 }
20 }
21
22 pub fn with_return(self, value: T) -> Self {
24 *self.return_value.lock().unwrap() = Some(value);
25 self
26 }
27
28 pub fn record_call(&self, method: &str) {
30 self.calls.lock().unwrap().push(method.to_string());
31 }
32
33 pub fn call_count(&self) -> usize {
35 self.calls.lock().unwrap().len()
36 }
37
38 pub fn get_calls(&self) -> Vec<String> {
40 self.calls.lock().unwrap().clone()
41 }
42
43 pub fn was_called(&self, method: &str) -> bool {
45 self.calls.lock().unwrap().contains(&method.to_string())
46 }
47
48 pub fn clear_calls(&self) {
50 self.calls.lock().unwrap().clear();
51 }
52
53 pub fn get_return(&self) -> Option<T>
55 where
56 T: Clone,
57 {
58 self.return_value.lock().unwrap().clone()
59 }
60}
61
62impl<T> Default for MockService<T> {
63 fn default() -> Self {
64 Self::new()
65 }
66}
67
68type CallLog = Arc<Mutex<Vec<(String, Vec<String>)>>>;
69
70#[derive(Clone)]
72pub struct MockController {
73 _name: String,
74 calls: CallLog,
75}
76
77impl MockController {
78 pub fn new(name: &str) -> Self {
80 Self {
81 _name: name.to_string(),
82 calls: Arc::new(Mutex::new(Vec::new())),
83 }
84 }
85
86 pub fn record_call(&self, method: &str, args: Vec<String>) {
88 self.calls.lock().unwrap().push((method.to_string(), args));
89 }
90
91 pub fn method_call_count(&self, method: &str) -> usize {
93 self.calls
94 .lock()
95 .unwrap()
96 .iter()
97 .filter(|(m, _)| m == method)
98 .count()
99 }
100
101 pub fn get_all_calls(&self) -> Vec<(String, Vec<String>)> {
103 self.calls.lock().unwrap().clone()
104 }
105
106 pub fn clear(&self) {
108 self.calls.lock().unwrap().clear();
109 }
110}
111
112pub trait MockProvider: Provider + Clone {
114 fn reset(&mut self);
116
117 fn call_count(&self) -> usize;
119}
120
121#[derive(Clone)]
156pub struct Spy<T: Clone> {
157 inner: T,
158 calls: Arc<Mutex<Vec<String>>>,
159}
160
161impl<T: Clone> Spy<T> {
162 pub fn new(inner: T) -> Self {
164 Self {
165 inner,
166 calls: Arc::new(Mutex::new(Vec::new())),
167 }
168 }
169
170 pub fn record(&self, method: &str) {
175 self.calls.lock().unwrap().push(method.to_string());
176 }
177
178 pub fn call_count(&self) -> usize {
180 self.calls.lock().unwrap().len()
181 }
182
183 pub fn was_called(&self, method: &str) -> bool {
185 self.calls.lock().unwrap().contains(&method.to_string())
186 }
187
188 pub fn calls(&self) -> Vec<String> {
190 self.calls.lock().unwrap().clone()
191 }
192
193 pub fn clear(&self) {
195 self.calls.lock().unwrap().clear();
196 }
197
198 pub fn inner(&self) -> &T {
203 &self.inner
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn test_mock_service() {
213 let mock = MockService::<String>::new();
214 mock.record_call("test_method");
215 assert_eq!(mock.call_count(), 1);
216 assert!(mock.was_called("test_method"));
217 }
218
219 #[test]
220 fn test_mock_controller() {
221 let mock = MockController::new("TestController");
222 mock.record_call("get", vec!["id".to_string()]);
223 assert_eq!(mock.method_call_count("get"), 1);
224 }
225
226 #[test]
227 fn test_spy() {
228 let spy = Spy::new("test_value");
229 spy.record("method1");
230 spy.record("method2");
231 assert_eq!(spy.call_count(), 2);
232 assert!(spy.was_called("method1"));
233 }
234}