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