Skip to main content

armature_testing/
mock.rs

1// Mock utilities for testing
2
3use armature_core::Provider;
4use std::sync::{Arc, Mutex};
5
6/// Mock service for testing
7#[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    /// Create a new mock service
15    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    /// Set the return value
23    pub fn with_return(self, value: T) -> Self {
24        *self.return_value.lock().unwrap() = Some(value);
25        self
26    }
27
28    /// Record a method call
29    pub fn record_call(&self, method: &str) {
30        self.calls.lock().unwrap().push(method.to_string());
31    }
32
33    /// Get the number of calls
34    pub fn call_count(&self) -> usize {
35        self.calls.lock().unwrap().len()
36    }
37
38    /// Get all recorded calls
39    pub fn get_calls(&self) -> Vec<String> {
40        self.calls.lock().unwrap().clone()
41    }
42
43    /// Check if a method was called
44    pub fn was_called(&self, method: &str) -> bool {
45        self.calls.lock().unwrap().contains(&method.to_string())
46    }
47
48    /// Clear all recorded calls
49    pub fn clear_calls(&self) {
50        self.calls.lock().unwrap().clear();
51    }
52
53    /// Get the mock return value
54    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/// Mock controller for testing
71#[derive(Clone)]
72pub struct MockController {
73    _name: String,
74    calls: CallLog,
75}
76
77impl MockController {
78    /// Create a new mock controller
79    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    /// Record a method call with arguments
87    pub fn record_call(&self, method: &str, args: Vec<String>) {
88        self.calls.lock().unwrap().push((method.to_string(), args));
89    }
90
91    /// Get the number of calls to a specific method
92    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    /// Get all calls
102    pub fn get_all_calls(&self) -> Vec<(String, Vec<String>)> {
103        self.calls.lock().unwrap().clone()
104    }
105
106    /// Clear all calls
107    pub fn clear(&self) {
108        self.calls.lock().unwrap().clear();
109    }
110}
111
112/// Mock provider trait implementation
113pub trait MockProvider: Provider + Clone {
114    /// Reset the mock to its initial state
115    fn reset(&mut self);
116
117    /// Get the number of calls
118    fn call_count(&self) -> usize;
119}
120
121/// Spy wrapper for providers
122#[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    /// Create a new spy wrapping a provider
131    #[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    /// Record a method call
140    #[allow(dead_code)]
141    pub fn record(&self, method: &str) {
142        self.calls.lock().unwrap().push(method.to_string());
143    }
144
145    /// Get the number of calls
146    #[allow(dead_code)]
147    pub fn call_count(&self) -> usize {
148        self.calls.lock().unwrap().len()
149    }
150
151    /// Check if a method was called
152    #[allow(dead_code)]
153    pub fn was_called(&self, method: &str) -> bool {
154        self.calls.lock().unwrap().contains(&method.to_string())
155    }
156
157    /// Get the wrapped provider
158    #[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}