1use crate::consistency::ConsistencyStore;
8use crate::domains::Domain;
9use crate::faker::EnhancedFaker;
10use crate::persona::PersonaRegistry;
11use crate::persona_backstory::BackstoryGenerator;
12use crate::persona_templates::PersonaTemplateRegistry;
13use crate::schema::{FieldDefinition, SchemaDefinition};
14use crate::{Error, Result};
15use serde_json::{json, Value};
16use std::collections::HashMap;
17use std::sync::Arc;
18use tracing::{debug, info, warn};
19
20#[derive(Debug, Clone)]
22pub struct MockGeneratorConfig {
23 pub realistic_mode: bool,
25 pub default_array_size: usize,
27 pub max_array_size: usize,
29 pub include_optional_fields: bool,
31 pub field_mappings: HashMap<String, String>,
33 pub validate_generated_data: bool,
35 pub enable_backstories: bool,
37}
38
39impl Default for MockGeneratorConfig {
40 fn default() -> Self {
41 Self {
42 realistic_mode: true,
43 default_array_size: 3,
44 max_array_size: 10,
45 include_optional_fields: true,
46 field_mappings: HashMap::new(),
47 validate_generated_data: true,
48 enable_backstories: false,
49 }
50 }
51}
52
53impl MockGeneratorConfig {
54 pub fn new() -> Self {
56 Self::default()
57 }
58
59 pub fn realistic_mode(mut self, enabled: bool) -> Self {
61 self.realistic_mode = enabled;
62 self
63 }
64
65 pub fn default_array_size(mut self, size: usize) -> Self {
67 self.default_array_size = size;
68 self
69 }
70
71 pub fn max_array_size(mut self, size: usize) -> Self {
73 self.max_array_size = size;
74 self
75 }
76
77 pub fn include_optional_fields(mut self, include: bool) -> Self {
79 self.include_optional_fields = include;
80 self
81 }
82
83 pub fn field_mapping(mut self, field_name: String, faker_type: String) -> Self {
85 self.field_mappings.insert(field_name, faker_type);
86 self
87 }
88
89 pub fn validate_generated_data(mut self, validate: bool) -> Self {
91 self.validate_generated_data = validate;
92 self
93 }
94
95 pub fn enable_backstories(mut self, enable: bool) -> Self {
97 self.enable_backstories = enable;
98 self
99 }
100}
101
102#[derive(Debug)]
104pub struct MockDataGenerator {
105 config: MockGeneratorConfig,
107 faker: EnhancedFaker,
109 field_patterns: HashMap<String, String>,
111 persona_registry: Option<Arc<PersonaRegistry>>,
113 consistency_store: Option<Arc<ConsistencyStore>>,
115 active_domain: Option<Domain>,
117}
118
119impl MockDataGenerator {
120 pub fn new() -> Self {
122 Self::with_config(MockGeneratorConfig::new())
123 }
124
125 pub fn with_config(config: MockGeneratorConfig) -> Self {
127 let mut generator = Self {
128 config,
129 faker: EnhancedFaker::new(),
130 field_patterns: Self::create_field_patterns(),
131 persona_registry: None,
132 consistency_store: None,
133 active_domain: None,
134 };
135
136 generator.initialize_common_schemas();
138 generator
139 }
140
141 pub fn with_persona_support(config: MockGeneratorConfig, domain: Option<Domain>) -> Self {
143 let persona_registry = Arc::new(PersonaRegistry::new());
144 let consistency_store =
145 Arc::new(ConsistencyStore::with_registry_and_domain(persona_registry.clone(), domain));
146
147 let mut generator = Self {
148 config,
149 faker: EnhancedFaker::new(),
150 field_patterns: Self::create_field_patterns(),
151 persona_registry: Some(persona_registry),
152 consistency_store: Some(consistency_store),
153 active_domain: domain,
154 };
155
156 generator.initialize_common_schemas();
158 generator
159 }
160
161 pub fn set_active_domain(&mut self, domain: Option<Domain>) {
163 self.active_domain = domain;
164 }
167
168 pub fn persona_registry(&self) -> Option<&Arc<PersonaRegistry>> {
170 self.persona_registry.as_ref()
171 }
172
173 pub fn consistency_store(&self) -> Option<&Arc<ConsistencyStore>> {
175 self.consistency_store.as_ref()
176 }
177
178 pub fn generate_from_openapi_spec(&mut self, spec: &Value) -> Result<MockDataResult> {
180 info!("Generating mock data from OpenAPI specification");
181
182 let spec_info = self.parse_openapi_spec_info(spec)?;
184
185 let schemas = self.extract_schemas_from_spec(spec)?;
187
188 let mut generated_data = HashMap::new();
190 let mut warnings = Vec::new();
191
192 for (schema_name, schema_def) in schemas {
193 debug!("Generating data for schema: {}", schema_name);
194
195 match self.generate_schema_data(&schema_def) {
196 Ok(data) => {
197 generated_data.insert(schema_name, data);
198 }
199 Err(e) => {
200 let warning =
201 format!("Failed to generate data for schema '{}': {}", schema_name, e);
202 warn!("{}", warning);
203 warnings.push(warning);
204 }
205 }
206 }
207
208 let mut mock_responses = HashMap::new();
211 if let Some(paths) = spec.get("paths") {
212 if let Some(paths_obj) = paths.as_object() {
213 for (path, path_item) in paths_obj {
214 if let Some(path_obj) = path_item.as_object() {
215 for (method, operation) in path_obj {
216 if let Some(op_obj) = operation.as_object() {
217 let endpoint_key = format!("{} {}", method.to_uppercase(), path);
218
219 if let Some(responses) = op_obj.get("responses") {
221 if let Some(resp_obj) = responses.as_object() {
222 let mut response_schema = None;
224
225 if let Some(response) = resp_obj.get("200") {
227 response_schema = self
228 .extract_response_schema_from_json(response)
229 .ok()
230 .flatten();
231 }
232
233 if response_schema.is_none() {
235 if let Some(response) = resp_obj.get("201") {
236 response_schema = self
237 .extract_response_schema_from_json(response)
238 .ok()
239 .flatten();
240 }
241 }
242
243 if response_schema.is_none() {
245 for (status_code, response) in resp_obj {
246 if let Ok(code) = status_code.parse::<u16>() {
247 if (200..300).contains(&code) {
248 if let Some(schema) = self
249 .extract_response_schema_from_json(
250 response,
251 )
252 .ok()
253 .flatten()
254 {
255 response_schema = Some(schema);
256 break;
257 }
258 }
259 }
260 }
261 }
262
263 if let Some(schema) = response_schema {
265 let resolved_schema = if let Some(ref_path) =
267 schema.get("$ref").and_then(|r| r.as_str())
268 {
269 self.resolve_schema_ref(spec, ref_path)?
270 } else {
271 Some(schema)
272 };
273
274 if let Some(resolved) = resolved_schema {
275 if let Ok(mock_data) =
276 self.generate_from_json_schema(&resolved)
277 {
278 mock_responses.insert(
279 endpoint_key,
280 MockResponse {
281 status: 200,
282 headers: HashMap::new(),
283 body: mock_data,
284 },
285 );
286 }
287 }
288 }
289 }
290 }
291 }
292 }
293 }
294 }
295 }
296 }
297
298 Ok(MockDataResult {
299 schemas: generated_data,
300 responses: mock_responses,
301 warnings,
302 spec_info,
303 })
304 }
305
306 pub fn generate_from_json_schema(&mut self, schema: &Value) -> Result<Value> {
308 debug!("Generating mock data from JSON Schema");
309
310 let schema_def = SchemaDefinition::from_json_schema(schema)?;
312
313 self.generate_schema_data(&schema_def)
315 }
316
317 fn generate_schema_data(&mut self, schema: &SchemaDefinition) -> Result<Value> {
319 let mut object = serde_json::Map::new();
320
321 for field in &schema.fields {
322 if !field.required && !self.config.include_optional_fields {
324 continue;
325 }
326
327 let faker_type = self.determine_faker_type(field);
329
330 let value = self.generate_field_value(field, &faker_type)?;
332
333 if self.config.validate_generated_data {
335 field.validate_value(&value)?;
336 }
337
338 object.insert(field.name.clone(), value);
339 }
340
341 Ok(Value::Object(object))
342 }
343
344 fn extract_response_schema_from_json(&self, response: &Value) -> Result<Option<Value>> {
346 if let Some(content) = response.get("content") {
348 if let Some(json_content) = content.get("application/json") {
349 if let Some(schema) = json_content.get("schema") {
350 if let Some(ref_path) = schema.get("$ref").and_then(|r| r.as_str()) {
352 if let Some(schema_name) = ref_path.split('/').next_back() {
354 return Ok(Some(json!({
357 "$ref": ref_path,
358 "schema_name": schema_name
359 })));
360 }
361 }
362 return Ok(Some(schema.clone()));
363 }
364 }
365 }
366 Ok(None)
367 }
368
369 fn resolve_schema_ref(&self, spec: &Value, ref_path: &str) -> Result<Option<Value>> {
371 if ref_path.starts_with("#/components/schemas/") {
373 let schema_name = ref_path
374 .strip_prefix("#/components/schemas/")
375 .expect("already verified starts_with this prefix");
376 if let Some(components) = spec.get("components") {
377 if let Some(schemas) = components.get("schemas") {
378 if let Some(schema) = schemas.get(schema_name) {
379 return Ok(Some(schema.clone()));
380 }
381 }
382 }
383 }
384 Ok(None)
385 }
386
387 fn determine_faker_type(&self, field: &FieldDefinition) -> String {
389 let field_name = field.name.to_lowercase();
390
391 if let Some(mapped_type) = self.config.field_mappings.get(&field_name) {
393 return mapped_type.clone();
394 }
395
396 let mut best_match: Option<(&String, &String)> = None;
400 let priority_patterns = ["email", "mail"]; for (pattern, faker_type) in &self.field_patterns {
403 if field_name.contains(pattern) {
404 let is_priority = priority_patterns.contains(&pattern.as_str());
406
407 if let Some((best_pattern, _best_faker_type)) = best_match {
408 let best_is_priority = priority_patterns.contains(&best_pattern.as_str());
409
410 if is_priority && !best_is_priority {
412 best_match = Some((pattern, faker_type));
413 } else if !is_priority && best_is_priority {
414 } else if pattern.len() > best_pattern.len() {
416 best_match = Some((pattern, faker_type));
417 }
418 } else {
419 best_match = Some((pattern, faker_type));
420 }
421 }
422 }
423
424 if let Some((_, faker_type)) = best_match {
425 return faker_type.clone();
426 }
427
428 field.field_type.clone()
430 }
431
432 fn generate_field_value(&mut self, field: &FieldDefinition, faker_type: &str) -> Result<Value> {
434 if let Some(template) = &field.faker_template {
441 return Ok(self.faker.generate_by_type(template));
442 }
443
444 if field.field_type == "array" {
446 return self.generate_array_value(field);
447 }
448
449 if field.field_type == "object" && field.constraints.contains_key("properties") {
451 return self.generate_object_value(field);
452 }
453
454 let value = self.faker.generate_by_type(faker_type);
456
457 self.apply_constraints(&value, field)
459 }
460
461 fn generate_array_value(&mut self, field: &FieldDefinition) -> Result<Value> {
463 let min_items =
465 field.constraints.get("minItems").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
466 let max_items = field
467 .constraints
468 .get("maxItems")
469 .and_then(|v| v.as_u64())
470 .unwrap_or(self.config.max_array_size as u64) as usize;
471
472 let array_size = if min_items > 0 || max_items < self.config.max_array_size {
474 let size = if min_items > 0 {
476 min_items.max(self.config.default_array_size)
477 } else {
478 self.config.default_array_size
479 };
480 size.min(max_items.max(min_items))
481 } else {
482 self.config.default_array_size
483 };
484
485 let mut array = Vec::new();
487
488 if let Some(items_schema) = field.constraints.get("itemsSchema") {
490 let items_schema_def = SchemaDefinition::from_json_schema(items_schema)?;
492 for _ in 0..array_size {
493 let item = self.generate_schema_data(&items_schema_def)?;
494 array.push(item);
495 }
496 } else {
497 let items_type =
499 field.constraints.get("itemsType").and_then(|v| v.as_str()).unwrap_or("string");
500
501 for _ in 0..array_size {
502 let item = self.faker.generate_by_type(items_type);
503 array.push(item);
504 }
505 }
506
507 Ok(Value::Array(array))
508 }
509
510 fn generate_object_value(&mut self, field: &FieldDefinition) -> Result<Value> {
512 let properties = field
514 .constraints
515 .get("properties")
516 .ok_or_else(|| Error::generic("Object field missing properties constraint"))?;
517
518 let required_fields: Vec<String> = field
520 .constraints
521 .get("required")
522 .and_then(|v| v.as_array())
523 .map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect())
524 .unwrap_or_default();
525
526 let nested_schema = SchemaDefinition::from_json_schema(&json!({
528 "type": "object",
529 "properties": properties,
530 "required": required_fields
531 }))?;
532
533 self.generate_schema_data(&nested_schema)
535 }
536
537 pub fn generate_with_persona(
543 &mut self,
544 entity_id: &str,
545 domain: Domain,
546 schema: &SchemaDefinition,
547 ) -> Result<Value> {
548 let store = self.consistency_store.as_ref().ok_or_else(|| {
550 Error::generic("Persona support not enabled. Use with_persona_support() to create generator with persona support.")
551 })?;
552
553 if self.config.enable_backstories {
555 self.ensure_persona_backstory(store, entity_id, domain)?;
556 }
557
558 let mut object = serde_json::Map::new();
559
560 for field in &schema.fields {
561 if !field.required && !self.config.include_optional_fields {
563 continue;
564 }
565
566 let faker_type = self.determine_faker_type(field);
568
569 let value = match store.generate_consistent_value(entity_id, &faker_type, Some(domain))
571 {
572 Ok(v) => v,
573 Err(_) => {
574 self.faker.generate_by_type(&faker_type)
576 }
577 };
578
579 if self.config.validate_generated_data {
581 field.validate_value(&value)?;
582 }
583
584 object.insert(field.name.clone(), value);
585 }
586
587 Ok(Value::Object(object))
588 }
589
590 fn ensure_persona_backstory(
595 &self,
596 store: &ConsistencyStore,
597 entity_id: &str,
598 domain: Domain,
599 ) -> Result<()> {
600 let persona_registry = store.persona_registry();
601 let persona = store.get_entity_persona(entity_id, Some(domain));
602
603 if persona.has_backstory() {
605 return Ok(());
606 }
607
608 let mut persona_mut = persona.clone();
610 if persona_mut.traits.is_empty() {
611 let template_registry = PersonaTemplateRegistry::new();
612 template_registry.apply_template_to_persona(&mut persona_mut)?;
613 }
614
615 let backstory_generator = BackstoryGenerator::new();
617 match backstory_generator.generate_backstory(&persona_mut) {
618 Ok(backstory) => {
619 let mut traits = HashMap::new();
621 for (key, value) in &persona_mut.traits {
622 traits.insert(key.clone(), value.clone());
623 }
624
625 if !traits.is_empty() {
627 persona_registry.update_persona(entity_id, traits)?;
628 }
629
630 persona_registry.update_persona_backstory(entity_id, backstory)?;
632 }
633 Err(e) => {
634 warn!("Failed to generate backstory for persona {}: {}", entity_id, e);
635 }
636 }
637
638 Ok(())
639 }
640
641 fn apply_constraints(&mut self, value: &Value, field: &FieldDefinition) -> Result<Value> {
643 let mut constrained_value = value.clone();
644
645 if let Value::Number(num) = value {
647 let is_integer_field = field.field_type == "int" || field.field_type == "integer";
649
650 if let Some(minimum) = field.constraints.get("minimum") {
651 if let Some(min_val) = minimum.as_f64() {
652 if num.as_f64().unwrap_or(0.0) < min_val {
653 if is_integer_field {
655 constrained_value = json!(min_val as i64);
656 } else {
657 constrained_value = json!(min_val);
658 }
659 }
660 }
661 }
662
663 if let Some(maximum) = field.constraints.get("maximum") {
664 if let Some(max_val) = maximum.as_f64() {
665 if num.as_f64().unwrap_or(0.0) > max_val {
666 if is_integer_field {
668 constrained_value = json!(max_val as i64);
669 } else {
670 constrained_value = json!(max_val);
671 }
672 }
673 }
674 }
675 }
676
677 if let Value::String(s) = value {
679 let mut constrained_string = s.clone();
680
681 if let Some(min_length) = field.constraints.get("minLength") {
683 if let Some(min_len) = min_length.as_u64() {
684 if constrained_string.len() < min_len as usize {
685 let padding_needed = min_len as usize - constrained_string.len();
687 let padding = self.faker.string(padding_needed);
688 constrained_string = format!("{}{}", constrained_string, padding);
689 }
690 }
691 }
692
693 if let Some(max_length) = field.constraints.get("maxLength") {
694 if let Some(max_len) = max_length.as_u64() {
695 if constrained_string.len() > max_len as usize {
696 constrained_string.truncate(max_len as usize);
697 }
698 }
699 }
700
701 constrained_value = json!(constrained_string);
702 }
703
704 if let Some(enum_values) = field.constraints.get("enum") {
706 if let Some(enum_array) = enum_values.as_array() {
707 if !enum_array.is_empty() {
708 if let Some(random_value) = self.faker.random_element(enum_array) {
709 constrained_value = random_value.clone();
710 }
711 }
712 }
713 }
714
715 Ok(constrained_value)
716 }
717
718 fn parse_openapi_spec_info(&self, spec: &Value) -> Result<OpenApiInfo> {
720 let spec_obj = spec
721 .as_object()
722 .ok_or_else(|| Error::generic("Invalid OpenAPI specification"))?;
723
724 let info = spec_obj
725 .get("info")
726 .ok_or_else(|| Error::generic("Missing 'info' section in OpenAPI spec"))?;
727
728 let title = info.get("title").and_then(|t| t.as_str()).unwrap_or("Unknown API").to_string();
729
730 let version = info.get("version").and_then(|v| v.as_str()).unwrap_or("1.0.0").to_string();
731
732 let description = info.get("description").and_then(|d| d.as_str()).map(|s| s.to_string());
733
734 Ok(OpenApiInfo {
735 title,
736 version,
737 description,
738 })
739 }
740
741 fn extract_schemas_from_spec(
743 &mut self,
744 spec: &Value,
745 ) -> Result<HashMap<String, SchemaDefinition>> {
746 let mut schemas = HashMap::new();
747
748 if let Some(components) = spec.get("components") {
750 if let Some(schemas_section) = components.get("schemas") {
751 if let Some(schema_obj) = schemas_section.as_object() {
752 for (name, schema_def) in schema_obj {
753 let schema = SchemaDefinition::from_json_schema(schema_def)?;
754 schemas.insert(name.clone(), schema);
755 }
756 }
757 }
758 }
759
760 if let Some(paths) = spec.get("paths") {
762 if let Some(paths_obj) = paths.as_object() {
763 for (path, path_item) in paths_obj {
764 if let Some(path_obj) = path_item.as_object() {
765 for (method, operation) in path_obj {
766 if let Some(op_obj) = operation.as_object() {
767 if let Some(request_body) = op_obj.get("requestBody") {
769 if let Some(content) = request_body.get("content") {
770 if let Some(json_content) = content.get("application/json")
771 {
772 if let Some(schema) = json_content.get("schema") {
773 let schema_name = format!(
774 "{}_{}_request",
775 path.replace("/", "_").trim_start_matches("_"),
776 method
777 );
778 let schema_def =
779 SchemaDefinition::from_json_schema(schema)?;
780 schemas.insert(schema_name, schema_def);
781 }
782 }
783 }
784 }
785
786 if let Some(responses) = op_obj.get("responses") {
788 if let Some(resp_obj) = responses.as_object() {
789 for (status_code, response) in resp_obj {
790 if let Some(content) = response.get("content") {
791 if let Some(json_content) =
792 content.get("application/json")
793 {
794 if let Some(schema) = json_content.get("schema")
795 {
796 let schema_name = format!(
797 "{}_{}_response_{}",
798 path.replace("/", "_")
799 .trim_start_matches("_"),
800 method,
801 status_code
802 );
803 let schema_def =
804 SchemaDefinition::from_json_schema(
805 schema,
806 )?;
807 schemas.insert(schema_name, schema_def);
808 }
809 }
810 }
811 }
812 }
813 }
814 }
815 }
816 }
817 }
818 }
819 }
820
821 Ok(schemas)
822 }
823
824 fn create_field_patterns() -> HashMap<String, String> {
826 let mut patterns = HashMap::new();
827
828 patterns.insert("email".to_string(), "email".to_string());
830 patterns.insert("mail".to_string(), "email".to_string());
831
832 patterns.insert("name".to_string(), "name".to_string());
834 patterns.insert("firstname".to_string(), "name".to_string());
835 patterns.insert("lastname".to_string(), "name".to_string());
836 patterns.insert("username".to_string(), "name".to_string());
837
838 patterns.insert("phone".to_string(), "phone".to_string());
840 patterns.insert("mobile".to_string(), "phone".to_string());
841 patterns.insert("telephone".to_string(), "phone".to_string());
842
843 patterns.insert("address".to_string(), "address".to_string());
845 patterns.insert("street".to_string(), "address".to_string());
846 patterns.insert("city".to_string(), "string".to_string());
847 patterns.insert("state".to_string(), "string".to_string());
848 patterns.insert("zip".to_string(), "string".to_string());
849 patterns.insert("postal".to_string(), "string".to_string());
850
851 patterns.insert("company".to_string(), "company".to_string());
853 patterns.insert("organization".to_string(), "company".to_string());
854 patterns.insert("corp".to_string(), "company".to_string());
855
856 patterns.insert("url".to_string(), "url".to_string());
858 patterns.insert("website".to_string(), "url".to_string());
859 patterns.insert("link".to_string(), "url".to_string());
860
861 patterns.insert("date".to_string(), "date".to_string());
863 patterns.insert("created".to_string(), "date".to_string());
864 patterns.insert("updated".to_string(), "date".to_string());
865 patterns.insert("timestamp".to_string(), "date".to_string());
866
867 patterns.insert("id".to_string(), "uuid".to_string());
869 patterns.insert("uuid".to_string(), "uuid".to_string());
870 patterns.insert("guid".to_string(), "uuid".to_string());
871
872 patterns.insert("ip".to_string(), "ip".to_string());
874 patterns.insert("ipv4".to_string(), "ip".to_string());
875 patterns.insert("ipv6".to_string(), "ip".to_string());
876
877 patterns
878 }
879
880 fn initialize_common_schemas(&mut self) {
882 }
885}
886
887impl Default for MockDataGenerator {
888 fn default() -> Self {
889 Self::new()
890 }
891}
892
893#[derive(Debug, Clone, serde::Serialize)]
895pub struct MockDataResult {
896 pub schemas: HashMap<String, Value>,
898 pub responses: HashMap<String, MockResponse>,
900 pub warnings: Vec<String>,
902 pub spec_info: OpenApiInfo,
904}
905
906#[derive(Debug, Clone, serde::Serialize)]
908pub struct MockResponse {
909 pub status: u16,
911 pub headers: HashMap<String, String>,
913 pub body: Value,
915}
916
917#[derive(Debug, Clone, serde::Serialize)]
919pub struct OpenApiInfo {
920 pub title: String,
922 pub version: String,
924 pub description: Option<String>,
926}
927
928#[cfg(test)]
929mod tests {
930 use super::*;
931
932 #[test]
933 fn test_mock_generator_config_default() {
934 let config = MockGeneratorConfig::default();
935
936 assert!(config.realistic_mode);
937 assert_eq!(config.default_array_size, 3);
938 assert_eq!(config.max_array_size, 10);
939 assert!(config.include_optional_fields);
940 assert!(config.validate_generated_data);
941 }
942
943 #[test]
944 fn test_mock_generator_config_custom() {
945 let config = MockGeneratorConfig::new()
946 .realistic_mode(false)
947 .default_array_size(5)
948 .max_array_size(20)
949 .include_optional_fields(false)
950 .field_mapping("email".to_string(), "email".to_string())
951 .validate_generated_data(false);
952
953 assert!(!config.realistic_mode);
954 assert_eq!(config.default_array_size, 5);
955 assert_eq!(config.max_array_size, 20);
956 assert!(!config.include_optional_fields);
957 assert!(!config.validate_generated_data);
958 assert!(config.field_mappings.contains_key("email"));
959 }
960
961 #[test]
962 fn test_mock_data_generator_new() {
963 let generator = MockDataGenerator::new();
964
965 assert!(generator.config.realistic_mode);
966 assert!(!generator.field_patterns.is_empty());
967 }
968
969 #[test]
970 fn test_mock_data_generator_with_config() {
971 let config = MockGeneratorConfig::new().realistic_mode(false).default_array_size(10);
972
973 let generator = MockDataGenerator::with_config(config);
974
975 assert!(!generator.config.realistic_mode);
976 assert_eq!(generator.config.default_array_size, 10);
977 }
978
979 #[test]
980 fn test_determine_faker_type_custom_mapping() {
981 let mut config = MockGeneratorConfig::new();
982 config.field_mappings.insert("user_email".to_string(), "email".to_string());
983
984 let generator = MockDataGenerator::with_config(config);
985
986 let field = FieldDefinition::new("user_email".to_string(), "string".to_string());
987 let faker_type = generator.determine_faker_type(&field);
988
989 assert_eq!(faker_type, "email");
990 }
991
992 #[test]
993 fn test_determine_faker_type_pattern_matching() {
994 let generator = MockDataGenerator::new();
995
996 let field = FieldDefinition::new("email_address".to_string(), "string".to_string());
997 let faker_type = generator.determine_faker_type(&field);
998
999 assert_eq!(faker_type, "email");
1000 }
1001
1002 #[test]
1003 fn test_determine_faker_type_fallback() {
1004 let generator = MockDataGenerator::new();
1005
1006 let field = FieldDefinition::new("unknown_field".to_string(), "integer".to_string());
1007 let faker_type = generator.determine_faker_type(&field);
1008
1009 assert_eq!(faker_type, "integer");
1010 }
1011
1012 #[test]
1013 fn test_field_patterns_creation() {
1014 let patterns = MockDataGenerator::create_field_patterns();
1015
1016 assert!(patterns.contains_key("email"));
1017 assert!(patterns.contains_key("name"));
1018 assert!(patterns.contains_key("phone"));
1019 assert!(patterns.contains_key("address"));
1020 assert!(patterns.contains_key("company"));
1021 assert!(patterns.contains_key("url"));
1022 assert!(patterns.contains_key("date"));
1023 assert!(patterns.contains_key("id"));
1024 assert!(patterns.contains_key("ip"));
1025 }
1026
1027 #[test]
1028 fn test_generate_from_json_schema_simple() {
1029 let mut generator = MockDataGenerator::new();
1030
1031 let schema = json!({
1032 "type": "object",
1033 "properties": {
1034 "name": { "type": "string" },
1035 "age": { "type": "integer" },
1036 "email": { "type": "string" }
1037 },
1038 "required": ["name", "age"]
1039 });
1040
1041 let result = generator.generate_from_json_schema(&schema).unwrap();
1042
1043 assert!(result.is_object());
1044 let obj = result.as_object().unwrap();
1045 assert!(obj.contains_key("name"));
1046 assert!(obj.contains_key("age"));
1047 assert!(obj.contains_key("email"));
1048 }
1049
1050 #[test]
1051 fn test_generate_from_json_schema_with_constraints() {
1052 let mut generator = MockDataGenerator::new();
1053
1054 let schema = json!({
1055 "type": "object",
1056 "properties": {
1057 "age": {
1058 "type": "integer",
1059 "minimum": 18,
1060 "maximum": 65
1061 },
1062 "name": {
1063 "type": "string",
1064 "minLength": 5,
1065 "maxLength": 20
1066 }
1067 }
1068 });
1069
1070 let result = generator.generate_from_json_schema(&schema).unwrap();
1071
1072 assert!(result.is_object());
1073 let obj = result.as_object().unwrap();
1074
1075 if let Some(age) = obj.get("age") {
1076 if let Some(age_num) = age.as_i64() {
1077 assert!(age_num >= 18);
1078 assert!(age_num <= 65);
1079 }
1080 }
1081 }
1082
1083 #[test]
1084 fn test_generate_from_json_schema_with_enum() {
1085 let mut generator = MockDataGenerator::new();
1086
1087 let schema = json!({
1088 "type": "object",
1089 "properties": {
1090 "status": {
1091 "type": "string",
1092 "enum": ["active", "inactive", "pending"]
1093 }
1094 }
1095 });
1096
1097 let result = generator.generate_from_json_schema(&schema).unwrap();
1098
1099 assert!(result.is_object());
1100 let obj = result.as_object().unwrap();
1101
1102 if let Some(status) = obj.get("status") {
1103 if let Some(status_str) = status.as_str() {
1104 assert!(["active", "inactive", "pending"].contains(&status_str));
1105 }
1106 }
1107 }
1108}