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#[allow(dead_code)]
123#[derive(Clone)]
124pub struct Spy<T: Clone> {
125 inner: T,
126 calls: Arc<Mutex<Vec<String>>>,
127}
128
129impl<T: Clone> Spy<T> {
130 #[allow(dead_code)]
132 pub fn new(inner: T) -> Self {
133 Self {
134 inner,
135 calls: Arc::new(Mutex::new(Vec::new())),
136 }
137 }
138
139 #[allow(dead_code)]
141 pub fn record(&self, method: &str) {
142 self.calls.lock().unwrap().push(method.to_string());
143 }
144
145 #[allow(dead_code)]
147 pub fn call_count(&self) -> usize {
148 self.calls.lock().unwrap().len()
149 }
150
151 #[allow(dead_code)]
153 pub fn was_called(&self, method: &str) -> bool {
154 self.calls.lock().unwrap().contains(&method.to_string())
155 }
156
157 #[allow(dead_code)]
159 pub fn inner(&self) -> &T {
160 &self.inner
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_mock_service() {
170 let mock = MockService::<String>::new();
171 mock.record_call("test_method");
172 assert_eq!(mock.call_count(), 1);
173 assert!(mock.was_called("test_method"));
174 }
175
176 #[test]
177 fn test_mock_controller() {
178 let mock = MockController::new("TestController");
179 mock.record_call("get", vec!["id".to_string()]);
180 assert_eq!(mock.method_call_count("get"), 1);
181 }
182
183 #[test]
184 fn test_spy() {
185 let spy = Spy::new("test_value");
186 spy.record("method1");
187 spy.record("method2");
188 assert_eq!(spy.call_count(), 2);
189 assert!(spy.was_called("method1"));
190 }
191}