mockforge_data/
faker.rs

1//! Faker utilities for generating realistic fake data
2
3use fake::Fake;
4use rand::Rng;
5use serde_json::Value;
6use std::collections::HashMap;
7
8/// Enhanced faker with additional utilities
9#[derive(Debug, Default)]
10pub struct EnhancedFaker;
11
12impl EnhancedFaker {
13    /// Create a new enhanced faker
14    pub fn new() -> Self {
15        Self
16    }
17
18    /// Generate a random UUID
19    pub fn uuid(&mut self) -> String {
20        uuid::Uuid::new_v4().to_string()
21    }
22
23    /// Generate a random integer within range
24    pub fn int_range(&mut self, min: i64, max: i64) -> i64 {
25        rand::rng().random_range(min..=max)
26    }
27
28    /// Generate a random float within range
29    pub fn float_range(&mut self, min: f64, max: f64) -> f64 {
30        rand::rng().random_range(min..=max)
31    }
32
33    /// Generate a random boolean with given probability
34    pub fn boolean(&mut self, probability: f64) -> bool {
35        rand::rng().random_bool(probability.clamp(0.0, 1.0))
36    }
37
38    /// Generate a random string of given length
39    pub fn string(&mut self, length: usize) -> String {
40        use fake::faker::lorem::en::*;
41        let word_count = (length / 5).max(1); // Approximate words needed
42        let words: Vec<String> = Words(word_count..word_count + 1).fake();
43        words.join(" ")
44    }
45
46    /// Generate a random email
47    pub fn email(&mut self) -> String {
48        use fake::faker::internet::en::*;
49        FreeEmail().fake()
50    }
51
52    /// Generate a random name
53    pub fn name(&mut self) -> String {
54        use fake::faker::name::en::*;
55        Name().fake()
56    }
57
58    /// Generate a random address
59    pub fn address(&mut self) -> String {
60        use fake::faker::address::en::*;
61        StreetName().fake()
62    }
63
64    /// Generate a random phone number
65    pub fn phone(&mut self) -> String {
66        use fake::faker::phone_number::en::*;
67        CellNumber().fake()
68    }
69
70    /// Generate a random company name
71    pub fn company(&mut self) -> String {
72        use fake::faker::company::en::*;
73        CompanyName().fake()
74    }
75
76    /// Generate a random date in ISO format
77    pub fn date_iso(&mut self) -> String {
78        use fake::faker::chrono::en::*;
79        DateTime().fake::<chrono::DateTime<chrono::Utc>>().to_rfc3339()
80    }
81
82    /// Generate a random URL
83    pub fn url(&mut self) -> String {
84        use fake::faker::internet::en::*;
85        let domain: &str = DomainSuffix().fake();
86        format!("https://example.{}", domain)
87    }
88
89    /// Generate a random IP address
90    pub fn ip_address(&mut self) -> String {
91        use fake::faker::internet::en::*;
92        IPv4().fake()
93    }
94
95    /// Generate a random color name
96    pub fn color(&mut self) -> String {
97        let colors = [
98            "red", "blue", "green", "yellow", "purple", "orange", "pink", "brown", "black", "white",
99        ];
100        self.random_element(&colors).unwrap_or(&"blue").to_string()
101    }
102
103    /// Generate a random word
104    pub fn word(&mut self) -> String {
105        use fake::faker::lorem::en::*;
106        Word().fake()
107    }
108
109    /// Generate random words
110    pub fn words(&mut self, count: usize) -> Vec<String> {
111        use fake::faker::lorem::en::*;
112        Words(count..count + 1).fake()
113    }
114
115    /// Generate a random sentence
116    pub fn sentence(&mut self) -> String {
117        use fake::faker::lorem::en::*;
118        Sentence(5..15).fake()
119    }
120
121    /// Generate a random paragraph
122    pub fn paragraph(&mut self) -> String {
123        use fake::faker::lorem::en::*;
124        Paragraph(3..7).fake()
125    }
126
127    /// Pick a random element from a list
128    pub fn random_element<'a, T>(&mut self, items: &'a [T]) -> Option<&'a T> {
129        if items.is_empty() {
130            None
131        } else {
132            let index = rand::rng().random_range(0..items.len());
133            Some(&items[index])
134        }
135    }
136
137    /// Generate a value based on field type
138    pub fn generate_by_type(&mut self, field_type: &str) -> Value {
139        match field_type.to_lowercase().as_str() {
140            "string" | "str" => Value::String(self.string(10)),
141            "email" => Value::String(self.email()),
142            "name" => Value::String(self.name()),
143            "address" => Value::String(self.address()),
144            "phone" => Value::String(self.phone()),
145            "company" => Value::String(self.company()),
146            "url" => Value::String(self.url()),
147            "ip" => Value::String(self.ip_address()),
148            "color" => Value::String(self.color()),
149            "uuid" => Value::String(self.uuid()),
150            "date" | "datetime" => Value::String(self.date_iso()),
151            "int" | "integer" => Value::Number(self.int_range(0, 1000).into()),
152            "float" | "number" => {
153                Value::Number(serde_json::Number::from_f64(self.float_range(0.0, 1000.0)).unwrap())
154            }
155            "bool" | "boolean" => Value::Bool(self.boolean(0.5)),
156            "word" => Value::String(self.word()),
157            "sentence" => Value::String(self.sentence()),
158            "paragraph" => Value::String(self.paragraph()),
159            _ => Value::String(format!("unknown_type_{}", field_type)),
160        }
161    }
162}
163
164/// Template-based faker for complex data generation
165#[derive(Debug)]
166pub struct TemplateFaker {
167    /// Base faker
168    faker: EnhancedFaker,
169    /// Template variables
170    variables: HashMap<String, Value>,
171}
172
173impl TemplateFaker {
174    /// Create a new template faker
175    pub fn new() -> Self {
176        Self {
177            faker: EnhancedFaker::new(),
178            variables: HashMap::new(),
179        }
180    }
181
182    /// Add a template variable
183    pub fn with_variable(mut self, key: String, value: Value) -> Self {
184        self.variables.insert(key, value);
185        self
186    }
187
188    /// Generate data from a template string
189    pub fn generate_from_template(&mut self, template: &str) -> Value {
190        let mut result = template.to_string();
191
192        // Replace {{variable}} patterns
193        for (key, value) in &self.variables {
194            let pattern = format!("{{{{{}}}}}", key);
195            let replacement = value.to_string().trim_matches('"').to_string(); // Remove quotes if present
196            result = result.replace(&pattern, &replacement);
197        }
198
199        // Replace faker patterns like {{faker.email}}
200        result = self.replace_faker_patterns(&result);
201
202        Value::String(result)
203    }
204
205    /// Replace faker patterns in template
206    fn replace_faker_patterns(&mut self, template: &str) -> String {
207        let mut result = template.to_string();
208
209        // Common faker patterns
210        let patterns = vec![
211            ("{{faker.email}}", self.faker.email()),
212            ("{{faker.name}}", self.faker.name()),
213            ("{{faker.uuid}}", self.faker.uuid()),
214            ("{{faker.int}}", self.faker.int_range(0, 1000).to_string()),
215            ("{{faker.word}}", self.faker.word()),
216            ("{{faker.sentence}}", self.faker.sentence()),
217            ("{{faker.paragraph}}", self.faker.paragraph()),
218            ("{{faker.date}}", self.faker.date_iso()),
219            ("{{faker.url}}", self.faker.url()),
220            ("{{faker.phone}}", self.faker.phone()),
221            ("{{faker.company}}", self.faker.company()),
222        ];
223
224        for (pattern, replacement) in patterns {
225            result = result.replace(pattern, &replacement);
226        }
227
228        result
229    }
230
231    /// Generate a complex object from template
232    pub fn generate_object(&mut self, templates: HashMap<String, String>) -> Value {
233        let mut object = serde_json::Map::new();
234
235        for (key, template) in templates {
236            object.insert(key, self.generate_from_template(&template));
237        }
238
239        Value::Object(object)
240    }
241}
242
243impl Default for TemplateFaker {
244    fn default() -> Self {
245        Self::new()
246    }
247}
248
249/// Quick faker functions for common use cases
250pub mod quick {
251    use super::*;
252
253    /// Generate a random email
254    pub fn email() -> String {
255        EnhancedFaker::new().email()
256    }
257
258    /// Generate a random name
259    pub fn name() -> String {
260        EnhancedFaker::new().name()
261    }
262
263    /// Generate a random UUID
264    pub fn uuid() -> String {
265        EnhancedFaker::new().uuid()
266    }
267
268    /// Generate a random integer
269    pub fn int(min: i64, max: i64) -> i64 {
270        EnhancedFaker::new().int_range(min, max)
271    }
272
273    /// Generate a random string
274    pub fn string(length: usize) -> String {
275        EnhancedFaker::new().string(length)
276    }
277}
278
279#[cfg(test)]
280mod tests {
281    use super::*;
282
283    #[test]
284    fn test_enhanced_faker_new() {
285        let _faker = EnhancedFaker::new();
286        // Should create successfully
287    }
288
289    #[test]
290    fn test_enhanced_faker_default() {
291        let _faker = EnhancedFaker;
292        // Should create successfully
293    }
294
295    #[test]
296    fn test_uuid_generation() {
297        let mut faker = EnhancedFaker::new();
298        let uuid = faker.uuid();
299
300        // Should have correct UUID format (36 chars with dashes)
301        assert_eq!(uuid.len(), 36);
302        assert!(uuid.contains('-'));
303    }
304
305    #[test]
306    fn test_int_range() {
307        let mut faker = EnhancedFaker::new();
308        let value = faker.int_range(1, 10);
309
310        assert!(value >= 1);
311        assert!(value <= 10);
312    }
313
314    #[test]
315    fn test_float_range() {
316        let mut faker = EnhancedFaker::new();
317        let value = faker.float_range(0.0, 1.0);
318
319        assert!(value >= 0.0);
320        assert!(value <= 1.0);
321    }
322
323    #[test]
324    fn test_boolean() {
325        let mut faker = EnhancedFaker::new();
326        let _value = faker.boolean(0.5);
327
328        // Boolean generation should not panic
329    }
330
331    #[test]
332    fn test_boolean_always_true() {
333        let mut faker = EnhancedFaker::new();
334        let value = faker.boolean(1.0);
335
336        assert!(value);
337    }
338
339    #[test]
340    fn test_boolean_always_false() {
341        let mut faker = EnhancedFaker::new();
342        let value = faker.boolean(0.0);
343
344        assert!(!value);
345    }
346
347    #[test]
348    fn test_string_generation() {
349        let mut faker = EnhancedFaker::new();
350        let s = faker.string(10);
351
352        // Should generate a string (actual length may vary due to words)
353        assert!(!s.is_empty());
354    }
355
356    #[test]
357    fn test_email_generation() {
358        let mut faker = EnhancedFaker::new();
359        let email = faker.email();
360
361        assert!(!email.is_empty());
362        assert!(email.contains('@'));
363    }
364
365    #[test]
366    fn test_name_generation() {
367        let mut faker = EnhancedFaker::new();
368        let name = faker.name();
369
370        assert!(!name.is_empty());
371    }
372
373    #[test]
374    fn test_address_generation() {
375        let mut faker = EnhancedFaker::new();
376        let address = faker.address();
377
378        assert!(!address.is_empty());
379    }
380
381    #[test]
382    fn test_phone_generation() {
383        let mut faker = EnhancedFaker::new();
384        let phone = faker.phone();
385
386        assert!(!phone.is_empty());
387    }
388
389    #[test]
390    fn test_company_generation() {
391        let mut faker = EnhancedFaker::new();
392        let company = faker.company();
393
394        assert!(!company.is_empty());
395    }
396
397    #[test]
398    fn test_date_iso_generation() {
399        let mut faker = EnhancedFaker::new();
400        let date = faker.date_iso();
401
402        assert!(!date.is_empty());
403        // Should contain 'T' from ISO format
404        assert!(date.contains('T') || date.contains('-'));
405    }
406
407    #[test]
408    fn test_url_generation() {
409        let mut faker = EnhancedFaker::new();
410        let url = faker.url();
411
412        assert!(url.starts_with("https://"));
413    }
414
415    #[test]
416    fn test_ip_address_generation() {
417        let mut faker = EnhancedFaker::new();
418        let ip = faker.ip_address();
419
420        assert!(!ip.is_empty());
421        assert!(ip.contains('.'));
422    }
423
424    #[test]
425    fn test_color_generation() {
426        let mut faker = EnhancedFaker::new();
427        let color = faker.color();
428
429        let valid_colors = [
430            "red", "blue", "green", "yellow", "purple", "orange", "pink", "brown", "black", "white",
431        ];
432        assert!(valid_colors.contains(&color.as_str()));
433    }
434
435    #[test]
436    fn test_word_generation() {
437        let mut faker = EnhancedFaker::new();
438        let word = faker.word();
439
440        assert!(!word.is_empty());
441    }
442
443    #[test]
444    fn test_words_generation() {
445        let mut faker = EnhancedFaker::new();
446        let words = faker.words(5);
447
448        assert_eq!(words.len(), 5);
449    }
450
451    #[test]
452    fn test_sentence_generation() {
453        let mut faker = EnhancedFaker::new();
454        let sentence = faker.sentence();
455
456        assert!(!sentence.is_empty());
457    }
458
459    #[test]
460    fn test_paragraph_generation() {
461        let mut faker = EnhancedFaker::new();
462        let paragraph = faker.paragraph();
463
464        assert!(!paragraph.is_empty());
465    }
466
467    #[test]
468    fn test_random_element_success() {
469        let mut faker = EnhancedFaker::new();
470        let items = ["a", "b", "c", "d"];
471        let element = faker.random_element(&items);
472
473        assert!(element.is_some());
474        assert!(items.contains(element.unwrap()));
475    }
476
477    #[test]
478    fn test_random_element_empty_list() {
479        let mut faker = EnhancedFaker::new();
480        let items: [&str; 0] = [];
481        let element = faker.random_element(&items);
482
483        assert!(element.is_none());
484    }
485
486    #[test]
487    fn test_generate_by_type_string() {
488        let mut faker = EnhancedFaker::new();
489        let result = faker.generate_by_type("string");
490
491        assert!(matches!(result, Value::String(_)));
492    }
493
494    #[test]
495    fn test_generate_by_type_email() {
496        let mut faker = EnhancedFaker::new();
497        let result = faker.generate_by_type("email");
498
499        if let Value::String(s) = result {
500            assert!(s.contains('@'));
501        } else {
502            panic!("Expected string value");
503        }
504    }
505
506    #[test]
507    fn test_generate_by_type_int() {
508        let mut faker = EnhancedFaker::new();
509        let result = faker.generate_by_type("int");
510
511        assert!(matches!(result, Value::Number(_)));
512    }
513
514    #[test]
515    fn test_generate_by_type_bool() {
516        let mut faker = EnhancedFaker::new();
517        let result = faker.generate_by_type("bool");
518
519        assert!(matches!(result, Value::Bool(_)));
520    }
521
522    #[test]
523    fn test_generate_by_type_uuid() {
524        let mut faker = EnhancedFaker::new();
525        let result = faker.generate_by_type("uuid");
526
527        if let Value::String(s) = result {
528            assert_eq!(s.len(), 36);
529        } else {
530            panic!("Expected string value");
531        }
532    }
533
534    #[test]
535    fn test_template_faker_new() {
536        let _faker = TemplateFaker::new();
537    }
538
539    #[test]
540    fn test_template_faker_default() {
541        let _faker = TemplateFaker::default();
542    }
543
544    #[test]
545    fn test_template_faker_with_variable() {
546        let faker = TemplateFaker::new()
547            .with_variable("name".to_string(), Value::String("John".to_string()));
548
549        assert_eq!(faker.variables.len(), 1);
550        assert_eq!(faker.variables.get("name"), Some(&Value::String("John".to_string())));
551    }
552
553    #[test]
554    fn test_template_faker_generate_from_template() {
555        let mut faker = TemplateFaker::new()
556            .with_variable("name".to_string(), Value::String("Alice".to_string()));
557
558        let result = faker.generate_from_template("Hello {{name}}!");
559
560        if let Value::String(s) = result {
561            assert!(s.contains("Alice"));
562        } else {
563            panic!("Expected string value");
564        }
565    }
566
567    #[test]
568    fn test_template_faker_generate_object() {
569        let mut faker = TemplateFaker::new()
570            .with_variable("user".to_string(), Value::String("Bob".to_string()));
571
572        let mut templates = HashMap::new();
573        templates.insert("greeting".to_string(), "Hello {{user}}".to_string());
574        templates.insert("farewell".to_string(), "Goodbye {{user}}".to_string());
575
576        let result = faker.generate_object(templates);
577
578        if let Value::Object(obj) = result {
579            assert!(obj.contains_key("greeting"));
580            assert!(obj.contains_key("farewell"));
581        } else {
582            panic!("Expected object value");
583        }
584    }
585
586    #[test]
587    fn test_quick_email() {
588        let email = quick::email();
589        assert!(!email.is_empty());
590        assert!(email.contains('@'));
591    }
592
593    #[test]
594    fn test_quick_name() {
595        let name = quick::name();
596        assert!(!name.is_empty());
597    }
598
599    #[test]
600    fn test_quick_uuid() {
601        let uuid = quick::uuid();
602        assert_eq!(uuid.len(), 36);
603        assert!(uuid.contains('-'));
604    }
605
606    #[test]
607    fn test_quick_int() {
608        let value = quick::int(1, 10);
609        assert!(value >= 1);
610        assert!(value <= 10);
611    }
612
613    #[test]
614    fn test_quick_string() {
615        let s = quick::string(10);
616        assert!(!s.is_empty());
617    }
618
619    #[test]
620    fn test_generate_by_type_unknown() {
621        let mut faker = EnhancedFaker::new();
622        let result = faker.generate_by_type("unknown_type");
623
624        if let Value::String(s) = result {
625            assert!(s.contains("unknown_type"));
626        } else {
627            panic!("Expected string value");
628        }
629    }
630
631    #[test]
632    fn test_template_faker_multiple_variables() {
633        let faker = TemplateFaker::new()
634            .with_variable("first".to_string(), Value::String("John".to_string()))
635            .with_variable("last".to_string(), Value::String("Doe".to_string()));
636
637        assert_eq!(faker.variables.len(), 2);
638    }
639
640    #[test]
641    fn test_template_faker_generate_with_faker_pattern() {
642        let mut faker = TemplateFaker::new();
643        let result = faker.generate_from_template("Email: {{faker.email}}");
644
645        if let Value::String(s) = result {
646            assert!(s.contains("Email:"));
647            assert!(!s.contains("{{faker.email}}"));
648        } else {
649            panic!("Expected string value");
650        }
651    }
652}