Skip to main content

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            "object" => Value::Object(serde_json::Map::new()),
157            "array" => Value::Array(vec![]),
158            "word" => Value::String(self.word()),
159            "sentence" => Value::String(self.sentence()),
160            "paragraph" => Value::String(self.paragraph()),
161            _ => Value::String(format!("unknown_type_{}", field_type)),
162        }
163    }
164}
165
166/// Template-based faker for complex data generation
167#[derive(Debug)]
168pub struct TemplateFaker {
169    /// Base faker
170    faker: EnhancedFaker,
171    /// Template variables
172    variables: HashMap<String, Value>,
173}
174
175impl TemplateFaker {
176    /// Create a new template faker
177    pub fn new() -> Self {
178        Self {
179            faker: EnhancedFaker::new(),
180            variables: HashMap::new(),
181        }
182    }
183
184    /// Add a template variable
185    pub fn with_variable(mut self, key: String, value: Value) -> Self {
186        self.variables.insert(key, value);
187        self
188    }
189
190    /// Generate data from a template string
191    pub fn generate_from_template(&mut self, template: &str) -> Value {
192        let mut result = template.to_string();
193
194        // Replace {{variable}} patterns
195        for (key, value) in &self.variables {
196            let pattern = format!("{{{{{}}}}}", key);
197            let replacement = value.to_string().trim_matches('"').to_string(); // Remove quotes if present
198            result = result.replace(&pattern, &replacement);
199        }
200
201        // Replace faker patterns like {{faker.email}}
202        result = self.replace_faker_patterns(&result);
203
204        Value::String(result)
205    }
206
207    /// Replace faker patterns in template
208    fn replace_faker_patterns(&mut self, template: &str) -> String {
209        let mut result = template.to_string();
210
211        // Common faker patterns
212        let patterns = vec![
213            ("{{faker.email}}", self.faker.email()),
214            ("{{faker.name}}", self.faker.name()),
215            ("{{faker.uuid}}", self.faker.uuid()),
216            ("{{faker.int}}", self.faker.int_range(0, 1000).to_string()),
217            ("{{faker.word}}", self.faker.word()),
218            ("{{faker.sentence}}", self.faker.sentence()),
219            ("{{faker.paragraph}}", self.faker.paragraph()),
220            ("{{faker.date}}", self.faker.date_iso()),
221            ("{{faker.url}}", self.faker.url()),
222            ("{{faker.phone}}", self.faker.phone()),
223            ("{{faker.company}}", self.faker.company()),
224        ];
225
226        for (pattern, replacement) in patterns {
227            result = result.replace(pattern, &replacement);
228        }
229
230        result
231    }
232
233    /// Generate a complex object from template
234    pub fn generate_object(&mut self, templates: HashMap<String, String>) -> Value {
235        let mut object = serde_json::Map::new();
236
237        for (key, template) in templates {
238            object.insert(key, self.generate_from_template(&template));
239        }
240
241        Value::Object(object)
242    }
243}
244
245impl Default for TemplateFaker {
246    fn default() -> Self {
247        Self::new()
248    }
249}
250
251/// Quick faker functions for common use cases
252pub mod quick {
253    use super::*;
254
255    /// Generate a random email
256    pub fn email() -> String {
257        EnhancedFaker::new().email()
258    }
259
260    /// Generate a random name
261    pub fn name() -> String {
262        EnhancedFaker::new().name()
263    }
264
265    /// Generate a random UUID
266    pub fn uuid() -> String {
267        EnhancedFaker::new().uuid()
268    }
269
270    /// Generate a random integer
271    pub fn int(min: i64, max: i64) -> i64 {
272        EnhancedFaker::new().int_range(min, max)
273    }
274
275    /// Generate a random string
276    pub fn string(length: usize) -> String {
277        EnhancedFaker::new().string(length)
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use super::*;
284
285    #[test]
286    fn test_enhanced_faker_new() {
287        let _faker = EnhancedFaker::new();
288        // Should create successfully
289    }
290
291    #[test]
292    fn test_enhanced_faker_default() {
293        let _faker = EnhancedFaker;
294        // Should create successfully
295    }
296
297    #[test]
298    fn test_uuid_generation() {
299        let mut faker = EnhancedFaker::new();
300        let uuid = faker.uuid();
301
302        // Should have correct UUID format (36 chars with dashes)
303        assert_eq!(uuid.len(), 36);
304        assert!(uuid.contains('-'));
305    }
306
307    #[test]
308    fn test_int_range() {
309        let mut faker = EnhancedFaker::new();
310        let value = faker.int_range(1, 10);
311
312        assert!(value >= 1);
313        assert!(value <= 10);
314    }
315
316    #[test]
317    fn test_float_range() {
318        let mut faker = EnhancedFaker::new();
319        let value = faker.float_range(0.0, 1.0);
320
321        assert!(value >= 0.0);
322        assert!(value <= 1.0);
323    }
324
325    #[test]
326    fn test_boolean() {
327        let mut faker = EnhancedFaker::new();
328        let _value = faker.boolean(0.5);
329
330        // Boolean generation should not panic
331    }
332
333    #[test]
334    fn test_boolean_always_true() {
335        let mut faker = EnhancedFaker::new();
336        let value = faker.boolean(1.0);
337
338        assert!(value);
339    }
340
341    #[test]
342    fn test_boolean_always_false() {
343        let mut faker = EnhancedFaker::new();
344        let value = faker.boolean(0.0);
345
346        assert!(!value);
347    }
348
349    #[test]
350    fn test_string_generation() {
351        let mut faker = EnhancedFaker::new();
352        let s = faker.string(10);
353
354        // Should generate a string (actual length may vary due to words)
355        assert!(!s.is_empty());
356    }
357
358    #[test]
359    fn test_email_generation() {
360        let mut faker = EnhancedFaker::new();
361        let email = faker.email();
362
363        assert!(!email.is_empty());
364        assert!(email.contains('@'));
365    }
366
367    #[test]
368    fn test_name_generation() {
369        let mut faker = EnhancedFaker::new();
370        let name = faker.name();
371
372        assert!(!name.is_empty());
373    }
374
375    #[test]
376    fn test_address_generation() {
377        let mut faker = EnhancedFaker::new();
378        let address = faker.address();
379
380        assert!(!address.is_empty());
381    }
382
383    #[test]
384    fn test_phone_generation() {
385        let mut faker = EnhancedFaker::new();
386        let phone = faker.phone();
387
388        assert!(!phone.is_empty());
389    }
390
391    #[test]
392    fn test_company_generation() {
393        let mut faker = EnhancedFaker::new();
394        let company = faker.company();
395
396        assert!(!company.is_empty());
397    }
398
399    #[test]
400    fn test_date_iso_generation() {
401        let mut faker = EnhancedFaker::new();
402        let date = faker.date_iso();
403
404        assert!(!date.is_empty());
405        // Should contain 'T' from ISO format
406        assert!(date.contains('T') || date.contains('-'));
407    }
408
409    #[test]
410    fn test_url_generation() {
411        let mut faker = EnhancedFaker::new();
412        let url = faker.url();
413
414        assert!(url.starts_with("https://"));
415    }
416
417    #[test]
418    fn test_ip_address_generation() {
419        let mut faker = EnhancedFaker::new();
420        let ip = faker.ip_address();
421
422        assert!(!ip.is_empty());
423        assert!(ip.contains('.'));
424    }
425
426    #[test]
427    fn test_color_generation() {
428        let mut faker = EnhancedFaker::new();
429        let color = faker.color();
430
431        let valid_colors = [
432            "red", "blue", "green", "yellow", "purple", "orange", "pink", "brown", "black", "white",
433        ];
434        assert!(valid_colors.contains(&color.as_str()));
435    }
436
437    #[test]
438    fn test_word_generation() {
439        let mut faker = EnhancedFaker::new();
440        let word = faker.word();
441
442        assert!(!word.is_empty());
443    }
444
445    #[test]
446    fn test_words_generation() {
447        let mut faker = EnhancedFaker::new();
448        let words = faker.words(5);
449
450        assert_eq!(words.len(), 5);
451    }
452
453    #[test]
454    fn test_sentence_generation() {
455        let mut faker = EnhancedFaker::new();
456        let sentence = faker.sentence();
457
458        assert!(!sentence.is_empty());
459    }
460
461    #[test]
462    fn test_paragraph_generation() {
463        let mut faker = EnhancedFaker::new();
464        let paragraph = faker.paragraph();
465
466        assert!(!paragraph.is_empty());
467    }
468
469    #[test]
470    fn test_random_element_success() {
471        let mut faker = EnhancedFaker::new();
472        let items = ["a", "b", "c", "d"];
473        let element = faker.random_element(&items);
474
475        assert!(element.is_some());
476        assert!(items.contains(element.unwrap()));
477    }
478
479    #[test]
480    fn test_random_element_empty_list() {
481        let mut faker = EnhancedFaker::new();
482        let items: [&str; 0] = [];
483        let element = faker.random_element(&items);
484
485        assert!(element.is_none());
486    }
487
488    #[test]
489    fn test_generate_by_type_string() {
490        let mut faker = EnhancedFaker::new();
491        let result = faker.generate_by_type("string");
492
493        assert!(matches!(result, Value::String(_)));
494    }
495
496    #[test]
497    fn test_generate_by_type_email() {
498        let mut faker = EnhancedFaker::new();
499        let result = faker.generate_by_type("email");
500
501        if let Value::String(s) = result {
502            assert!(s.contains('@'));
503        } else {
504            panic!("Expected string value");
505        }
506    }
507
508    #[test]
509    fn test_generate_by_type_int() {
510        let mut faker = EnhancedFaker::new();
511        let result = faker.generate_by_type("int");
512
513        assert!(matches!(result, Value::Number(_)));
514    }
515
516    #[test]
517    fn test_generate_by_type_bool() {
518        let mut faker = EnhancedFaker::new();
519        let result = faker.generate_by_type("bool");
520
521        assert!(matches!(result, Value::Bool(_)));
522    }
523
524    #[test]
525    fn test_generate_by_type_uuid() {
526        let mut faker = EnhancedFaker::new();
527        let result = faker.generate_by_type("uuid");
528
529        if let Value::String(s) = result {
530            assert_eq!(s.len(), 36);
531        } else {
532            panic!("Expected string value");
533        }
534    }
535
536    #[test]
537    fn test_template_faker_new() {
538        let _faker = TemplateFaker::new();
539    }
540
541    #[test]
542    fn test_template_faker_default() {
543        let _faker = TemplateFaker::default();
544    }
545
546    #[test]
547    fn test_template_faker_with_variable() {
548        let faker = TemplateFaker::new()
549            .with_variable("name".to_string(), Value::String("John".to_string()));
550
551        assert_eq!(faker.variables.len(), 1);
552        assert_eq!(faker.variables.get("name"), Some(&Value::String("John".to_string())));
553    }
554
555    #[test]
556    fn test_template_faker_generate_from_template() {
557        let mut faker = TemplateFaker::new()
558            .with_variable("name".to_string(), Value::String("Alice".to_string()));
559
560        let result = faker.generate_from_template("Hello {{name}}!");
561
562        if let Value::String(s) = result {
563            assert!(s.contains("Alice"));
564        } else {
565            panic!("Expected string value");
566        }
567    }
568
569    #[test]
570    fn test_template_faker_generate_object() {
571        let mut faker = TemplateFaker::new()
572            .with_variable("user".to_string(), Value::String("Bob".to_string()));
573
574        let mut templates = HashMap::new();
575        templates.insert("greeting".to_string(), "Hello {{user}}".to_string());
576        templates.insert("farewell".to_string(), "Goodbye {{user}}".to_string());
577
578        let result = faker.generate_object(templates);
579
580        if let Value::Object(obj) = result {
581            assert!(obj.contains_key("greeting"));
582            assert!(obj.contains_key("farewell"));
583        } else {
584            panic!("Expected object value");
585        }
586    }
587
588    #[test]
589    fn test_quick_email() {
590        let email = quick::email();
591        assert!(!email.is_empty());
592        assert!(email.contains('@'));
593    }
594
595    #[test]
596    fn test_quick_name() {
597        let name = quick::name();
598        assert!(!name.is_empty());
599    }
600
601    #[test]
602    fn test_quick_uuid() {
603        let uuid = quick::uuid();
604        assert_eq!(uuid.len(), 36);
605        assert!(uuid.contains('-'));
606    }
607
608    #[test]
609    fn test_quick_int() {
610        let value = quick::int(1, 10);
611        assert!(value >= 1);
612        assert!(value <= 10);
613    }
614
615    #[test]
616    fn test_quick_string() {
617        let s = quick::string(10);
618        assert!(!s.is_empty());
619    }
620
621    #[test]
622    fn test_generate_by_type_unknown() {
623        let mut faker = EnhancedFaker::new();
624        let result = faker.generate_by_type("unknown_type");
625
626        if let Value::String(s) = result {
627            assert!(s.contains("unknown_type"));
628        } else {
629            panic!("Expected string value");
630        }
631    }
632
633    #[test]
634    fn test_template_faker_multiple_variables() {
635        let faker = TemplateFaker::new()
636            .with_variable("first".to_string(), Value::String("John".to_string()))
637            .with_variable("last".to_string(), Value::String("Doe".to_string()));
638
639        assert_eq!(faker.variables.len(), 2);
640    }
641
642    #[test]
643    fn test_template_faker_generate_with_faker_pattern() {
644        let mut faker = TemplateFaker::new();
645        let result = faker.generate_from_template("Email: {{faker.email}}");
646
647        if let Value::String(s) = result {
648            assert!(s.contains("Email:"));
649            assert!(!s.contains("{{faker.email}}"));
650        } else {
651            panic!("Expected string value");
652        }
653    }
654}