1use std::collections::VecDeque;
2use std::sync::{Arc, Mutex};
3
4#[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#[derive(Clone)]
21pub(crate) enum MockResult {
22 OkGet(Option<Vec<u8>>),
24 OkVoid,
26 Err(String),
28}
29
30#[derive(Clone)]
32pub(crate) struct MockRule {
33 pub key: MockKey,
34 pub result: MockResult,
35}
36
37#[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 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
62pub 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 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 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 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
113pub 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 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 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
150pub 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 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 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}