mockforge_grpc/reflection/
smart_mock_generator.rs

1//! Smart mock data generator for gRPC services
2//!
3//! This module provides intelligent mock data generation based on field names,
4//! types, and context. It integrates with the mockforge-data faker system
5//! to generate realistic test data.
6
7use prost_reflect::{DynamicMessage, FieldDescriptor, Kind, MessageDescriptor, Value};
8use rand::rngs::StdRng;
9use rand::{Rng, SeedableRng};
10use std::collections::HashMap;
11use tracing::debug;
12
13#[cfg(feature = "data-faker")]
14use mockforge_data::faker::EnhancedFaker;
15
16// Re-export fake for direct use
17#[cfg(feature = "data-faker")]
18use fake::{
19    faker::name::en::{FirstName, LastName},
20    Fake,
21};
22
23/// Configuration for smart mock data generation
24#[derive(Debug, Clone)]
25pub struct SmartMockConfig {
26    /// Enable field name-based intelligent generation
27    pub field_name_inference: bool,
28    /// Enable faker integration for realistic data
29    pub use_faker: bool,
30    /// Custom field mappings (field_name -> mock_value)
31    pub field_overrides: HashMap<String, String>,
32    /// Service-specific data generation profiles
33    pub service_profiles: HashMap<String, ServiceProfile>,
34    /// Maximum recursion depth for nested messages
35    pub max_depth: usize,
36    /// Deterministic seed for reproducible data generation
37    pub seed: Option<u64>,
38    /// Whether to use deterministic generation for stable fixtures
39    pub deterministic: bool,
40}
41
42impl Default for SmartMockConfig {
43    fn default() -> Self {
44        Self {
45            field_name_inference: true,
46            use_faker: true,
47            field_overrides: HashMap::new(),
48            service_profiles: HashMap::new(),
49            max_depth: 5,
50            seed: None,
51            deterministic: false,
52        }
53    }
54}
55
56/// Service-specific data generation profile
57#[derive(Debug, Clone)]
58pub struct ServiceProfile {
59    /// Custom field mappings for this service
60    pub field_mappings: HashMap<String, String>,
61    /// Realistic data patterns to use
62    pub data_patterns: Vec<DataPattern>,
63    /// Whether to use sequential numbering for IDs
64    pub sequential_ids: bool,
65}
66
67/// Data generation patterns
68#[derive(Debug, Clone)]
69pub enum DataPattern {
70    /// User-related data (names, emails, etc.)
71    User,
72    /// Product/inventory data
73    Product,
74    /// Financial/transaction data
75    Financial,
76    /// Address/location data
77    Location,
78    /// Custom pattern with field mappings
79    Custom(HashMap<String, String>),
80}
81
82/// Smart mock data generator
83pub struct SmartMockGenerator {
84    config: SmartMockConfig,
85    /// Counter for sequential data generation
86    sequence_counter: u64,
87    /// Enhanced faker for realistic data generation
88    #[cfg(feature = "data-faker")]
89    faker: Option<EnhancedFaker>,
90    /// Seeded random number generator for deterministic generation
91    rng: Option<StdRng>,
92}
93
94impl SmartMockGenerator {
95    /// Create a new smart mock generator
96    pub fn new(config: SmartMockConfig) -> Self {
97        #[cfg(feature = "data-faker")]
98        let faker = if config.use_faker {
99            Some(EnhancedFaker::new())
100        } else {
101            None
102        };
103
104        // Initialize seeded RNG if deterministic mode is enabled
105        let rng = if config.deterministic {
106            let seed = config.seed.unwrap_or(42); // Default seed if none provided
107            Some(StdRng::seed_from_u64(seed))
108        } else {
109            None
110        };
111
112        Self {
113            config,
114            sequence_counter: 1,
115            #[cfg(feature = "data-faker")]
116            faker,
117            rng,
118        }
119    }
120
121    /// Create a new deterministic generator with a specific seed
122    pub fn new_with_seed(mut config: SmartMockConfig, seed: u64) -> Self {
123        config.seed = Some(seed);
124        config.deterministic = true;
125        Self::new(config)
126    }
127
128    /// Reset the generator to its initial state (useful for reproducible tests)
129    pub fn reset(&mut self) {
130        self.sequence_counter = 1;
131        if let Some(seed) = self.config.seed {
132            self.rng = Some(StdRng::seed_from_u64(seed));
133        }
134    }
135
136    /// Generate a deterministic random number
137    fn next_random<T>(&mut self) -> T
138    where
139        rand::distr::StandardUniform: rand::distr::Distribution<T>,
140    {
141        if let Some(ref mut rng) = self.rng {
142            rng.random()
143        } else {
144            rand::random()
145        }
146    }
147
148    /// Generate a deterministic random number within a range
149    ///
150    /// TODO: Use in smart generation features when range-based field inference is implemented
151    #[allow(dead_code)] // TODO: Remove when range-based smart generation is implemented
152    fn next_random_range(&mut self, min: i64, max: i64) -> i64 {
153        if let Some(ref mut rng) = self.rng {
154            rng.random_range(min..=max)
155        } else {
156            rand::rng().random_range(min..=max)
157        }
158    }
159
160    /// Generate a mock value for a field with intelligent inference
161    pub fn generate_value_for_field(
162        &mut self,
163        field: &FieldDescriptor,
164        service_name: &str,
165        method_name: &str,
166        depth: usize,
167    ) -> Value {
168        if depth >= self.config.max_depth {
169            return self.generate_depth_limit_value(field);
170        }
171
172        let field_name = field.name().to_lowercase();
173
174        debug!(
175            "Generating smart mock value for field: {} (type: {:?}) in service: {}, method: {}",
176            field.name(),
177            field.kind(),
178            service_name,
179            method_name
180        );
181
182        // Check for field overrides first
183        if let Some(override_value) = self.config.field_overrides.get(&field_name) {
184            return self.parse_override_value(override_value, field);
185        }
186
187        // Check service profile mappings
188        if let Some(profile) = self.config.service_profiles.get(service_name) {
189            if let Some(mapping) = profile.field_mappings.get(&field_name) {
190                return self.parse_override_value(mapping, field);
191            }
192        }
193
194        // Use intelligent field name inference
195        if self.config.field_name_inference {
196            if let Some(value) = self.infer_value_from_field_name(&field_name, field) {
197                return value;
198            }
199        }
200
201        // Use faker system if available
202        #[cfg(feature = "data-faker")]
203        if self.config.use_faker && self.faker.is_some() {
204            if let Some(value) = self.generate_with_faker_safe(field) {
205                return value;
206            }
207        }
208
209        // Fallback to basic type-based generation
210        self.generate_basic_value_for_type(field, depth)
211    }
212
213    /// Infer mock value based on field name patterns
214    fn infer_value_from_field_name(
215        &mut self,
216        field_name: &str,
217        field: &FieldDescriptor,
218    ) -> Option<Value> {
219        match field.kind() {
220            Kind::String => {
221                let mock_value = match field_name {
222                    // Identity fields - enhanced with more realistic fallbacks
223                    name if name.contains("email") => {
224                        // Use faker first, fallback to pattern
225                        #[cfg(feature = "data-faker")]
226                        if let Some(faker) = &mut self.faker {
227                            faker.email()
228                        } else {
229                            format!("user{}@example.com", self.next_sequence())
230                        }
231                        #[cfg(not(feature = "data-faker"))]
232                        format!("user{}@example.com", self.next_sequence())
233                    }
234                    name if name.contains("name") && name.contains("first") => {
235                        #[cfg(feature = "data-faker")]
236                        if let Some(_faker) = &mut self.faker {
237                            FirstName().fake()
238                        } else {
239                            "John".to_string()
240                        }
241                        #[cfg(not(feature = "data-faker"))]
242                        "John".to_string()
243                    }
244                    name if name.contains("name") && name.contains("last") => {
245                        #[cfg(feature = "data-faker")]
246                        if let Some(_faker) = &mut self.faker {
247                            LastName().fake()
248                        } else {
249                            "Doe".to_string()
250                        }
251                        #[cfg(not(feature = "data-faker"))]
252                        "Doe".to_string()
253                    }
254                    name if name.contains("username") => format!("user{}", self.next_sequence()),
255                    name if name.contains("full_name") || name.contains("display_name") => {
256                        #[cfg(feature = "data-faker")]
257                        if let Some(faker) = &mut self.faker {
258                            faker.name()
259                        } else {
260                            "John Doe".to_string()
261                        }
262                        #[cfg(not(feature = "data-faker"))]
263                        "John Doe".to_string()
264                    }
265
266                    // Contact information
267                    name if name.contains("phone") => "+1-555-123-4567".to_string(),
268                    name if name.contains("address") => "123 Main Street".to_string(),
269                    name if name.contains("city") => "San Francisco".to_string(),
270                    name if name.contains("state") || name.contains("region") => {
271                        "California".to_string()
272                    }
273                    name if name.contains("country") => "United States".to_string(),
274                    name if name.contains("zip") || name.contains("postal") => "94102".to_string(),
275
276                    // Product/business fields
277                    name if name.contains("title") => "Sample Product".to_string(),
278                    name if name.contains("description") => {
279                        "This is a sample product description".to_string()
280                    }
281                    name if name.contains("sku") || name.contains("product_id") => {
282                        format!("SKU{:06}", self.next_sequence())
283                    }
284                    name if name.contains("category") => "Electronics".to_string(),
285                    name if name.contains("brand") => "MockForge".to_string(),
286
287                    // Technical fields
288                    name if name.contains("url") || name.contains("link") => {
289                        "https://example.com".to_string()
290                    }
291                    name if name.contains("token") => {
292                        format!("token_{}", self.generate_random_string(16))
293                    }
294                    name if name.contains("uuid") || name.contains("guid") => self.generate_uuid(),
295                    name if name.contains("hash") => self.generate_random_string(32),
296                    name if name.contains("version") => "1.0.0".to_string(),
297                    name if name.contains("status") => "active".to_string(),
298
299                    // Default patterns
300                    _ => return None,
301                };
302                Some(Value::String(mock_value))
303            }
304            Kind::Int32 | Kind::Int64 => {
305                let mock_value = match field_name {
306                    // ID fields
307                    name if name.contains("id") || name.contains("identifier") => {
308                        self.next_sequence()
309                    }
310
311                    // Quantity/count fields
312                    name if name.contains("count") || name.contains("quantity") => {
313                        (self.next_random::<u32>() % 100 + 1) as u64
314                    }
315                    name if name.contains("age") => (self.next_random::<u32>() % 80 + 18) as u64,
316                    name if name.contains("year") => (self.next_random::<u32>() % 30 + 1995) as u64,
317
318                    // Size/dimension fields
319                    name if name.contains("width")
320                        || name.contains("height")
321                        || name.contains("length") =>
322                    {
323                        (self.next_random::<u32>() % 1000 + 100) as u64
324                    }
325                    name if name.contains("weight") => {
326                        (self.next_random::<u32>() % 1000 + 1) as u64
327                    }
328
329                    _ => return None,
330                };
331
332                Some(match field.kind() {
333                    Kind::Int32 => Value::I32(mock_value as i32),
334                    Kind::Int64 => Value::I64(mock_value as i64),
335                    _ => unreachable!(),
336                })
337            }
338            Kind::Double | Kind::Float => {
339                let mock_value = match field_name {
340                    name if name.contains("price") || name.contains("cost") => {
341                        self.next_random::<f64>() * 1000.0 + 10.0
342                    }
343                    name if name.contains("rate") || name.contains("percentage") => {
344                        self.next_random::<f64>() * 100.0
345                    }
346                    name if name.contains("latitude") => self.next_random::<f64>() * 180.0 - 90.0,
347                    name if name.contains("longitude") => self.next_random::<f64>() * 360.0 - 180.0,
348                    _ => return None,
349                };
350
351                Some(match field.kind() {
352                    Kind::Double => Value::F64(mock_value),
353                    Kind::Float => Value::F32(mock_value as f32),
354                    _ => unreachable!(),
355                })
356            }
357            Kind::Bool => {
358                let mock_value = match field_name {
359                    name if name.contains("active") || name.contains("enabled") => true,
360                    name if name.contains("verified") || name.contains("confirmed") => true,
361                    name if name.contains("deleted") || name.contains("archived") => false,
362                    _ => self.next_random::<bool>(),
363                };
364                Some(Value::Bool(mock_value))
365            }
366            _ => None,
367        }
368    }
369
370    /// Generate value using the enhanced faker system (safe version)
371    #[cfg(feature = "data-faker")]
372    fn generate_with_faker_safe(&mut self, field: &FieldDescriptor) -> Option<Value> {
373        let faker = self.faker.as_mut()?;
374        let field_name = field.name().to_lowercase();
375
376        match field.kind() {
377            Kind::String => {
378                let fake_data = match field_name.as_str() {
379                    // Email patterns
380                    name if name.contains("email") => faker.email(),
381
382                    // Name patterns
383                    name if name.contains("first") && name.contains("name") => FirstName().fake(),
384                    name if name.contains("last") && name.contains("name") => LastName().fake(),
385                    name if name.contains("name")
386                        && !name.contains("file")
387                        && !name.contains("path") =>
388                    {
389                        faker.name()
390                    }
391
392                    // Contact patterns
393                    name if name.contains("phone") || name.contains("mobile") => faker.phone(),
394                    name if name.contains("address") => faker.address(),
395
396                    // Company/Organization patterns
397                    name if name.contains("company") || name.contains("organization") => {
398                        faker.company()
399                    }
400
401                    // Web/Internet patterns
402                    name if name.contains("url") || name.contains("website") => faker.url(),
403                    name if name.contains("ip") => faker.ip_address(),
404
405                    // ID/UUID patterns
406                    name if name.contains("uuid") || name.contains("guid") => faker.uuid(),
407
408                    // Date patterns
409                    name if name.contains("date")
410                        || name.contains("time")
411                        || name.contains("created")
412                        || name.contains("updated") =>
413                    {
414                        faker.date_iso()
415                    }
416
417                    // Color patterns
418                    name if name.contains("color") || name.contains("colour") => faker.color(),
419
420                    // Default: use the field name inference for other patterns
421                    _ => return None,
422                };
423
424                Some(Value::String(fake_data))
425            }
426
427            Kind::Int32 | Kind::Int64 => {
428                let fake_value = match field_name.as_str() {
429                    // Age patterns
430                    name if name.contains("age") => faker.int_range(18, 90),
431
432                    // Year patterns
433                    name if name.contains("year") => faker.int_range(1990, 2024),
434
435                    // Count/quantity patterns
436                    name if name.contains("count")
437                        || name.contains("quantity")
438                        || name.contains("amount") =>
439                    {
440                        faker.int_range(1, 1000)
441                    }
442
443                    // Port numbers
444                    name if name.contains("port") => faker.int_range(1024, 65535),
445
446                    // Default: use sequence for IDs or random for others
447                    name if name.contains("id") || name.contains("identifier") => {
448                        self.next_sequence() as i64
449                    }
450                    _ => faker.int_range(1, 100),
451                };
452
453                Some(match field.kind() {
454                    Kind::Int32 => Value::I32(fake_value as i32),
455                    Kind::Int64 => Value::I64(fake_value),
456                    _ => unreachable!(),
457                })
458            }
459
460            Kind::Double | Kind::Float => {
461                let fake_value = match field_name.as_str() {
462                    // Price/money patterns
463                    name if name.contains("price")
464                        || name.contains("cost")
465                        || name.contains("amount") =>
466                    {
467                        faker.float_range(1.0, 1000.0)
468                    }
469
470                    // Percentage/rate patterns
471                    name if name.contains("rate") || name.contains("percent") => {
472                        faker.float_range(0.0, 100.0)
473                    }
474
475                    // Geographic coordinates
476                    name if name.contains("latitude") || name.contains("lat") => {
477                        faker.float_range(-90.0, 90.0)
478                    }
479                    name if name.contains("longitude")
480                        || name.contains("lng")
481                        || name.contains("lon") =>
482                    {
483                        faker.float_range(-180.0, 180.0)
484                    }
485
486                    // Default random float
487                    _ => faker.float_range(0.0, 100.0),
488                };
489
490                Some(match field.kind() {
491                    Kind::Double => Value::F64(fake_value),
492                    Kind::Float => Value::F32(fake_value as f32),
493                    _ => unreachable!(),
494                })
495            }
496
497            Kind::Bool => {
498                let probability = match field_name.as_str() {
499                    // Usually true patterns
500                    name if name.contains("active")
501                        || name.contains("enabled")
502                        || name.contains("verified") =>
503                    {
504                        0.8
505                    }
506
507                    // Usually false patterns
508                    name if name.contains("deleted")
509                        || name.contains("archived")
510                        || name.contains("disabled") =>
511                    {
512                        0.2
513                    }
514
515                    // Default 50/50
516                    _ => 0.5,
517                };
518
519                Some(Value::Bool(faker.boolean(probability)))
520            }
521
522            _ => None,
523        }
524    }
525
526    #[cfg(not(feature = "data-faker"))]
527    fn generate_with_faker_safe(&mut self, _field: &FieldDescriptor) -> Option<Value> {
528        None
529    }
530
531    /// Generate basic value based on type
532    fn generate_basic_value_for_type(&mut self, field: &FieldDescriptor, depth: usize) -> Value {
533        match field.kind() {
534            Kind::String => Value::String(format!("mock_{}", field.name())),
535            Kind::Int32 => Value::I32(self.next_sequence() as i32),
536            Kind::Int64 => Value::I64(self.next_sequence() as i64),
537            Kind::Uint32 => Value::U32(self.next_sequence() as u32),
538            Kind::Uint64 => Value::U64(self.next_sequence()),
539            Kind::Sint32 => Value::I32(self.next_sequence() as i32),
540            Kind::Sint64 => Value::I64(self.next_sequence() as i64),
541            Kind::Fixed32 => Value::U32(self.next_sequence() as u32),
542            Kind::Fixed64 => Value::U64(self.next_sequence()),
543            Kind::Sfixed32 => Value::I32(self.next_sequence() as i32),
544            Kind::Sfixed64 => Value::I64(self.next_sequence() as i64),
545            Kind::Bool => Value::Bool(self.next_sequence().is_multiple_of(2)),
546            Kind::Double => Value::F64(self.next_random::<f64>() * 100.0),
547            Kind::Float => Value::F32(self.next_random::<f32>() * 100.0),
548            Kind::Bytes => {
549                Value::Bytes(format!("bytes_{}", self.next_sequence()).into_bytes().into())
550            }
551            Kind::Enum(enum_descriptor) => {
552                // Use the first enum value, or 0 if no values defined
553                if let Some(first_value) = enum_descriptor.values().next() {
554                    Value::EnumNumber(first_value.number())
555                } else {
556                    Value::EnumNumber(0)
557                }
558            }
559            Kind::Message(message_descriptor) => {
560                self.generate_mock_message(&message_descriptor, depth + 1)
561            }
562        }
563    }
564
565    /// Generate a mock message with all fields populated
566    fn generate_mock_message(&mut self, descriptor: &MessageDescriptor, depth: usize) -> Value {
567        let mut message = prost_reflect::DynamicMessage::new(descriptor.clone());
568
569        if depth >= self.config.max_depth {
570            return Value::Message(message);
571        }
572
573        for field in descriptor.fields() {
574            let value = self.generate_basic_value_for_type(&field, depth);
575            message.set_field(&field, value);
576        }
577
578        Value::Message(message)
579    }
580
581    /// Generate value when depth limit is reached
582    fn generate_depth_limit_value(&self, field: &FieldDescriptor) -> Value {
583        match field.kind() {
584            Kind::String => Value::String(format!("depth_limit_reached_{}", field.name())),
585            Kind::Int32 => Value::I32(999),
586            Kind::Int64 => Value::I64(999),
587            _ => Value::String("depth_limit".to_string()),
588        }
589    }
590
591    /// Parse override value from string
592    fn parse_override_value(&self, override_value: &str, field: &FieldDescriptor) -> Value {
593        match field.kind() {
594            Kind::String => Value::String(override_value.to_string()),
595            Kind::Int32 => Value::I32(override_value.parse().unwrap_or(0)),
596            Kind::Int64 => Value::I64(override_value.parse().unwrap_or(0)),
597            Kind::Bool => Value::Bool(override_value.parse().unwrap_or(false)),
598            Kind::Double => Value::F64(override_value.parse().unwrap_or(0.0)),
599            Kind::Float => Value::F32(override_value.parse().unwrap_or(0.0)),
600            _ => Value::String(override_value.to_string()),
601        }
602    }
603
604    /// Get next sequence number
605    pub fn next_sequence(&mut self) -> u64 {
606        let current = self.sequence_counter;
607        self.sequence_counter += 1;
608        current
609    }
610
611    /// Generate a mock message for the given descriptor
612    ///
613    /// # Panics
614    /// This function will panic if `generate_mock_message` returns a non-Message Value,
615    /// which should never happen in practice as `generate_mock_message` always returns
616    /// `Value::Message`. This is defensive programming to catch any unexpected bugs.
617    pub fn generate_message(&mut self, descriptor: &MessageDescriptor) -> DynamicMessage {
618        match self.generate_mock_message(descriptor, 0) {
619            Value::Message(msg) => msg,
620            // This should never happen - generate_mock_message always returns Value::Message
621            // Using unreachable!() instead of panic!() as this is a logic error if it occurs
622            _ => unreachable!(
623                "generate_mock_message should always return a Message Value - this indicates a bug"
624            ),
625        }
626    }
627
628    /// Generate random string
629    pub fn generate_random_string(&mut self, length: usize) -> String {
630        use rand::distr::Alphanumeric;
631        use rand::{rng, Rng};
632
633        if let Some(ref mut rng) = self.rng {
634            rng.sample_iter(&Alphanumeric).take(length).map(char::from).collect()
635        } else {
636            rng().sample_iter(&Alphanumeric).take(length).map(char::from).collect()
637        }
638    }
639
640    /// Generate a UUID-like string
641    pub fn generate_uuid(&mut self) -> String {
642        format!(
643            "{:08x}-{:04x}-{:04x}-{:04x}-{:12x}",
644            self.next_random::<u32>(),
645            self.next_random::<u16>(),
646            self.next_random::<u16>(),
647            self.next_random::<u16>(),
648            self.next_random::<u64>() & 0xffffffffffff,
649        )
650    }
651
652    /// Get configuration for external inspection
653    pub fn config(&self) -> &SmartMockConfig {
654        &self.config
655    }
656
657    /// Check if faker is enabled and available
658    #[cfg(feature = "data-faker")]
659    pub fn is_faker_enabled(&self) -> bool {
660        self.config.use_faker && self.faker.is_some()
661    }
662
663    #[cfg(not(feature = "data-faker"))]
664    pub fn is_faker_enabled(&self) -> bool {
665        false
666    }
667}
668
669#[cfg(test)]
670mod tests {
671    use super::*;
672
673    #[test]
674    fn test_smart_mock_generator() {
675        let config = SmartMockConfig::default();
676        let mut generator = SmartMockGenerator::new(config);
677
678        // Test sequence generation
679        assert_eq!(generator.next_sequence(), 1);
680        assert_eq!(generator.next_sequence(), 2);
681
682        // Test UUID generation
683        let uuid = generator.generate_uuid();
684        assert!(uuid.contains('-'));
685        assert_eq!(uuid.matches('-').count(), 4);
686    }
687
688    #[test]
689    fn test_field_name_inference() {
690        let config = SmartMockConfig::default();
691        let mut generator = SmartMockGenerator::new(config);
692
693        // Test email inference - we'd need actual field descriptors for full testing
694        // This is a unit test placeholder
695        assert!(generator.generate_random_string(10).len() == 10);
696    }
697
698    #[test]
699    fn test_deterministic_seeding() {
700        // Create two generators with the same seed
701        let config1 = SmartMockConfig {
702            seed: Some(12345),
703            deterministic: true,
704            ..Default::default()
705        };
706        let config2 = SmartMockConfig {
707            seed: Some(12345),
708            deterministic: true,
709            ..Default::default()
710        };
711
712        let mut gen1 = SmartMockGenerator::new(config1);
713        let mut gen2 = SmartMockGenerator::new(config2);
714
715        // Generate same values with same seed
716        assert_eq!(gen1.generate_uuid(), gen2.generate_uuid());
717        assert_eq!(gen1.generate_random_string(10), gen2.generate_random_string(10));
718
719        // Test that different seeds produce different values
720        let config3 = SmartMockConfig {
721            seed: Some(54321),
722            deterministic: true,
723            ..Default::default()
724        };
725        let mut gen3 = SmartMockGenerator::new(config3);
726
727        // Reset first generator
728        gen1.reset();
729        gen3.reset();
730
731        // Should produce different values with different seeds
732        assert_ne!(gen1.generate_uuid(), gen3.generate_uuid());
733    }
734
735    #[test]
736    fn test_new_with_seed() {
737        let config = SmartMockConfig::default();
738        let mut gen1 = SmartMockGenerator::new_with_seed(config.clone(), 999);
739        let mut gen2 = SmartMockGenerator::new_with_seed(config, 999);
740
741        // Both should be deterministic and produce same results
742        assert!(gen1.config.deterministic);
743        assert!(gen2.config.deterministic);
744        assert_eq!(gen1.config.seed, Some(999));
745        assert_eq!(gen2.config.seed, Some(999));
746
747        let uuid1 = gen1.generate_uuid();
748        let uuid2 = gen2.generate_uuid();
749        assert_eq!(uuid1, uuid2);
750    }
751
752    #[test]
753    fn test_generator_reset() {
754        let config = SmartMockConfig {
755            seed: Some(777),
756            deterministic: true,
757            ..Default::default()
758        };
759
760        let mut generator = SmartMockGenerator::new(config);
761
762        // Generate some values
763        let uuid1 = generator.generate_uuid();
764        let seq1 = generator.next_sequence();
765        let seq2 = generator.next_sequence();
766
767        assert_eq!(seq1, 1);
768        assert_eq!(seq2, 2);
769
770        // Reset and verify we get same values again
771        generator.reset();
772        let uuid2 = generator.generate_uuid();
773        let seq3 = generator.next_sequence();
774        let seq4 = generator.next_sequence();
775
776        assert_eq!(uuid1, uuid2); // Same UUID after reset
777        assert_eq!(seq3, 1); // Sequence counter reset
778        assert_eq!(seq4, 2);
779    }
780
781    #[test]
782    fn test_deterministic_vs_non_deterministic() {
783        // Non-deterministic generator
784        let mut gen_random = SmartMockGenerator::new(SmartMockConfig::default());
785
786        // Deterministic generator
787        let mut gen_deterministic =
788            SmartMockGenerator::new_with_seed(SmartMockConfig::default(), 42);
789
790        // Generate multiple UUIDs - deterministic should be repeatable
791        let det_uuid1 = gen_deterministic.generate_uuid();
792        let det_uuid2 = gen_deterministic.generate_uuid();
793
794        gen_deterministic.reset();
795        let det_uuid1_repeat = gen_deterministic.generate_uuid();
796        let det_uuid2_repeat = gen_deterministic.generate_uuid();
797
798        // Deterministic should be the same after reset
799        assert_eq!(det_uuid1, det_uuid1_repeat);
800        assert_eq!(det_uuid2, det_uuid2_repeat);
801
802        // Just verify random generator works (can't test randomness reliably)
803        let _random_uuid = gen_random.generate_uuid();
804    }
805
806    #[cfg(feature = "data-faker")]
807    #[test]
808    fn test_faker_integration() {
809        let config = SmartMockConfig {
810            use_faker: true,
811            ..Default::default()
812        };
813        let mut generator = SmartMockGenerator::new(config);
814
815        // Test that faker is initialized
816        assert!(generator.faker.is_some());
817
818        // Test sequence generation still works
819        assert_eq!(generator.next_sequence(), 1);
820        assert_eq!(generator.next_sequence(), 2);
821    }
822}