Skip to main content

rskit_testutil/
mock_provider.rs

1use std::collections::VecDeque;
2
3use parking_lot::Mutex;
4
5use rskit_errors::{AppError, AppResult};
6
7/// A generic mock that records calls and returns pre-configured responses.
8///
9/// Useful for testing code that depends on a `RequestResponse`-style provider without reaching real infrastructure.
10///
11/// # Example
12///
13/// ```ignore
14/// let mock = MockProvider::<String, u64>::new();
15/// mock.will_return(42);
16///
17/// // Hand `mock` to the system under test, then verify:
18/// assert_eq!(mock.call_count(), 1);
19/// ```
20pub struct MockProvider<I, O> {
21    responses: Mutex<VecDeque<AppResult<O>>>,
22    calls: Mutex<Vec<I>>,
23}
24
25impl<I: Clone + Send + Sync + 'static, O: Clone + Send + Sync + 'static> MockProvider<I, O> {
26    /// Create a new mock with no pre-configured responses.
27    pub fn new() -> Self {
28        Self {
29            responses: Mutex::new(VecDeque::new()),
30            calls: Mutex::new(Vec::new()),
31        }
32    }
33
34    /// Enqueue a successful response.
35    pub fn will_return(&self, response: O) -> &Self {
36        self.responses.lock().push_back(Ok(response));
37        self
38    }
39
40    /// Enqueue an error response.
41    pub fn will_fail(&self, err: AppError) -> &Self {
42        self.responses.lock().push_back(Err(err));
43        self
44    }
45
46    /// Return a clone of all recorded call inputs.
47    pub fn calls(&self) -> Vec<I> {
48        self.calls.lock().clone()
49    }
50
51    /// Return the number of calls recorded so far.
52    pub fn call_count(&self) -> usize {
53        self.calls.lock().len()
54    }
55
56    /// Record a call and pop the next response.
57    ///
58    /// Panics if no response has been enqueued.
59    pub fn execute(&self, input: I) -> AppResult<O> {
60        self.calls.lock().push(input);
61        self.responses
62            .lock()
63            .pop_front()
64            .expect("MockProvider: no more responses enqueued")
65    }
66}
67
68impl<I: Clone + Send + Sync + 'static, O: Clone + Send + Sync + 'static> Default
69    for MockProvider<I, O>
70{
71    fn default() -> Self {
72        Self::new()
73    }
74}