Skip to main content

doc_db/
mock.rs

1use std::collections::VecDeque;
2use std::sync::{Arc, Mutex};
3
4/// Key for matching mock rules against operations.
5#[derive(Clone, Debug, PartialEq, Eq, Hash)]
6pub(crate) struct MockKey {
7    pub op: MockOp,
8    pub pk: String,
9    pub sk: String,
10}
11
12#[derive(Clone, Debug, PartialEq, Eq, Hash)]
13pub(crate) enum MockOp {
14    Get,
15    Put,
16    Delete,
17}
18
19/// The result a mock rule produces.
20#[derive(Clone)]
21pub(crate) enum MockResult {
22    /// Return Ok with this data (for Get: Some(bytes), None means not found)
23    OkGet(Option<Vec<u8>>),
24    /// Return Ok(()) for put/delete
25    OkVoid,
26    /// Return Err with this message
27    Err(String),
28}
29
30/// A single mock rule.
31#[derive(Clone)]
32pub(crate) struct MockRule {
33    pub key: MockKey,
34    pub result: MockResult,
35}
36
37/// Shared mock state stored inside a Database.
38#[derive(Clone, Default)]
39pub(crate) struct MockState {
40    rules: Arc<Mutex<VecDeque<MockRule>>>,
41}
42
43impl MockState {
44    pub(crate) fn push(&self, rule: MockRule) {
45        self.rules.lock().unwrap().push_back(rule);
46    }
47
48    /// Try to match and consume a rule for the given operation.
49    pub(crate) fn try_match(&self, op: MockOp, pk: &str, sk: &str) -> Option<MockResult> {
50        let mut rules = self.rules.lock().unwrap();
51        let pos = rules
52            .iter()
53            .position(|r| r.key.op == op && r.key.pk == pk && r.key.sk == sk)?;
54        Some(rules.remove(pos).unwrap().result)
55    }
56
57    pub(crate) fn clear(&self) {
58        self.rules.lock().unwrap().clear();
59    }
60}
61
62// --- Public builder API ---
63
64/// Builder for configuring a mock rule on a Get operation.
65pub struct MockGetBuilder<'a> {
66    db: &'a crate::Database,
67    pk: String,
68    sk: String,
69}
70
71impl<'a> MockGetBuilder<'a> {
72    pub(crate) fn new(db: &'a crate::Database, pk: String, sk: String) -> Self {
73        Self { db, pk, sk }
74    }
75
76    /// Mock this get to return the given data.
77    pub fn returns(self, data: impl Into<Vec<u8>>) {
78        self.db.add_mock_rule(MockRule {
79            key: MockKey {
80                op: MockOp::Get,
81                pk: self.pk,
82                sk: self.sk,
83            },
84            result: MockResult::OkGet(Some(data.into())),
85        });
86    }
87
88    /// Mock this get to return None (not found).
89    pub fn returns_none(self) {
90        self.db.add_mock_rule(MockRule {
91            key: MockKey {
92                op: MockOp::Get,
93                pk: self.pk,
94                sk: self.sk,
95            },
96            result: MockResult::OkGet(None),
97        });
98    }
99
100    /// Mock this get to return an error.
101    pub fn returns_err(self, msg: impl Into<String>) {
102        self.db.add_mock_rule(MockRule {
103            key: MockKey {
104                op: MockOp::Get,
105                pk: self.pk,
106                sk: self.sk,
107            },
108            result: MockResult::Err(msg.into()),
109        });
110    }
111}
112
113/// Builder for configuring a mock rule on a Put operation.
114pub struct MockPutBuilder<'a> {
115    db: &'a crate::Database,
116    pk: String,
117    sk: String,
118}
119
120impl<'a> MockPutBuilder<'a> {
121    pub(crate) fn new(db: &'a crate::Database, pk: String, sk: String) -> Self {
122        Self { db, pk, sk }
123    }
124
125    /// Mock this put to succeed.
126    pub fn returns_ok(self) {
127        self.db.add_mock_rule(MockRule {
128            key: MockKey {
129                op: MockOp::Put,
130                pk: self.pk,
131                sk: self.sk,
132            },
133            result: MockResult::OkVoid,
134        });
135    }
136
137    /// Mock this put to return an error.
138    pub fn returns_err(self, msg: impl Into<String>) {
139        self.db.add_mock_rule(MockRule {
140            key: MockKey {
141                op: MockOp::Put,
142                pk: self.pk,
143                sk: self.sk,
144            },
145            result: MockResult::Err(msg.into()),
146        });
147    }
148}
149
150/// Builder for configuring a mock rule on a Delete operation.
151pub struct MockDeleteBuilder<'a> {
152    db: &'a crate::Database,
153    pk: String,
154    sk: String,
155}
156
157impl<'a> MockDeleteBuilder<'a> {
158    pub(crate) fn new(db: &'a crate::Database, pk: String, sk: String) -> Self {
159        Self { db, pk, sk }
160    }
161
162    /// Mock this delete to succeed.
163    pub fn returns_ok(self) {
164        self.db.add_mock_rule(MockRule {
165            key: MockKey {
166                op: MockOp::Delete,
167                pk: self.pk,
168                sk: self.sk,
169            },
170            result: MockResult::OkVoid,
171        });
172    }
173
174    /// Mock this delete to return an error.
175    pub fn returns_err(self, msg: impl Into<String>) {
176        self.db.add_mock_rule(MockRule {
177            key: MockKey {
178                op: MockOp::Delete,
179                pk: self.pk,
180                sk: self.sk,
181            },
182            result: MockResult::Err(msg.into()),
183        });
184    }
185}