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