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.strip_prefix("#/components/schemas/").unwrap();
374 if let Some(components) = spec.get("components") {
375 if let Some(schemas) = components.get("schemas") {
376 if let Some(schema) = schemas.get(schema_name) {
377 return Ok(Some(schema.clone()));
378 }
379 }
380 }
381 }
382 Ok(None)
383 }
384
385 fn determine_faker_type(&self, field: &FieldDefinition) -> String {
387 let field_name = field.name.to_lowercase();
388
389 if let Some(mapped_type) = self.config.field_mappings.get(&field_name) {
391 return mapped_type.clone();
392 }
393
394 let mut best_match: Option<(&String, &String)> = None;
398 let priority_patterns = ["email", "mail"]; for (pattern, faker_type) in &self.field_patterns {
401 if field_name.contains(pattern) {
402 let is_priority = priority_patterns.contains(&pattern.as_str());
404
405 if let Some((best_pattern, _best_faker_type)) = best_match {
406 let best_is_priority = priority_patterns.contains(&best_pattern.as_str());
407
408 if is_priority && !best_is_priority {
410 best_match = Some((pattern, faker_type));
411 } else if !is_priority && best_is_priority {
412 } else if pattern.len() > best_pattern.len() {
414 best_match = Some((pattern, faker_type));
415 }
416 } else {
417 best_match = Some((pattern, faker_type));
418 }
419 }
420 }
421
422 if let Some((_, faker_type)) = best_match {
423 return faker_type.clone();
424 }
425
426 field.field_type.clone()
428 }
429
430 fn generate_field_value(&mut self, field: &FieldDefinition, faker_type: &str) -> Result<Value> {
432 if let Some(template) = &field.faker_template {
439 return Ok(self.faker.generate_by_type(template));
440 }
441
442 if field.field_type == "array" {
444 return self.generate_array_value(field);
445 }
446
447 if field.field_type == "object" && field.constraints.contains_key("properties") {
449 return self.generate_object_value(field);
450 }
451
452 let value = self.faker.generate_by_type(faker_type);
454
455 self.apply_constraints(&value, field)
457 }
458
459 fn generate_array_value(&mut self, field: &FieldDefinition) -> Result<Value> {
461 let min_items =
463 field.constraints.get("minItems").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
464 let max_items = field
465 .constraints
466 .get("maxItems")
467 .and_then(|v| v.as_u64())
468 .unwrap_or(self.config.max_array_size as u64) as usize;
469
470 let array_size = if min_items > 0 || max_items < self.config.max_array_size {
472 let size = if min_items > 0 {
474 min_items.max(self.config.default_array_size)
475 } else {
476 self.config.default_array_size
477 };
478 size.min(max_items.max(min_items))
479 } else {
480 self.config.default_array_size
481 };
482
483 let mut array = Vec::new();
485
486 if let Some(items_schema) = field.constraints.get("itemsSchema") {
488 let items_schema_def = SchemaDefinition::from_json_schema(items_schema)?;
490 for _ in 0..array_size {
491 let item = self.generate_schema_data(&items_schema_def)?;
492 array.push(item);
493 }
494 } else {
495 let items_type =
497 field.constraints.get("itemsType").and_then(|v| v.as_str()).unwrap_or("string");
498
499 for _ in 0..array_size {
500 let item = self.faker.generate_by_type(items_type);
501 array.push(item);
502 }
503 }
504
505 Ok(Value::Array(array))
506 }
507
508 fn generate_object_value(&mut self, field: &FieldDefinition) -> Result<Value> {
510 let properties = field
512 .constraints
513 .get("properties")
514 .ok_or_else(|| Error::generic("Object field missing properties constraint"))?;
515
516 let required_fields: Vec<String> = field
518 .constraints
519 .get("required")
520 .and_then(|v| v.as_array())
521 .map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect())
522 .unwrap_or_default();
523
524 let nested_schema = SchemaDefinition::from_json_schema(&json!({
526 "type": "object",
527 "properties": properties,
528 "required": required_fields
529 }))?;
530
531 self.generate_schema_data(&nested_schema)
533 }
534
535 pub fn generate_with_persona(
541 &mut self,
542 entity_id: &str,
543 domain: Domain,
544 schema: &SchemaDefinition,
545 ) -> Result<Value> {
546 let store = self.consistency_store.as_ref().ok_or_else(|| {
548 Error::generic("Persona support not enabled. Use with_persona_support() to create generator with persona support.")
549 })?;
550
551 if self.config.enable_backstories {
553 self.ensure_persona_backstory(store, entity_id, domain)?;
554 }
555
556 let mut object = serde_json::Map::new();
557
558 for field in &schema.fields {
559 if !field.required && !self.config.include_optional_fields {
561 continue;
562 }
563
564 let faker_type = self.determine_faker_type(field);
566
567 let value = match store.generate_consistent_value(entity_id, &faker_type, Some(domain))
569 {
570 Ok(v) => v,
571 Err(_) => {
572 self.faker.generate_by_type(&faker_type)
574 }
575 };
576
577 if self.config.validate_generated_data {
579 field.validate_value(&value)?;
580 }
581
582 object.insert(field.name.clone(), value);
583 }
584
585 Ok(Value::Object(object))
586 }
587
588 fn ensure_persona_backstory(
593 &self,
594 store: &ConsistencyStore,
595 entity_id: &str,
596 domain: Domain,
597 ) -> Result<()> {
598 let persona_registry = store.persona_registry();
599 let persona = store.get_entity_persona(entity_id, Some(domain));
600
601 if persona.has_backstory() {
603 return Ok(());
604 }
605
606 let mut persona_mut = persona.clone();
608 if persona_mut.traits.is_empty() {
609 let template_registry = PersonaTemplateRegistry::new();
610 template_registry.apply_template_to_persona(&mut persona_mut)?;
611 }
612
613 let backstory_generator = BackstoryGenerator::new();
615 match backstory_generator.generate_backstory(&persona_mut) {
616 Ok(backstory) => {
617 let mut traits = HashMap::new();
619 for (key, value) in &persona_mut.traits {
620 traits.insert(key.clone(), value.clone());
621 }
622
623 if !traits.is_empty() {
625 persona_registry.update_persona(entity_id, traits)?;
626 }
627
628 persona_registry.update_persona_backstory(entity_id, backstory)?;
630 }
631 Err(e) => {
632 warn!("Failed to generate backstory for persona {}: {}", entity_id, e);
633 }
634 }
635
636 Ok(())
637 }
638
639 fn apply_constraints(&mut self, value: &Value, field: &FieldDefinition) -> Result<Value> {
641 let mut constrained_value = value.clone();
642
643 if let Value::Number(num) = value {
645 let is_integer_field = field.field_type == "int" || field.field_type == "integer";
647
648 if let Some(minimum) = field.constraints.get("minimum") {
649 if let Some(min_val) = minimum.as_f64() {
650 if num.as_f64().unwrap_or(0.0) < min_val {
651 if is_integer_field {
653 constrained_value = json!(min_val as i64);
654 } else {
655 constrained_value = json!(min_val);
656 }
657 }
658 }
659 }
660
661 if let Some(maximum) = field.constraints.get("maximum") {
662 if let Some(max_val) = maximum.as_f64() {
663 if num.as_f64().unwrap_or(0.0) > max_val {
664 if is_integer_field {
666 constrained_value = json!(max_val as i64);
667 } else {
668 constrained_value = json!(max_val);
669 }
670 }
671 }
672 }
673 }
674
675 if let Value::String(s) = value {
677 let mut constrained_string = s.clone();
678
679 if let Some(min_length) = field.constraints.get("minLength") {
681 if let Some(min_len) = min_length.as_u64() {
682 if constrained_string.len() < min_len as usize {
683 let padding_needed = min_len as usize - constrained_string.len();
685 let padding = self.faker.string(padding_needed);
686 constrained_string = format!("{}{}", constrained_string, padding);
687 }
688 }
689 }
690
691 if let Some(max_length) = field.constraints.get("maxLength") {
692 if let Some(max_len) = max_length.as_u64() {
693 if constrained_string.len() > max_len as usize {
694 constrained_string.truncate(max_len as usize);
695 }
696 }
697 }
698
699 constrained_value = json!(constrained_string);
700 }
701
702 if let Some(enum_values) = field.constraints.get("enum") {
704 if let Some(enum_array) = enum_values.as_array() {
705 if !enum_array.is_empty() {
706 if let Some(random_value) = self.faker.random_element(enum_array) {
707 constrained_value = random_value.clone();
708 }
709 }
710 }
711 }
712
713 Ok(constrained_value)
714 }
715
716 fn parse_openapi_spec_info(&self, spec: &Value) -> Result<OpenApiInfo> {
718 let spec_obj = spec
719 .as_object()
720 .ok_or_else(|| Error::generic("Invalid OpenAPI specification"))?;
721
722 let info = spec_obj
723 .get("info")
724 .ok_or_else(|| Error::generic("Missing 'info' section in OpenAPI spec"))?;
725
726 let title = info.get("title").and_then(|t| t.as_str()).unwrap_or("Unknown API").to_string();
727
728 let version = info.get("version").and_then(|v| v.as_str()).unwrap_or("1.0.0").to_string();
729
730 let description = info.get("description").and_then(|d| d.as_str()).map(|s| s.to_string());
731
732 Ok(OpenApiInfo {
733 title,
734 version,
735 description,
736 })
737 }
738
739 fn extract_schemas_from_spec(
741 &mut self,
742 spec: &Value,
743 ) -> Result<HashMap<String, SchemaDefinition>> {
744 let mut schemas = HashMap::new();
745
746 if let Some(components) = spec.get("components") {
748 if let Some(schemas_section) = components.get("schemas") {
749 if let Some(schema_obj) = schemas_section.as_object() {
750 for (name, schema_def) in schema_obj {
751 let schema = SchemaDefinition::from_json_schema(schema_def)?;
752 schemas.insert(name.clone(), schema);
753 }
754 }
755 }
756 }
757
758 if let Some(paths) = spec.get("paths") {
760 if let Some(paths_obj) = paths.as_object() {
761 for (path, path_item) in paths_obj {
762 if let Some(path_obj) = path_item.as_object() {
763 for (method, operation) in path_obj {
764 if let Some(op_obj) = operation.as_object() {
765 if let Some(request_body) = op_obj.get("requestBody") {
767 if let Some(content) = request_body.get("content") {
768 if let Some(json_content) = content.get("application/json")
769 {
770 if let Some(schema) = json_content.get("schema") {
771 let schema_name = format!(
772 "{}_{}_request",
773 path.replace("/", "_").trim_start_matches("_"),
774 method
775 );
776 let schema_def =
777 SchemaDefinition::from_json_schema(schema)?;
778 schemas.insert(schema_name, schema_def);
779 }
780 }
781 }
782 }
783
784 if let Some(responses) = op_obj.get("responses") {
786 if let Some(resp_obj) = responses.as_object() {
787 for (status_code, response) in resp_obj {
788 if let Some(content) = response.get("content") {
789 if let Some(json_content) =
790 content.get("application/json")
791 {
792 if let Some(schema) = json_content.get("schema")
793 {
794 let schema_name = format!(
795 "{}_{}_response_{}",
796 path.replace("/", "_")
797 .trim_start_matches("_"),
798 method,
799 status_code
800 );
801 let schema_def =
802 SchemaDefinition::from_json_schema(
803 schema,
804 )?;
805 schemas.insert(schema_name, schema_def);
806 }
807 }
808 }
809 }
810 }
811 }
812 }
813 }
814 }
815 }
816 }
817 }
818
819 Ok(schemas)
820 }
821
822 fn create_field_patterns() -> HashMap<String, String> {
824 let mut patterns = HashMap::new();
825
826 patterns.insert("email".to_string(), "email".to_string());
828 patterns.insert("mail".to_string(), "email".to_string());
829
830 patterns.insert("name".to_string(), "name".to_string());
832 patterns.insert("firstname".to_string(), "name".to_string());
833 patterns.insert("lastname".to_string(), "name".to_string());
834 patterns.insert("username".to_string(), "name".to_string());
835
836 patterns.insert("phone".to_string(), "phone".to_string());
838 patterns.insert("mobile".to_string(), "phone".to_string());
839 patterns.insert("telephone".to_string(), "phone".to_string());
840
841 patterns.insert("address".to_string(), "address".to_string());
843 patterns.insert("street".to_string(), "address".to_string());
844 patterns.insert("city".to_string(), "string".to_string());
845 patterns.insert("state".to_string(), "string".to_string());
846 patterns.insert("zip".to_string(), "string".to_string());
847 patterns.insert("postal".to_string(), "string".to_string());
848
849 patterns.insert("company".to_string(), "company".to_string());
851 patterns.insert("organization".to_string(), "company".to_string());
852 patterns.insert("corp".to_string(), "company".to_string());
853
854 patterns.insert("url".to_string(), "url".to_string());
856 patterns.insert("website".to_string(), "url".to_string());
857 patterns.insert("link".to_string(), "url".to_string());
858
859 patterns.insert("date".to_string(), "date".to_string());
861 patterns.insert("created".to_string(), "date".to_string());
862 patterns.insert("updated".to_string(), "date".to_string());
863 patterns.insert("timestamp".to_string(), "date".to_string());
864
865 patterns.insert("id".to_string(), "uuid".to_string());
867 patterns.insert("uuid".to_string(), "uuid".to_string());
868 patterns.insert("guid".to_string(), "uuid".to_string());
869
870 patterns.insert("ip".to_string(), "ip".to_string());
872 patterns.insert("ipv4".to_string(), "ip".to_string());
873 patterns.insert("ipv6".to_string(), "ip".to_string());
874
875 patterns
876 }
877
878 fn initialize_common_schemas(&mut self) {
880 }
883}
884
885impl Default for MockDataGenerator {
886 fn default() -> Self {
887 Self::new()
888 }
889}
890
891#[derive(Debug, Clone, serde::Serialize)]
893pub struct MockDataResult {
894 pub schemas: HashMap<String, Value>,
896 pub responses: HashMap<String, MockResponse>,
898 pub warnings: Vec<String>,
900 pub spec_info: OpenApiInfo,
902}
903
904#[derive(Debug, Clone, serde::Serialize)]
906pub struct MockResponse {
907 pub status: u16,
909 pub headers: HashMap<String, String>,
911 pub body: Value,
913}
914
915#[derive(Debug, Clone, serde::Serialize)]
917pub struct OpenApiInfo {
918 pub title: String,
920 pub version: String,
922 pub description: Option<String>,
924}
925
926#[cfg(test)]
927mod tests {
928 use super::*;
929
930 #[test]
931 fn test_mock_generator_config_default() {
932 let config = MockGeneratorConfig::default();
933
934 assert!(config.realistic_mode);
935 assert_eq!(config.default_array_size, 3);
936 assert_eq!(config.max_array_size, 10);
937 assert!(config.include_optional_fields);
938 assert!(config.validate_generated_data);
939 }
940
941 #[test]
942 fn test_mock_generator_config_custom() {
943 let config = MockGeneratorConfig::new()
944 .realistic_mode(false)
945 .default_array_size(5)
946 .max_array_size(20)
947 .include_optional_fields(false)
948 .field_mapping("email".to_string(), "email".to_string())
949 .validate_generated_data(false);
950
951 assert!(!config.realistic_mode);
952 assert_eq!(config.default_array_size, 5);
953 assert_eq!(config.max_array_size, 20);
954 assert!(!config.include_optional_fields);
955 assert!(!config.validate_generated_data);
956 assert!(config.field_mappings.contains_key("email"));
957 }
958
959 #[test]
960 fn test_mock_data_generator_new() {
961 let generator = MockDataGenerator::new();
962
963 assert!(generator.config.realistic_mode);
964 assert!(!generator.field_patterns.is_empty());
965 }
966
967 #[test]
968 fn test_mock_data_generator_with_config() {
969 let config = MockGeneratorConfig::new().realistic_mode(false).default_array_size(10);
970
971 let generator = MockDataGenerator::with_config(config);
972
973 assert!(!generator.config.realistic_mode);
974 assert_eq!(generator.config.default_array_size, 10);
975 }
976
977 #[test]
978 fn test_determine_faker_type_custom_mapping() {
979 let mut config = MockGeneratorConfig::new();
980 config.field_mappings.insert("user_email".to_string(), "email".to_string());
981
982 let generator = MockDataGenerator::with_config(config);
983
984 let field = FieldDefinition::new("user_email".to_string(), "string".to_string());
985 let faker_type = generator.determine_faker_type(&field);
986
987 assert_eq!(faker_type, "email");
988 }
989
990 #[test]
991 fn test_determine_faker_type_pattern_matching() {
992 let generator = MockDataGenerator::new();
993
994 let field = FieldDefinition::new("email_address".to_string(), "string".to_string());
995 let faker_type = generator.determine_faker_type(&field);
996
997 assert_eq!(faker_type, "email");
998 }
999
1000 #[test]
1001 fn test_determine_faker_type_fallback() {
1002 let generator = MockDataGenerator::new();
1003
1004 let field = FieldDefinition::new("unknown_field".to_string(), "integer".to_string());
1005 let faker_type = generator.determine_faker_type(&field);
1006
1007 assert_eq!(faker_type, "integer");
1008 }
1009
1010 #[test]
1011 fn test_field_patterns_creation() {
1012 let patterns = MockDataGenerator::create_field_patterns();
1013
1014 assert!(patterns.contains_key("email"));
1015 assert!(patterns.contains_key("name"));
1016 assert!(patterns.contains_key("phone"));
1017 assert!(patterns.contains_key("address"));
1018 assert!(patterns.contains_key("company"));
1019 assert!(patterns.contains_key("url"));
1020 assert!(patterns.contains_key("date"));
1021 assert!(patterns.contains_key("id"));
1022 assert!(patterns.contains_key("ip"));
1023 }
1024
1025 #[test]
1026 fn test_generate_from_json_schema_simple() {
1027 let mut generator = MockDataGenerator::new();
1028
1029 let schema = json!({
1030 "type": "object",
1031 "properties": {
1032 "name": { "type": "string" },
1033 "age": { "type": "integer" },
1034 "email": { "type": "string" }
1035 },
1036 "required": ["name", "age"]
1037 });
1038
1039 let result = generator.generate_from_json_schema(&schema).unwrap();
1040
1041 assert!(result.is_object());
1042 let obj = result.as_object().unwrap();
1043 assert!(obj.contains_key("name"));
1044 assert!(obj.contains_key("age"));
1045 assert!(obj.contains_key("email"));
1046 }
1047
1048 #[test]
1049 fn test_generate_from_json_schema_with_constraints() {
1050 let mut generator = MockDataGenerator::new();
1051
1052 let schema = json!({
1053 "type": "object",
1054 "properties": {
1055 "age": {
1056 "type": "integer",
1057 "minimum": 18,
1058 "maximum": 65
1059 },
1060 "name": {
1061 "type": "string",
1062 "minLength": 5,
1063 "maxLength": 20
1064 }
1065 }
1066 });
1067
1068 let result = generator.generate_from_json_schema(&schema).unwrap();
1069
1070 assert!(result.is_object());
1071 let obj = result.as_object().unwrap();
1072
1073 if let Some(age) = obj.get("age") {
1074 if let Some(age_num) = age.as_i64() {
1075 assert!(age_num >= 18);
1076 assert!(age_num <= 65);
1077 }
1078 }
1079 }
1080
1081 #[test]
1082 fn test_generate_from_json_schema_with_enum() {
1083 let mut generator = MockDataGenerator::new();
1084
1085 let schema = json!({
1086 "type": "object",
1087 "properties": {
1088 "status": {
1089 "type": "string",
1090 "enum": ["active", "inactive", "pending"]
1091 }
1092 }
1093 });
1094
1095 let result = generator.generate_from_json_schema(&schema).unwrap();
1096
1097 assert!(result.is_object());
1098 let obj = result.as_object().unwrap();
1099
1100 if let Some(status) = obj.get("status") {
1101 if let Some(status_str) = status.as_str() {
1102 assert!(["active", "inactive", "pending"].contains(&status_str));
1103 }
1104 }
1105 }
1106}