1use crate::error::{TestingError, TestingResult};
4use rand::{RngExt, distr::Alphanumeric, prelude::IndexedRandom};
5
6pub trait Fixture: Sized {
8 fn generate() -> TestingResult<Self>;
10}
11
12pub trait FixtureBuilder<T>: Sized {
14 fn build(self) -> TestingResult<T>;
16}
17
18#[derive(Debug, Clone)]
20pub struct RandomString {
21 pub length: usize,
23 pub prefix: Option<String>,
25 pub suffix: Option<String>,
27}
28
29impl Default for RandomString {
30 fn default() -> Self {
31 Self { length: 10, prefix: None, suffix: None }
32 }
33}
34
35impl RandomString {
36 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn length(mut self, len: usize) -> Self {
43 self.length = len;
44 self
45 }
46
47 pub fn prefix(mut self, prefix: impl Into<String>) -> Self {
49 self.prefix = Some(prefix.into());
50 self
51 }
52
53 pub fn suffix(mut self, suffix: impl Into<String>) -> Self {
55 self.suffix = Some(suffix.into());
56 self
57 }
58
59 pub fn generate(&self) -> TestingResult<String> {
61 let mut rng = rand::rng();
62 let random_part: String = (0..self.length).map(|_| rng.sample(Alphanumeric) as char).collect();
63
64 let mut result = String::new();
65 if let Some(ref prefix) = self.prefix {
66 result.push_str(prefix);
67 }
68 result.push_str(&random_part);
69 if let Some(ref suffix) = self.suffix {
70 result.push_str(suffix);
71 }
72
73 Ok(result)
74 }
75}
76
77impl Fixture for String {
78 fn generate() -> TestingResult<Self> {
79 RandomString::new().generate()
80 }
81}
82
83#[derive(Debug, Clone)]
85pub struct RandomNumber<T> {
86 pub min: T,
88 pub max: T,
90 _marker: std::marker::PhantomData<T>,
91}
92
93impl<T> RandomNumber<T> {
94 pub fn new(min: T, max: T) -> Self {
96 Self { min, max, _marker: std::marker::PhantomData }
97 }
98}
99
100impl RandomNumber<i32> {
101 pub fn generate(&self) -> TestingResult<i32> {
103 let mut rng = rand::rng();
104 Ok(rng.random_range(self.min..=self.max))
105 }
106}
107
108impl RandomNumber<i64> {
109 pub fn generate(&self) -> TestingResult<i64> {
111 let mut rng = rand::rng();
112 Ok(rng.random_range(self.min..=self.max))
113 }
114}
115
116impl RandomNumber<u32> {
117 pub fn generate(&self) -> TestingResult<u32> {
119 let mut rng = rand::rng();
120 Ok(rng.random_range(self.min..=self.max))
121 }
122}
123
124impl RandomNumber<u64> {
125 pub fn generate(&self) -> TestingResult<u64> {
127 let mut rng = rand::rng();
128 Ok(rng.random_range(self.min..=self.max))
129 }
130}
131
132impl RandomNumber<f64> {
133 pub fn generate(&self) -> TestingResult<f64> {
135 let mut rng = rand::rng();
136 Ok(rng.random_range(self.min..=self.max))
137 }
138}
139
140impl Fixture for i32 {
141 fn generate() -> TestingResult<Self> {
142 let generator: RandomNumber<i32> = RandomNumber::new(0, 1000000);
143 generator.generate()
144 }
145}
146
147impl Fixture for u64 {
148 fn generate() -> TestingResult<Self> {
149 RandomNumber::new(0u64, 1000000u64).generate()
150 }
151}
152
153#[derive(Debug, Clone)]
155pub struct RandomEmail {
156 pub domain: String,
158}
159
160impl Default for RandomEmail {
161 fn default() -> Self {
162 Self { domain: "test.example.com".to_string() }
163 }
164}
165
166impl RandomEmail {
167 pub fn new() -> Self {
169 Self::default()
170 }
171
172 pub fn domain(mut self, domain: impl Into<String>) -> Self {
174 self.domain = domain.into();
175 self
176 }
177
178 pub fn generate(&self) -> TestingResult<String> {
180 let username = RandomString::new().length(8).generate()?;
181 Ok(format!("{}@{}", username, self.domain))
182 }
183}
184
185#[derive(Debug, Clone, Default)]
187pub struct RandomUuid {
188 pub version4: bool,
190}
191
192impl RandomUuid {
193 pub fn new() -> Self {
195 Self { version4: true }
196 }
197
198 pub fn version7(mut self) -> Self {
200 self.version4 = false;
201 self
202 }
203
204 pub fn generate(&self) -> TestingResult<uuid::Uuid> {
206 if self.version4 { Ok(uuid::Uuid::new_v4()) } else { Ok(uuid::Uuid::now_v7()) }
207 }
208
209 pub fn generate_string(&self) -> TestingResult<String> {
211 Ok(self.generate()?.to_string())
212 }
213}
214
215impl Fixture for uuid::Uuid {
216 fn generate() -> TestingResult<Self> {
217 RandomUuid::new().generate()
218 }
219}
220
221#[derive(Debug, Clone, Default)]
223pub struct RandomBool {
224 pub true_probability: f64,
226}
227
228impl RandomBool {
229 pub fn new() -> Self {
231 Self { true_probability: 0.5 }
232 }
233
234 pub fn probability(mut self, prob: f64) -> Self {
236 self.true_probability = prob.clamp(0.0, 1.0);
237 self
238 }
239
240 pub fn generate(&self) -> TestingResult<bool> {
242 let mut rng = rand::rng();
243 Ok(rng.random_bool(self.true_probability))
244 }
245}
246
247impl Fixture for bool {
248 fn generate() -> TestingResult<Self> {
249 RandomBool::new().generate()
250 }
251}
252
253#[derive(Debug, Clone)]
255pub struct RandomChoice<T> {
256 pub items: Vec<T>,
258}
259
260impl<T: Clone> RandomChoice<T> {
261 pub fn new(items: Vec<T>) -> Self {
263 Self { items }
264 }
265
266 pub fn generate(&self) -> TestingResult<T> {
268 let mut rng = rand::rng();
269 self.items.choose(&mut rng).cloned().ok_or_else(|| TestingError::FixtureError("No items to choose from".to_string()))
270 }
271}
272
273#[derive(Debug, Clone)]
275pub struct RandomDateTime {
276 pub start_timestamp: i64,
278 pub end_timestamp: i64,
280}
281
282impl Default for RandomDateTime {
283 fn default() -> Self {
284 Self { start_timestamp: 0, end_timestamp: 4102444800 }
285 }
286}
287
288impl RandomDateTime {
289 pub fn new() -> Self {
291 Self::default()
292 }
293
294 pub fn range(mut self, start: i64, end: i64) -> Self {
296 self.start_timestamp = start;
297 self.end_timestamp = end;
298 self
299 }
300
301 pub fn generate_timestamp(&self) -> TestingResult<i64> {
303 let mut rng = rand::rng();
304 Ok(rng.random_range(self.start_timestamp..=self.end_timestamp))
305 }
306}
307
308pub struct FixtureGenerator;
310
311impl FixtureGenerator {
312 pub fn strings(count: usize, length: usize) -> TestingResult<Vec<String>> {
314 (0..count).map(|_| RandomString::new().length(length).generate()).collect()
315 }
316
317 pub fn emails(count: usize, domain: &str) -> TestingResult<Vec<String>> {
319 (0..count).map(|_| RandomEmail::new().domain(domain).generate()).collect()
320 }
321
322 pub fn uuids(count: usize) -> TestingResult<Vec<uuid::Uuid>> {
324 (0..count).map(|_| RandomUuid::new().generate()).collect()
325 }
326
327 pub fn i32_numbers(count: usize, min: i32, max: i32) -> TestingResult<Vec<i32>> {
329 let mut rng = rand::rng();
330 (0..count).map(|_| Ok(rng.random_range(min..=max))).collect()
331 }
332
333 pub fn u64_numbers(count: usize, min: u64, max: u64) -> TestingResult<Vec<u64>> {
335 let mut rng = rand::rng();
336 (0..count).map(|_| Ok(rng.random_range(min..=max))).collect()
337 }
338}