xerv_core/testing/providers/
uuid.rs1use parking_lot::Mutex;
6use std::sync::atomic::{AtomicU64, Ordering};
7use uuid::Uuid;
8
9pub trait UuidProvider: Send + Sync {
11 fn new_v4(&self) -> Uuid;
13
14 fn is_mock(&self) -> bool;
16}
17
18pub struct RealUuid;
20
21impl RealUuid {
22 pub fn new() -> Self {
24 Self
25 }
26}
27
28impl Default for RealUuid {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl UuidProvider for RealUuid {
35 fn new_v4(&self) -> Uuid {
36 Uuid::new_v4()
37 }
38
39 fn is_mock(&self) -> bool {
40 false
41 }
42}
43
44pub struct MockUuid {
48 mode: MockUuidMode,
49}
50
51enum MockUuidMode {
52 Sequential(AtomicU64),
54 Predetermined(Mutex<Vec<Uuid>>),
56}
57
58impl MockUuid {
59 pub fn sequential() -> Self {
77 Self {
78 mode: MockUuidMode::Sequential(AtomicU64::new(1)),
79 }
80 }
81
82 pub fn sequential_from(start: u64) -> Self {
84 Self {
85 mode: MockUuidMode::Sequential(AtomicU64::new(start)),
86 }
87 }
88
89 pub fn predetermined(uuids: Vec<Uuid>) -> Self {
109 let mut reversed = uuids;
111 reversed.reverse();
112 Self {
113 mode: MockUuidMode::Predetermined(Mutex::new(reversed)),
114 }
115 }
116
117 pub fn from_strings(uuids: &[&str]) -> Self {
123 let parsed: Vec<Uuid> = uuids
124 .iter()
125 .map(|s| Uuid::parse_str(s).expect("Invalid UUID string"))
126 .collect();
127 Self::predetermined(parsed)
128 }
129
130 pub fn current_counter(&self) -> Option<u64> {
132 match &self.mode {
133 MockUuidMode::Sequential(counter) => Some(counter.load(Ordering::SeqCst)),
134 MockUuidMode::Predetermined(_) => None,
135 }
136 }
137}
138
139impl UuidProvider for MockUuid {
140 fn new_v4(&self) -> Uuid {
141 match &self.mode {
142 MockUuidMode::Sequential(counter) => {
143 let n = counter.fetch_add(1, Ordering::SeqCst);
144 let bytes: [u8; 16] = [
146 0,
147 0,
148 0,
149 0,
150 0,
151 0,
152 0,
153 0,
154 (n >> 56) as u8,
155 (n >> 48) as u8,
156 (n >> 40) as u8,
157 (n >> 32) as u8,
158 (n >> 24) as u8,
159 (n >> 16) as u8,
160 (n >> 8) as u8,
161 n as u8,
162 ];
163 Uuid::from_bytes(bytes)
164 }
165 MockUuidMode::Predetermined(uuids) => {
166 let mut guard = uuids.lock();
167 if let Some(uuid) = guard.pop() {
168 uuid
169 } else {
170 let n = guard.len() as u64 + 1;
172 drop(guard);
173 let bytes: [u8; 16] = [
174 0,
175 0,
176 0,
177 0,
178 0,
179 0,
180 0,
181 0,
182 (n >> 56) as u8,
183 (n >> 48) as u8,
184 (n >> 40) as u8,
185 (n >> 32) as u8,
186 (n >> 24) as u8,
187 (n >> 16) as u8,
188 (n >> 8) as u8,
189 n as u8,
190 ];
191 Uuid::from_bytes(bytes)
192 }
193 }
194 }
195 }
196
197 fn is_mock(&self) -> bool {
198 true
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn sequential_uuids() {
208 let provider = MockUuid::sequential();
209
210 let id1 = provider.new_v4();
211 let id2 = provider.new_v4();
212 let id3 = provider.new_v4();
213
214 assert_eq!(id1.to_string(), "00000000-0000-0000-0000-000000000001");
215 assert_eq!(id2.to_string(), "00000000-0000-0000-0000-000000000002");
216 assert_eq!(id3.to_string(), "00000000-0000-0000-0000-000000000003");
217 }
218
219 #[test]
220 fn sequential_from() {
221 let provider = MockUuid::sequential_from(100);
222
223 let id = provider.new_v4();
224 assert_eq!(id.to_string(), "00000000-0000-0000-0000-000000000064"); }
226
227 #[test]
228 fn predetermined_uuids() {
229 let id1 = Uuid::parse_str("12345678-1234-1234-1234-123456789abc").unwrap();
230 let id2 = Uuid::parse_str("abcdefab-cdef-abcd-efab-cdefabcdefab").unwrap();
231
232 let provider = MockUuid::predetermined(vec![id1, id2]);
233
234 assert_eq!(provider.new_v4(), id1);
235 assert_eq!(provider.new_v4(), id2);
236 }
237
238 #[test]
239 fn from_strings() {
240 let provider = MockUuid::from_strings(&[
241 "11111111-1111-1111-1111-111111111111",
242 "22222222-2222-2222-2222-222222222222",
243 ]);
244
245 assert_eq!(
246 provider.new_v4().to_string(),
247 "11111111-1111-1111-1111-111111111111"
248 );
249 assert_eq!(
250 provider.new_v4().to_string(),
251 "22222222-2222-2222-2222-222222222222"
252 );
253 }
254
255 #[test]
256 fn real_uuid_is_random() {
257 let provider = RealUuid::new();
258 let id1 = provider.new_v4();
259 let id2 = provider.new_v4();
260
261 assert_ne!(id1, id2);
262 }
263}