Skip to main content

wae_testing/
mock.rs

1//! Mock 工具模块
2//!
3//! 提供简洁易用的 Mock 功能,支持同步和异步操作。
4//! 当启用 `mockall` feature 时,还可以使用更强大的 trait-level mocking。
5
6use parking_lot::RwLock;
7use std::sync::Arc;
8use wae_types::{WaeError, WaeErrorKind, WaeResult as TestingResult};
9
10#[cfg(feature = "mockall")]
11pub use mockall::{self, __mock_MockObject, __mock_MockStatic, automock, mock, predicate, sequence};
12
13/// Mock 调用记录
14#[derive(Debug, Clone)]
15pub struct MockCall {
16    /// 调用参数 (JSON 序列化)
17    pub args: Vec<String>,
18    /// 调用时间戳
19    pub timestamp: std::time::Instant,
20}
21
22/// Mock 返回结果
23#[derive(Debug)]
24pub enum MockResult<T> {
25    /// 返回指定值
26    Return(T),
27    /// 返回错误
28    Error(String),
29    /// 根据调用次数返回不同结果
30    Sequence(Vec<T>),
31}
32
33impl<T: Clone> MockResult<T> {
34    /// 创建返回值
35    pub fn return_value(value: T) -> Self {
36        MockResult::Return(value)
37    }
38
39    /// 创建错误返回
40    pub fn error(msg: impl Into<String>) -> Self {
41        MockResult::Error(msg.into())
42    }
43
44    /// 创建序列返回
45    pub fn sequence(values: Vec<T>) -> Self {
46        MockResult::Sequence(values)
47    }
48}
49
50impl<T: Clone> Clone for MockResult<T> {
51    fn clone(&self) -> Self {
52        match self {
53            MockResult::Return(v) => MockResult::Return(v.clone()),
54            MockResult::Error(e) => MockResult::Error(e.clone()),
55            MockResult::Sequence(v) => MockResult::Sequence(v.clone()),
56        }
57    }
58}
59
60/// Mock 期望配置
61#[derive(Debug, Default)]
62pub struct MockExpectation {
63    /// 期望的调用次数
64    pub expected_calls: Option<usize>,
65    /// 描述信息
66    pub description: Option<String>,
67}
68
69impl MockExpectation {
70    /// 创建新的期望配置
71    pub fn new() -> Self {
72        Self::default()
73    }
74
75    /// 设置期望调用次数
76    pub fn times(mut self, count: usize) -> Self {
77        self.expected_calls = Some(count);
78        self
79    }
80
81    /// 设置描述
82    pub fn description(mut self, desc: impl Into<String>) -> Self {
83        self.description = Some(desc.into());
84        self
85    }
86}
87
88/// Mock 行为 trait
89pub trait Mock: Send + Sync {
90    /// 获取调用记录
91    fn calls(&self) -> Vec<MockCall>;
92
93    /// 获取调用次数
94    fn call_count(&self) -> usize;
95
96    /// 验证期望
97    fn verify(&self) -> TestingResult<()>;
98
99    /// 重置 Mock 状态
100    fn reset(&self);
101}
102
103/// 异步 Mock 行为 trait
104pub trait AsyncMock: Mock {
105    /// 异步验证期望
106    async fn verify_async(&self) -> TestingResult<()>;
107}
108
109/// Mock 构建器
110pub struct MockBuilder<T> {
111    result: Option<MockResult<T>>,
112    expectation: MockExpectation,
113    calls: Arc<RwLock<Vec<MockCall>>>,
114}
115
116impl<T: Clone + Send + Sync + 'static> MockBuilder<T> {
117    /// 创建新的 Mock 构建器
118    pub fn new() -> Self {
119        Self { result: None, expectation: MockExpectation::default(), calls: Arc::new(RwLock::new(Vec::new())) }
120    }
121
122    /// 设置返回值
123    pub fn return_value(mut self, value: T) -> Self {
124        self.result = Some(MockResult::return_value(value));
125        self
126    }
127
128    /// 设置错误返回
129    pub fn error(mut self, msg: impl Into<String>) -> Self {
130        self.result = Some(MockResult::error(msg));
131        self
132    }
133
134    /// 设置序列返回
135    pub fn sequence(mut self, values: Vec<T>) -> Self {
136        self.result = Some(MockResult::sequence(values));
137        self
138    }
139
140    /// 设置期望
141    pub fn expect(mut self, expectation: MockExpectation) -> Self {
142        self.expectation = expectation;
143        self
144    }
145
146    /// 构建可执行的 Mock
147    pub fn build(self) -> MockFn<T> {
148        MockFn {
149            result: self.result,
150            expectation: self.expectation,
151            calls: self.calls,
152            sequence_index: Arc::new(RwLock::new(0)),
153        }
154    }
155}
156
157impl<T: Clone + Send + Sync + 'static> Default for MockBuilder<T> {
158    fn default() -> Self {
159        Self::new()
160    }
161}
162
163/// 可执行的 Mock 函数
164pub struct MockFn<T> {
165    result: Option<MockResult<T>>,
166    expectation: MockExpectation,
167    calls: Arc<RwLock<Vec<MockCall>>>,
168    sequence_index: Arc<RwLock<usize>>,
169}
170
171impl<T: Clone + Send + Sync + 'static> MockFn<T> {
172    /// 执行 Mock 调用
173    pub fn call(&self, args: Vec<String>) -> TestingResult<T> {
174        {
175            let mut calls = self.calls.write();
176            calls.push(MockCall { args, timestamp: std::time::Instant::now() });
177        }
178
179        match &self.result {
180            Some(MockResult::Return(v)) => Ok(v.clone()),
181            Some(MockResult::Error(e)) => Err(WaeError::new(WaeErrorKind::MockError { reason: e.clone() })),
182            Some(MockResult::Sequence(values)) => {
183                let mut idx = self.sequence_index.write();
184                if *idx < values.len() {
185                    let value = values[*idx].clone();
186                    *idx += 1;
187                    Ok(value)
188                }
189                else {
190                    Err(WaeError::new(WaeErrorKind::MockError { reason: "Mock sequence exhausted".to_string() }))
191                }
192            }
193            None => Err(WaeError::new(WaeErrorKind::MockError { reason: "No mock result configured".to_string() })),
194        }
195    }
196
197    /// 异步执行 Mock 调用
198    pub async fn call_async(&self, args: Vec<String>) -> TestingResult<T> {
199        self.call(args)
200    }
201}
202
203impl<T: Clone + Send + Sync + 'static> Mock for MockFn<T> {
204    fn calls(&self) -> Vec<MockCall> {
205        self.calls.read().clone()
206    }
207
208    fn call_count(&self) -> usize {
209        self.calls.read().len()
210    }
211
212    fn verify(&self) -> TestingResult<()> {
213        let actual_calls = self.call_count();
214
215        if let Some(expected) = self.expectation.expected_calls
216            && actual_calls != expected
217        {
218            return Err(WaeError::new(WaeErrorKind::AssertionFailed {
219                message: format!("Expected {} calls, but got {}", expected, actual_calls),
220            }));
221        }
222
223        Ok(())
224    }
225
226    fn reset(&self) {
227        let mut calls = self.calls.write();
228        calls.clear();
229        let mut idx = self.sequence_index.write();
230        *idx = 0;
231    }
232}
233
234impl<T: Clone + Send + Sync + 'static> AsyncMock for MockFn<T> {
235    async fn verify_async(&self) -> TestingResult<()> {
236        self.verify()
237    }
238}
239
240/// 验证 Mock 期望
241pub fn verify<M: Mock>(mock: &M) -> TestingResult<()> {
242    mock.verify()
243}
244
245/// 异步验证 Mock 期望
246pub async fn verify_async<M: AsyncMock>(mock: &M) -> TestingResult<()> {
247    mock.verify_async().await
248}