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 #[allow(dead_code)]
111 schema_registry: HashMap<String, SchemaDefinition>,
112 field_patterns: HashMap<String, String>,
114 persona_registry: Option<Arc<PersonaRegistry>>,
116 consistency_store: Option<Arc<ConsistencyStore>>,
118 active_domain: Option<Domain>,
120}
121
122impl MockDataGenerator {
123 pub fn new() -> Self {
125 Self::with_config(MockGeneratorConfig::new())
126 }
127
128 pub fn with_config(config: MockGeneratorConfig) -> Self {
130 let mut generator = Self {
131 config,
132 faker: EnhancedFaker::new(),
133 schema_registry: HashMap::new(),
134 field_patterns: Self::create_field_patterns(),
135 persona_registry: None,
136 consistency_store: None,
137 active_domain: None,
138 };
139
140 generator.initialize_common_schemas();
142 generator
143 }
144
145 pub fn with_persona_support(config: MockGeneratorConfig, domain: Option<Domain>) -> Self {
147 let persona_registry = Arc::new(PersonaRegistry::new());
148 let consistency_store =
149 Arc::new(ConsistencyStore::with_registry_and_domain(persona_registry.clone(), domain));
150
151 let mut generator = Self {
152 config,
153 faker: EnhancedFaker::new(),
154 schema_registry: HashMap::new(),
155 field_patterns: Self::create_field_patterns(),
156 persona_registry: Some(persona_registry),
157 consistency_store: Some(consistency_store),
158 active_domain: domain,
159 };
160
161 generator.initialize_common_schemas();
163 generator
164 }
165
166 pub fn set_active_domain(&mut self, domain: Option<Domain>) {
168 self.active_domain = domain;
169 }
172
173 pub fn persona_registry(&self) -> Option<&Arc<PersonaRegistry>> {
175 self.persona_registry.as_ref()
176 }
177
178 pub fn consistency_store(&self) -> Option<&Arc<ConsistencyStore>> {
180 self.consistency_store.as_ref()
181 }
182
183 pub fn generate_from_openapi_spec(&mut self, spec: &Value) -> Result<MockDataResult> {
185 info!("Generating mock data from OpenAPI specification");
186
187 let openapi_spec = self.parse_openapi_spec(spec)?;
189
190 let schemas = self.extract_schemas_from_spec(spec)?;
192
193 let mut generated_data = HashMap::new();
195 let mut warnings = Vec::new();
196
197 for (schema_name, schema_def) in schemas {
198 debug!("Generating data for schema: {}", schema_name);
199
200 match self.generate_schema_data(&schema_def) {
201 Ok(data) => {
202 generated_data.insert(schema_name, data);
203 }
204 Err(e) => {
205 let warning =
206 format!("Failed to generate data for schema '{}': {}", schema_name, e);
207 warn!("{}", warning);
208 warnings.push(warning);
209 }
210 }
211 }
212
213 let mut mock_responses = HashMap::new();
215 for (path, path_item) in &openapi_spec.paths {
216 for (method, operation) in path_item.operations() {
217 let endpoint_key = format!("{} {}", method.to_uppercase(), path);
218
219 if let Some(response_data) = self.generate_endpoint_response(operation)? {
221 mock_responses.insert(endpoint_key, response_data);
222 }
223 }
224 }
225
226 Ok(MockDataResult {
227 schemas: generated_data,
228 responses: mock_responses,
229 warnings,
230 spec_info: openapi_spec.info,
231 })
232 }
233
234 pub fn generate_from_json_schema(&mut self, schema: &Value) -> Result<Value> {
236 debug!("Generating mock data from JSON Schema");
237
238 let schema_def = SchemaDefinition::from_json_schema(schema)?;
240
241 self.generate_schema_data(&schema_def)
243 }
244
245 fn generate_schema_data(&mut self, schema: &SchemaDefinition) -> Result<Value> {
247 let mut object = serde_json::Map::new();
248
249 for field in &schema.fields {
250 if !field.required && !self.config.include_optional_fields {
252 continue;
253 }
254
255 let faker_type = self.determine_faker_type(field);
257
258 let value = self.generate_field_value(field, &faker_type)?;
260
261 if self.config.validate_generated_data {
263 field.validate_value(&value)?;
264 }
265
266 object.insert(field.name.clone(), value);
267 }
268
269 Ok(Value::Object(object))
270 }
271
272 fn generate_endpoint_response(
274 &mut self,
275 operation: &openapiv3::Operation,
276 ) -> Result<Option<MockResponse>> {
277 let response_schema = self.find_best_response_schema(operation)?;
279
280 if let Some(schema) = response_schema {
281 let mock_data = self.generate_from_json_schema(&schema)?;
282
283 Ok(Some(MockResponse {
284 status: 200, headers: HashMap::new(),
286 body: mock_data,
287 }))
288 } else {
289 Ok(None)
290 }
291 }
292
293 fn find_best_response_schema(&self, operation: &openapiv3::Operation) -> Result<Option<Value>> {
295 let responses = &operation.responses;
296
297 if let Some(response) = responses.responses.get(&openapiv3::StatusCode::Code(200)) {
299 if let Some(schema) = self.extract_response_schema(response)? {
300 return Ok(Some(schema));
301 }
302 }
303
304 if let Some(response) = responses.responses.get(&openapiv3::StatusCode::Code(201)) {
306 if let Some(schema) = self.extract_response_schema(response)? {
307 return Ok(Some(schema));
308 }
309 }
310
311 for (code, response) in &responses.responses {
313 if let openapiv3::StatusCode::Code(status_code) = code {
314 if *status_code >= 200 && *status_code < 300 {
315 if let Some(schema) = self.extract_response_schema(response)? {
316 return Ok(Some(schema));
317 }
318 }
319 }
320 }
321
322 Ok(None)
323 }
324
325 fn extract_response_schema(
327 &self,
328 response: &openapiv3::ReferenceOr<openapiv3::Response>,
329 ) -> Result<Option<Value>> {
330 match response {
331 openapiv3::ReferenceOr::Item(response) => {
332 let content = &response.content;
333 if let Some(json_content) = content.get("application/json") {
335 if let Some(schema) = &json_content.schema {
336 return Ok(Some(serde_json::to_value(schema)?));
337 }
338 }
339
340 for (_, media_type) in content {
342 if let Some(schema) = &media_type.schema {
343 return Ok(Some(serde_json::to_value(schema)?));
344 }
345 }
346
347 Ok(None)
348 }
349 openapiv3::ReferenceOr::Reference { .. } => {
350 Ok(None)
352 }
353 }
354 }
355
356 fn determine_faker_type(&self, field: &FieldDefinition) -> String {
358 let field_name = field.name.to_lowercase();
359
360 if let Some(mapped_type) = self.config.field_mappings.get(&field_name) {
362 return mapped_type.clone();
363 }
364
365 for (pattern, faker_type) in &self.field_patterns {
367 if field_name.contains(pattern) {
368 return faker_type.clone();
369 }
370 }
371
372 field.field_type.clone()
374 }
375
376 fn generate_field_value(&mut self, field: &FieldDefinition, faker_type: &str) -> Result<Value> {
378 if let Some(template) = &field.faker_template {
385 return Ok(self.faker.generate_by_type(template));
386 }
387
388 let value = self.faker.generate_by_type(faker_type);
390
391 self.apply_constraints(&value, field)
393 }
394
395 pub fn generate_with_persona(
401 &mut self,
402 entity_id: &str,
403 domain: Domain,
404 schema: &SchemaDefinition,
405 ) -> Result<Value> {
406 let store = self.consistency_store.as_ref().ok_or_else(|| {
408 Error::generic("Persona support not enabled. Use with_persona_support() to create generator with persona support.")
409 })?;
410
411 if self.config.enable_backstories {
413 self.ensure_persona_backstory(store, entity_id, domain)?;
414 }
415
416 let mut object = serde_json::Map::new();
417
418 for field in &schema.fields {
419 if !field.required && !self.config.include_optional_fields {
421 continue;
422 }
423
424 let faker_type = self.determine_faker_type(field);
426
427 let value = match store.generate_consistent_value(entity_id, &faker_type, Some(domain))
429 {
430 Ok(v) => v,
431 Err(_) => {
432 self.faker.generate_by_type(&faker_type)
434 }
435 };
436
437 if self.config.validate_generated_data {
439 field.validate_value(&value)?;
440 }
441
442 object.insert(field.name.clone(), value);
443 }
444
445 Ok(Value::Object(object))
446 }
447
448 fn ensure_persona_backstory(
453 &self,
454 store: &ConsistencyStore,
455 entity_id: &str,
456 domain: Domain,
457 ) -> Result<()> {
458 let persona_registry = store.persona_registry();
459 let persona = store.get_entity_persona(entity_id, Some(domain));
460
461 if persona.has_backstory() {
463 return Ok(());
464 }
465
466 let mut persona_mut = persona.clone();
468 if persona_mut.traits.is_empty() {
469 let template_registry = PersonaTemplateRegistry::new();
470 template_registry.apply_template_to_persona(&mut persona_mut)?;
471 }
472
473 let backstory_generator = BackstoryGenerator::new();
475 match backstory_generator.generate_backstory(&persona_mut) {
476 Ok(backstory) => {
477 let mut traits = HashMap::new();
479 for (key, value) in &persona_mut.traits {
480 traits.insert(key.clone(), value.clone());
481 }
482
483 if !traits.is_empty() {
485 persona_registry.update_persona(entity_id, traits)?;
486 }
487
488 persona_registry.update_persona_backstory(entity_id, backstory)?;
490 }
491 Err(e) => {
492 warn!("Failed to generate backstory for persona {}: {}", entity_id, e);
493 }
494 }
495
496 Ok(())
497 }
498
499 fn apply_constraints(&mut self, value: &Value, field: &FieldDefinition) -> Result<Value> {
501 let mut constrained_value = value.clone();
502
503 if let Value::Number(num) = value {
505 if let Some(minimum) = field.constraints.get("minimum") {
506 if let Some(min_val) = minimum.as_f64() {
507 if num.as_f64().unwrap_or(0.0) < min_val {
508 constrained_value = json!(min_val);
509 }
510 }
511 }
512
513 if let Some(maximum) = field.constraints.get("maximum") {
514 if let Some(max_val) = maximum.as_f64() {
515 if num.as_f64().unwrap_or(0.0) > max_val {
516 constrained_value = json!(max_val);
517 }
518 }
519 }
520 }
521
522 if let Value::String(s) = value {
524 let mut constrained_string = s.clone();
525
526 if let Some(min_length) = field.constraints.get("minLength") {
528 if let Some(min_len) = min_length.as_u64() {
529 if constrained_string.len() < min_len as usize {
530 let padding_needed = min_len as usize - constrained_string.len();
532 let padding = self.faker.string(padding_needed);
533 constrained_string = format!("{}{}", constrained_string, padding);
534 }
535 }
536 }
537
538 if let Some(max_length) = field.constraints.get("maxLength") {
539 if let Some(max_len) = max_length.as_u64() {
540 if constrained_string.len() > max_len as usize {
541 constrained_string.truncate(max_len as usize);
542 }
543 }
544 }
545
546 constrained_value = json!(constrained_string);
547 }
548
549 if let Some(enum_values) = field.constraints.get("enum") {
551 if let Some(enum_array) = enum_values.as_array() {
552 if !enum_array.is_empty() {
553 if let Some(random_value) = self.faker.random_element(enum_array) {
554 constrained_value = random_value.clone();
555 }
556 }
557 }
558 }
559
560 Ok(constrained_value)
561 }
562
563 fn parse_openapi_spec(&self, spec: &Value) -> Result<OpenApiSpec> {
565 let spec_obj = spec
568 .as_object()
569 .ok_or_else(|| Error::generic("Invalid OpenAPI specification"))?;
570
571 let info = spec_obj
572 .get("info")
573 .ok_or_else(|| Error::generic("Missing 'info' section in OpenAPI spec"))?;
574
575 let title = info.get("title").and_then(|t| t.as_str()).unwrap_or("Unknown API").to_string();
576
577 let version = info.get("version").and_then(|v| v.as_str()).unwrap_or("1.0.0").to_string();
578
579 let description = info.get("description").and_then(|d| d.as_str()).map(|s| s.to_string());
580
581 Ok(OpenApiSpec {
582 info: OpenApiInfo {
583 title,
584 version,
585 description,
586 },
587 paths: HashMap::new(), })
589 }
590
591 fn extract_schemas_from_spec(
593 &mut self,
594 spec: &Value,
595 ) -> Result<HashMap<String, SchemaDefinition>> {
596 let mut schemas = HashMap::new();
597
598 if let Some(components) = spec.get("components") {
600 if let Some(schemas_section) = components.get("schemas") {
601 if let Some(schema_obj) = schemas_section.as_object() {
602 for (name, schema_def) in schema_obj {
603 let schema = SchemaDefinition::from_json_schema(schema_def)?;
604 schemas.insert(name.clone(), schema);
605 }
606 }
607 }
608 }
609
610 if let Some(paths) = spec.get("paths") {
612 if let Some(paths_obj) = paths.as_object() {
613 for (path, path_item) in paths_obj {
614 if let Some(path_obj) = path_item.as_object() {
615 for (method, operation) in path_obj {
616 if let Some(op_obj) = operation.as_object() {
617 if let Some(request_body) = op_obj.get("requestBody") {
619 if let Some(content) = request_body.get("content") {
620 if let Some(json_content) = content.get("application/json")
621 {
622 if let Some(schema) = json_content.get("schema") {
623 let schema_name = format!(
624 "{}_{}_request",
625 path.replace("/", "_").trim_start_matches("_"),
626 method
627 );
628 let schema_def =
629 SchemaDefinition::from_json_schema(schema)?;
630 schemas.insert(schema_name, schema_def);
631 }
632 }
633 }
634 }
635
636 if let Some(responses) = op_obj.get("responses") {
638 if let Some(resp_obj) = responses.as_object() {
639 for (status_code, response) in resp_obj {
640 if let Some(content) = response.get("content") {
641 if let Some(json_content) =
642 content.get("application/json")
643 {
644 if let Some(schema) = json_content.get("schema")
645 {
646 let schema_name = format!(
647 "{}_{}_response_{}",
648 path.replace("/", "_")
649 .trim_start_matches("_"),
650 method,
651 status_code
652 );
653 let schema_def =
654 SchemaDefinition::from_json_schema(
655 schema,
656 )?;
657 schemas.insert(schema_name, schema_def);
658 }
659 }
660 }
661 }
662 }
663 }
664 }
665 }
666 }
667 }
668 }
669 }
670
671 Ok(schemas)
672 }
673
674 fn create_field_patterns() -> HashMap<String, String> {
676 let mut patterns = HashMap::new();
677
678 patterns.insert("email".to_string(), "email".to_string());
680 patterns.insert("mail".to_string(), "email".to_string());
681
682 patterns.insert("name".to_string(), "name".to_string());
684 patterns.insert("firstname".to_string(), "name".to_string());
685 patterns.insert("lastname".to_string(), "name".to_string());
686 patterns.insert("username".to_string(), "name".to_string());
687
688 patterns.insert("phone".to_string(), "phone".to_string());
690 patterns.insert("mobile".to_string(), "phone".to_string());
691 patterns.insert("telephone".to_string(), "phone".to_string());
692
693 patterns.insert("address".to_string(), "address".to_string());
695 patterns.insert("street".to_string(), "address".to_string());
696 patterns.insert("city".to_string(), "string".to_string());
697 patterns.insert("state".to_string(), "string".to_string());
698 patterns.insert("zip".to_string(), "string".to_string());
699 patterns.insert("postal".to_string(), "string".to_string());
700
701 patterns.insert("company".to_string(), "company".to_string());
703 patterns.insert("organization".to_string(), "company".to_string());
704 patterns.insert("corp".to_string(), "company".to_string());
705
706 patterns.insert("url".to_string(), "url".to_string());
708 patterns.insert("website".to_string(), "url".to_string());
709 patterns.insert("link".to_string(), "url".to_string());
710
711 patterns.insert("date".to_string(), "date".to_string());
713 patterns.insert("created".to_string(), "date".to_string());
714 patterns.insert("updated".to_string(), "date".to_string());
715 patterns.insert("timestamp".to_string(), "date".to_string());
716
717 patterns.insert("id".to_string(), "uuid".to_string());
719 patterns.insert("uuid".to_string(), "uuid".to_string());
720 patterns.insert("guid".to_string(), "uuid".to_string());
721
722 patterns.insert("ip".to_string(), "ip".to_string());
724 patterns.insert("ipv4".to_string(), "ip".to_string());
725 patterns.insert("ipv6".to_string(), "ip".to_string());
726
727 patterns
728 }
729
730 fn initialize_common_schemas(&mut self) {
732 }
735}
736
737impl Default for MockDataGenerator {
738 fn default() -> Self {
739 Self::new()
740 }
741}
742
743#[derive(Debug, Clone, serde::Serialize)]
745pub struct MockDataResult {
746 pub schemas: HashMap<String, Value>,
748 pub responses: HashMap<String, MockResponse>,
750 pub warnings: Vec<String>,
752 pub spec_info: OpenApiInfo,
754}
755
756#[derive(Debug, Clone, serde::Serialize)]
758pub struct MockResponse {
759 pub status: u16,
761 pub headers: HashMap<String, String>,
763 pub body: Value,
765}
766
767#[derive(Debug, Clone, serde::Serialize)]
769pub struct OpenApiInfo {
770 pub title: String,
772 pub version: String,
774 pub description: Option<String>,
776}
777
778#[derive(Debug)]
780struct OpenApiSpec {
781 info: OpenApiInfo,
782 paths: HashMap<String, PathItem>,
783}
784
785#[derive(Debug)]
787struct PathItem {
788 operations: HashMap<String, openapiv3::Operation>,
789}
790
791impl PathItem {
792 fn operations(&self) -> &HashMap<String, openapiv3::Operation> {
793 &self.operations
794 }
795}
796
797#[cfg(test)]
798mod tests {
799 use super::*;
800
801 #[test]
802 fn test_mock_generator_config_default() {
803 let config = MockGeneratorConfig::default();
804
805 assert!(config.realistic_mode);
806 assert_eq!(config.default_array_size, 3);
807 assert_eq!(config.max_array_size, 10);
808 assert!(config.include_optional_fields);
809 assert!(config.validate_generated_data);
810 }
811
812 #[test]
813 fn test_mock_generator_config_custom() {
814 let config = MockGeneratorConfig::new()
815 .realistic_mode(false)
816 .default_array_size(5)
817 .max_array_size(20)
818 .include_optional_fields(false)
819 .field_mapping("email".to_string(), "email".to_string())
820 .validate_generated_data(false);
821
822 assert!(!config.realistic_mode);
823 assert_eq!(config.default_array_size, 5);
824 assert_eq!(config.max_array_size, 20);
825 assert!(!config.include_optional_fields);
826 assert!(!config.validate_generated_data);
827 assert!(config.field_mappings.contains_key("email"));
828 }
829
830 #[test]
831 fn test_mock_data_generator_new() {
832 let generator = MockDataGenerator::new();
833
834 assert!(generator.config.realistic_mode);
835 assert!(!generator.field_patterns.is_empty());
836 }
837
838 #[test]
839 fn test_mock_data_generator_with_config() {
840 let config = MockGeneratorConfig::new().realistic_mode(false).default_array_size(10);
841
842 let generator = MockDataGenerator::with_config(config);
843
844 assert!(!generator.config.realistic_mode);
845 assert_eq!(generator.config.default_array_size, 10);
846 }
847
848 #[test]
849 fn test_determine_faker_type_custom_mapping() {
850 let mut config = MockGeneratorConfig::new();
851 config.field_mappings.insert("user_email".to_string(), "email".to_string());
852
853 let generator = MockDataGenerator::with_config(config);
854
855 let field = FieldDefinition::new("user_email".to_string(), "string".to_string());
856 let faker_type = generator.determine_faker_type(&field);
857
858 assert_eq!(faker_type, "email");
859 }
860
861 #[test]
862 fn test_determine_faker_type_pattern_matching() {
863 let generator = MockDataGenerator::new();
864
865 let field = FieldDefinition::new("email_address".to_string(), "string".to_string());
866 let faker_type = generator.determine_faker_type(&field);
867
868 assert_eq!(faker_type, "email");
869 }
870
871 #[test]
872 fn test_determine_faker_type_fallback() {
873 let generator = MockDataGenerator::new();
874
875 let field = FieldDefinition::new("unknown_field".to_string(), "integer".to_string());
876 let faker_type = generator.determine_faker_type(&field);
877
878 assert_eq!(faker_type, "integer");
879 }
880
881 #[test]
882 fn test_field_patterns_creation() {
883 let patterns = MockDataGenerator::create_field_patterns();
884
885 assert!(patterns.contains_key("email"));
886 assert!(patterns.contains_key("name"));
887 assert!(patterns.contains_key("phone"));
888 assert!(patterns.contains_key("address"));
889 assert!(patterns.contains_key("company"));
890 assert!(patterns.contains_key("url"));
891 assert!(patterns.contains_key("date"));
892 assert!(patterns.contains_key("id"));
893 assert!(patterns.contains_key("ip"));
894 }
895
896 #[test]
897 fn test_generate_from_json_schema_simple() {
898 let mut generator = MockDataGenerator::new();
899
900 let schema = json!({
901 "type": "object",
902 "properties": {
903 "name": { "type": "string" },
904 "age": { "type": "integer" },
905 "email": { "type": "string" }
906 },
907 "required": ["name", "age"]
908 });
909
910 let result = generator.generate_from_json_schema(&schema).unwrap();
911
912 assert!(result.is_object());
913 let obj = result.as_object().unwrap();
914 assert!(obj.contains_key("name"));
915 assert!(obj.contains_key("age"));
916 assert!(obj.contains_key("email"));
917 }
918
919 #[test]
920 fn test_generate_from_json_schema_with_constraints() {
921 let mut generator = MockDataGenerator::new();
922
923 let schema = json!({
924 "type": "object",
925 "properties": {
926 "age": {
927 "type": "integer",
928 "minimum": 18,
929 "maximum": 65
930 },
931 "name": {
932 "type": "string",
933 "minLength": 5,
934 "maxLength": 20
935 }
936 }
937 });
938
939 let result = generator.generate_from_json_schema(&schema).unwrap();
940
941 assert!(result.is_object());
942 let obj = result.as_object().unwrap();
943
944 if let Some(age) = obj.get("age") {
945 if let Some(age_num) = age.as_i64() {
946 assert!(age_num >= 18);
947 assert!(age_num <= 65);
948 }
949 }
950 }
951
952 #[test]
953 fn test_generate_from_json_schema_with_enum() {
954 let mut generator = MockDataGenerator::new();
955
956 let schema = json!({
957 "type": "object",
958 "properties": {
959 "status": {
960 "type": "string",
961 "enum": ["active", "inactive", "pending"]
962 }
963 }
964 });
965
966 let result = generator.generate_from_json_schema(&schema).unwrap();
967
968 assert!(result.is_object());
969 let obj = result.as_object().unwrap();
970
971 if let Some(status) = obj.get("status") {
972 if let Some(status_str) = status.as_str() {
973 assert!(["active", "inactive", "pending"].contains(&status_str));
974 }
975 }
976 }
977}