Skip to main content

jgd_rs/type_spec/
field.rs

1//! # Field Module
2//!
3//! This module defines the core `Field` enum which represents any value that can be generated
4//! in a JGD (JSON Generator Definition) schema. Fields are the building blocks of JSON data
5//! generation, supporting primitive types, complex structures, and dynamic content generation.
6//!
7//! ## Overview
8//!
9//! The `Field` enum supports all JSON value types plus specialized generator types:
10//! - **Primitive types**: strings, numbers, booleans, null
11//! - **Complex types**: arrays, entities (objects), optional values
12//! - **Dynamic types**: references to other generated values, template strings with placeholders
13//!
14//! ## Template String Processing
15//!
16//! String fields support template syntax with `${...}` placeholders for:
17//! - Fake data generation: `"${name.firstName}"`, `"${address.city}"`
18//! - Cross-references: `"${users.id}"`, `"${posts.title}"`
19//! - Function calls with arguments: `"${lorem.sentence(5)}"`
20
21use indexmap::IndexMap;
22use serde::Deserialize;
23use serde_json::Value;
24use crate::{type_spec::{ArraySpec, Entity, GeneratorConfig, JsonGenerator, NumberSpec, OptionalSpec, ReplacerCollection}, JgdGeneratorError, LocalConfig};
25
26/// A field specification that can generate any JSON value type.
27///
28/// Fields are the fundamental building blocks in JGD schemas. Each field variant
29/// corresponds to a different type of value generation strategy. The enum uses
30/// `#[serde(untagged)]` to support flexible JSON deserialization where the structure
31/// determines the variant.
32///
33/// # Variants
34///
35/// ## Complex Types
36/// - **`Array`**: Generates arrays with configurable element types and counts
37/// - **`Entity`**: Generates nested objects with multiple fields
38/// - **`Optional`**: Conditionally generates values based on probability
39///
40/// ## Dynamic Types
41/// - **`Ref`**: References values from other generated entities
42/// - **`Str`**: Template strings with placeholder substitution support
43///
44/// ## Primitive Types
45/// - **`Number`**: Generates numbers within specified ranges
46/// - **`Bool`**: Static boolean values
47/// - **`I64`**: Static 64-bit integer values
48/// - **`F64`**: Static 64-bit floating-point values
49/// - **`Null`**: JSON null values
50///
51/// # JGD Schema Examples
52///
53/// ```json
54/// {
55///   "name": "John Doe",                          // Field::Str
56///   "age": { "number": { "min": 18, "max": 65 } }, // Field::Number
57///   "active": true,                              // Field::Bool
58///   "score": 95.5,                              // Field::F64
59///   "id": 12345,                                // Field::I64
60///   "metadata": null,                           // Field::Null
61///   "email": "${internet.email}",               // Field::Str with template
62///   "user_id": { "ref": "users.id" },          // Field::Ref
63///   "tags": {                                   // Field::Array
64///     "array": {
65///       "count": 3,
66///       "of": "${lorem.word}"
67///     }
68///   },
69///   "profile": {                                // Field::Optional
70///     "optional": {
71///       "prob": 0.8,
72///       "of": { "bio": "${lorem.sentence}" }
73///     }
74///   }
75/// }
76/// ```
77///
78/// # Deserialization
79///
80/// The `#[serde(untagged)]` attribute allows automatic variant detection:
81/// - Objects with `"array"` key → `Field::Array`
82/// - Objects with `"number"` key → `Field::Number`
83/// - Objects with `"optional"` key → `Field::Optional`
84/// - Objects with `"ref"` key → `Field::Ref`
85/// - Plain strings → `Field::Str`
86/// - Plain numbers → `Field::I64` or `Field::F64`
87/// - Plain booleans → `Field::Bool`
88/// - `null` → `Field::Null`
89#[derive(Debug, Deserialize, Clone)]
90#[serde(untagged)]
91pub enum Field {
92    /// Array field that generates JSON arrays.
93    ///
94    /// Wraps an `ArraySpec` that defines the element type and count for array generation.
95    /// Arrays can contain any field type as elements and support dynamic sizing.
96    Array  {
97        array: ArraySpec
98    },
99
100    /// Entity field that generates nested JSON objects.
101    ///
102    /// Embeds a complete `Entity` specification for generating complex nested structures.
103    /// Entities can contain multiple fields and support uniqueness constraints.
104    Entity(Entity),
105
106    /// Number field that generates numeric values within ranges.
107    ///
108    /// Wraps a `NumberSpec` that defines the range and type (integer/float) for number generation.
109    /// Supports both discrete integer ranges and continuous floating-point ranges.
110    Number {
111        number: NumberSpec
112    },
113
114    /// Optional field that conditionally generates values.
115    ///
116    /// Wraps an `OptionalSpec` that defines probability-based value generation.
117    /// Can generate the specified field or null based on the configured probability.
118    Optional {
119        optional: OptionalSpec
120    },
121
122    /// Reference field that links to other generated entities.
123    ///
124    /// Contains a dot-notation path string for accessing values from previously generated
125    /// entities. Enables cross-referencing and relational data generation.
126    Ref {
127        r#ref: String
128    },
129
130    /// String field with template support.
131    ///
132    /// Can be a literal string or contain `${...}` placeholders for dynamic content generation.
133    /// Supports faker function calls and cross-references to other entities.
134    Str(String),
135
136    /// Static boolean field.
137    ///
138    /// Generates a fixed boolean value without any dynamic behavior.
139    Bool(bool),
140
141    /// Static 64-bit integer field.
142    ///
143    /// Generates a fixed integer value without any dynamic behavior.
144    I64(i64),
145
146    /// Static 64-bit floating-point field.
147    ///
148    /// Generates a fixed floating-point value without any dynamic behavior.
149    F64(f64),
150
151    /// Null field.
152    ///
153    /// Always generates a JSON null value.
154    Null,
155}
156
157impl Field {
158    /// Resolves a reference path to retrieve a value from generated entities.
159    ///
160    /// This method handles cross-reference resolution by looking up values in the
161    /// generator configuration's `gen_value` map using dot-notation paths.
162    ///
163    /// # Parameters
164    /// - `r#ref`: The dot-notation path to resolve (e.g., "users.name", "posts.0.title")
165    /// - `config`: Mutable reference to the generator configuration containing generated values
166    ///
167    /// # Returns
168    /// - `Value`: The resolved value if found, or an error message string if the path doesn't exist
169    ///
170    /// # Path Resolution
171    ///
172    /// Paths follow dot-notation syntax:
173    /// - `"entity.field"` - Access a field from a single entity
174    /// - `"entity.0.field"` - Access a field from the first item in an entity array
175    /// - `"entity.id"` - Common pattern for referencing entity IDs
176    ///
177    /// # Examples
178    ///
179    /// ```rust,ignore
180    /// // Reference a user's name from a posts entity
181    /// let user_ref = Field::Ref { r#ref: "users.name".to_string() };
182    /// let resolved_value = user_ref.generate_for_ref("users.name", &mut config);
183    ///
184    /// // Reference an ID from an entity array
185    /// let id_ref = Field::Ref { r#ref: "users.0.id".to_string() };
186    /// let user_id = id_ref.generate_for_ref("users.0.id", &mut config);
187    /// ```
188    fn generate_for_ref(&self, r#ref: &str, config: &mut GeneratorConfig, local_config: Option<&mut LocalConfig>
189        ) -> Result<Value, JgdGeneratorError> {
190        let value = config.get_value_from_path(r#ref.to_string());
191
192        if let Some(value) = value {
193            return Ok(value.clone());
194        }
195
196        let (entity_name, field_name) = if let Some(local_config) = local_config {
197            let entity_name = local_config.entity_name.clone();
198            let field_name = local_config.field_name.clone();
199            (entity_name, field_name)
200        } else {
201            (None, None)
202        };
203
204        Err(JgdGeneratorError {
205            message: format!("The path {} is not found", r#ref),
206            entity: entity_name,
207            field: field_name,
208        })
209    }
210}
211
212impl JsonGenerator for Field {
213    /// Generates a JSON value based on the field type.
214    ///
215    /// This method dispatches to the appropriate generation logic for each field variant.
216    /// It handles all supported field types and ensures proper JSON value generation
217    /// according to the JGD specification.
218    ///
219    /// # Parameters
220    /// - `config`: Mutable reference to generator configuration for accessing state and utilities
221    ///
222    /// # Returns
223    /// - `serde_json::Value`: The generated JSON value appropriate for the field type
224    ///
225    /// # Generation Behavior
226    ///
227    /// - **Array**: Delegates to `ArraySpec::generate()` for array creation
228    /// - **Entity**: Delegates to `Entity::generate()` for object creation
229    /// - **Number**: Delegates to `NumberSpec::generate()` for numeric value generation
230    /// - **Optional**: Delegates to `OptionalSpec::generate()` for probability-based generation
231    /// - **Ref**: Resolves cross-references using `generate_for_ref()`
232    /// - **Str**: Processes template strings with placeholder replacement
233    /// - **Bool/I64/F64/Null**: Direct conversion to corresponding JSON values
234    ///
235    /// # Template Processing
236    ///
237    /// String fields undergo template processing to replace `${...}` placeholders:
238    /// - Faker calls: `"${name.firstName}"` → `"John"`
239    /// - Cross-references: `"${users.id}"` → `"12345"`
240    /// - Function calls: `"${lorem.words(3)}"` → `"lorem ipsum dolor"`
241    ///
242    /// # Examples
243    ///
244    /// ```rust,ignore
245    /// let field = Field::Str("Hello ${name.firstName}!".to_string());
246    /// let result = field.generate(&mut config);
247    /// // Result: Value::String("Hello John!")
248    ///
249    /// let number_field = Field::Number {
250    ///     number: NumberSpec::new_integer(1.0, 100.0)
251    /// };
252    /// let result = number_field.generate(&mut config);
253    /// // Result: Value::Number(42)
254    /// ```
255    fn generate(&self, config: &mut super::GeneratorConfig, local_config: Option<&mut LocalConfig>
256        ) -> Result<Value, JgdGeneratorError> {
257        match self {
258            // Field::Object { object } => object.generate(config),
259            Field::Array { array } => array.generate(config, local_config),
260            Field::Entity(entity) => entity.generate(config, local_config),
261            Field::Number { number } => number.generate(config, local_config),
262            Field::Optional { optional } => optional.generate(config, local_config),
263            Field::Ref { r#ref } => self.generate_for_ref(r#ref, config, local_config),
264            Field::Str(value) => value.generate(config, local_config),
265            Field::Bool(value) => Ok(Value::Bool(*value)),
266            Field::I64(value) => Ok(Value::Number(serde_json::Number::from(*value))),
267            Field::F64(value) => Ok(Value::Number(serde_json::Number::from_f64(*value).unwrap())),
268            Field::Null => Ok(Value::Null),
269        }
270    }
271}
272
273impl JsonGenerator for IndexMap<String, Field> {
274    /// Generates a JSON object from a map of field specifications.
275    ///
276    /// This implementation allows `IndexMap<String, Field>` to be used directly as a
277    /// JSON generator, converting each field to its corresponding JSON value while
278    /// preserving key ordering.
279    ///
280    /// # Parameters
281    /// - `config`: Mutable reference to generator configuration for field generation
282    ///
283    /// # Returns
284    /// - `Value`: A JSON object containing all generated field values
285    ///
286    /// # Behavior
287    ///
288    /// - Iterates through the map in insertion order (preserved by `IndexMap`)
289    /// - Generates each field value using the field's `generate()` method
290    /// - Collects all key-value pairs into a JSON object
291    /// - Maintains field ordering as defined in the original specification
292    ///
293    /// # Examples
294    ///
295    /// ```rust,ignore
296    /// let mut fields = IndexMap::new();
297    /// fields.insert("name".to_string(), Field::Str("John".to_string()));
298    /// fields.insert("age".to_string(), Field::I64(30));
299    /// fields.insert("active".to_string(), Field::Bool(true));
300    ///
301    /// let result = fields.generate(&mut config);
302    /// // Result: {"name": "John", "age": 30, "active": true}
303    /// ```
304    ///
305    /// # Use Cases
306    ///
307    /// This implementation is primarily used by:
308    /// - Entity field generation for creating object structures
309    /// - Root-level object generation in JGD schemas
310    /// - Nested object creation within complex field hierarchies
311    fn generate(&self, config: &mut super::GeneratorConfig, local_config: Option<&mut LocalConfig>
312        ) -> Result<Value, JgdGeneratorError> {
313
314        let mut local_config = LocalConfig::from_current_with_config(None, None, local_config);
315
316        let mut map = serde_json::Map::new();
317        for (key, field) in self {
318            local_config.field_name = Some(key.clone());
319            let generated = field.generate(config, Some(&mut local_config))?;
320            map.insert(key.clone(), generated);
321        }
322
323        Ok(Value::Object(map))
324    }
325}
326
327impl JsonGenerator for String {
328    /// Generates a JSON value from a string with template processing.
329    ///
330    /// This implementation enables `String` values to be used directly in the JSON generation
331    /// pipeline with automatic template processing for placeholder substitution.
332    ///
333    /// # Parameters
334    /// - `config`: Mutable reference to generator configuration for replacement processing
335    ///
336    /// # Returns
337    /// - `Value`: A JSON string value, either the original string or with placeholders replaced
338    ///
339    /// # Template Processing
340    ///
341    /// The method uses `ReplacerCollection` to detect and process `${...}` placeholders:
342    ///
343    /// 1. **No placeholders**: Returns the string as-is
344    /// 2. **With placeholders**: Attempts replacement using available replacers
345    /// 3. **Replacement failure**: Falls back to the original string
346    ///
347    /// # Placeholder Types
348    ///
349    /// - **Faker calls**: `"${name.firstName}"` → generates fake names
350    /// - **Cross-references**: `"${users.id}"` → references other entity values
351    /// - **Function calls**: `"${lorem.sentence(5)}"` → calls faker functions with arguments
352    /// - **Mixed content**: `"User: ${name.firstName} (${internet.email})"` → multiple replacements
353    ///
354    /// # Examples
355    ///
356    /// ```rust,ignore
357    /// // Simple string without placeholders
358    /// let simple = "Hello World".to_string();
359    /// let result = simple.generate(&mut config);
360    /// // Result: Value::String("Hello World")
361    ///
362    /// // Template string with faker call
363    /// let template = "Welcome ${name.firstName}!".to_string();
364    /// let result = template.generate(&mut config);
365    /// // Result: Value::String("Welcome John!")
366    ///
367    /// // Complex template with multiple placeholders
368    /// let complex = "User ${name.firstName} lives in ${address.city}".to_string();
369    /// let result = complex.generate(&mut config);
370    /// // Result: Value::String("User John lives in New York")
371    /// ```
372    ///
373    /// # Error Handling
374    ///
375    /// If replacement fails for any reason, the method gracefully falls back to
376    /// returning the original string value, ensuring generation never fails due
377    /// to template processing errors.
378    fn generate(&self, config: &mut super::GeneratorConfig, local_config: Option<&mut LocalConfig>
379        ) -> Result<Value, JgdGeneratorError> {
380
381        let value = self.to_string();
382        let replacers = ReplacerCollection::new(value.clone());
383        if replacers.is_empty() {
384            return Ok(Value::String(value));
385        }
386
387        replacers.replace(config, local_config)
388    }
389}
390
391#[cfg(test)]
392mod tests {
393    use super::*;
394    use crate::type_spec::{Count, NumberSpec};
395    use serde_json::json;
396
397    fn create_test_config(seed: Option<u64>) -> GeneratorConfig {
398        GeneratorConfig::new("EN", seed)
399    }
400
401    #[test]
402    fn test_field_str_without_placeholders() {
403        let mut config = create_test_config(Some(42));
404        let field = Field::Str("Hello World".to_string());
405
406        let result = field.generate(&mut config, None);
407        assert!(result.is_ok());
408
409        if let Ok(result) = result {
410            assert_eq!(result, Value::String("Hello World".to_string()));
411        }
412    }
413
414    #[test]
415    fn test_field_bool_true() {
416        let mut config = create_test_config(Some(42));
417        let field = Field::Bool(true);
418
419        let result = field.generate(&mut config, None);
420        assert!(result.is_ok());
421
422        if let Ok(result) = result {
423            assert_eq!(result, Value::Bool(true));
424        }
425    }
426
427    #[test]
428    fn test_field_bool_false() {
429        let mut config = create_test_config(Some(42));
430        let field = Field::Bool(false);
431
432        let result = field.generate(&mut config, None);
433        assert!(result.is_ok());
434
435        if let Ok(result) = result {
436            assert_eq!(result, Value::Bool(false));
437        }
438    }
439
440    #[test]
441    fn test_field_i64() {
442        let mut config = create_test_config(Some(42));
443        let field = Field::I64(12345);
444
445        let result = field.generate(&mut config, None);
446        assert!(result.is_ok());
447
448        if let Ok(result) = result {
449            assert_eq!(result, Value::Number(serde_json::Number::from(12345)));
450        }
451    }
452
453    #[test]
454    fn test_field_f64() {
455        let mut config = create_test_config(Some(42));
456        let field = Field::F64(123.45);
457
458        let result = field.generate(&mut config, None);
459        assert!(result.is_ok());
460
461        if let Ok(result) = result {
462            if let Value::Number(num) = result {
463                assert_eq!(num.as_f64(), Some(123.45));
464            } else {
465                panic!("Expected number value");
466            }
467        }
468    }
469
470    #[test]
471    fn test_field_null() {
472        let mut config = create_test_config(Some(42));
473        let field = Field::Null;
474
475        let result = field.generate(&mut config, None);
476        assert!(result.is_ok());
477
478        if let Ok(result) = result {
479            assert_eq!(result, Value::Null);
480        }
481    }
482
483    #[test]
484    fn test_field_number() {
485        let mut config = create_test_config(Some(42));
486        let number_spec = NumberSpec::new_integer(1.0, 10.0);
487        let field = Field::Number { number: number_spec };
488
489        let result = field.generate(&mut config, None);
490        assert!(result.is_ok());
491
492        if let Ok(result) = result {
493            assert!(result.is_number());
494
495            if let Value::Number(num) = result {
496                let value = num.as_i64().unwrap();
497                assert!((1..=10).contains(&value));
498            }
499        }
500    }
501
502    #[test]
503    fn test_field_array() {
504        let mut config = create_test_config(Some(42));
505        let array_spec = ArraySpec {
506            count: Some(Count::Fixed(3)),
507            of: Box::new(Field::Str("test".to_string())),
508        };
509        let field = Field::Array { array: array_spec };
510
511        let result = field.generate(&mut config, None);
512        assert!(result.is_ok());
513
514        if let Ok(result) = result {
515            assert!(result.is_array());
516
517            if let Value::Array(arr) = result {
518                assert_eq!(arr.len(), 3);
519                for item in arr {
520                    assert_eq!(item, Value::String("test".to_string()));
521                }
522            }
523        }
524    }
525
526    #[test]
527    fn test_field_ref_existing_path() {
528        let mut config = create_test_config(Some(42));
529
530        // Set up a reference value in the config
531        config.gen_value.insert("users".to_string(), json!({
532            "id": 12345,
533            "name": "John Doe"
534        }));
535
536        let field = Field::Ref { r#ref: "users.name".to_string() };
537        let result = field.generate(&mut config, None);
538        assert!(result.is_ok());
539
540        if let Ok(result) = result {
541            assert_eq!(result, Value::String("John Doe".to_string()));
542        }
543    }
544
545    #[test]
546    fn test_field_ref_missing_path() {
547        let mut config = create_test_config(Some(42));
548        let field = Field::Ref { r#ref: "nonexistent.path".to_string() };
549
550        let result = field.generate(&mut config, None);
551        assert!(result.is_err());
552
553        if let Err(error) = result {
554            assert_eq!(error.message, "The path nonexistent.path is not found".to_string());
555        }
556    }
557
558    #[test]
559    fn test_field_entity() {
560        let mut config = create_test_config(Some(42));
561
562        let mut fields = IndexMap::new();
563        fields.insert("name".to_string(), Field::Str("Test User".to_string()));
564        fields.insert("age".to_string(), Field::I64(25));
565
566        let entity = Entity {
567            count: None,
568            seed: None,
569            unique_by: vec![],
570            fields,
571        };
572
573        let field = Field::Entity(entity);
574        let result = field.generate(&mut config, None);
575        assert!(result.is_ok());
576
577        if let Ok(result) = result {
578            assert!(result.is_object());
579            if let Value::Object(obj) = result {
580                assert_eq!(obj.get("name"), Some(&Value::String("Test User".to_string())));
581                assert_eq!(obj.get("age"), Some(&Value::Number(serde_json::Number::from(25))));
582            }
583        }
584    }
585
586    #[test]
587    fn test_indexmap_field_generation() {
588        let mut config = create_test_config(Some(42));
589        let mut fields = IndexMap::new();
590
591        fields.insert("string_field".to_string(), Field::Str("Hello".to_string()));
592        fields.insert("number_field".to_string(), Field::I64(42));
593        fields.insert("bool_field".to_string(), Field::Bool(true));
594        fields.insert("null_field".to_string(), Field::Null);
595
596        let result = fields.generate(&mut config, None);
597        assert!(result.is_ok());
598
599        if let Ok(result) = result {
600            assert!(result.is_object());
601            if let Value::Object(obj) = result {
602                assert_eq!(obj.get("string_field"), Some(&Value::String("Hello".to_string())));
603                assert_eq!(obj.get("number_field"), Some(&Value::Number(serde_json::Number::from(42))));
604                assert_eq!(obj.get("bool_field"), Some(&Value::Bool(true)));
605                assert_eq!(obj.get("null_field"), Some(&Value::Null));
606
607                // Verify ordering is preserved (IndexMap maintains insertion order)
608                let keys: Vec<&String> = obj.keys().collect();
609                assert_eq!(keys, vec!["string_field", "number_field", "bool_field", "null_field"]);
610            }
611        }
612    }
613
614    #[test]
615    fn test_indexmap_empty_generation() {
616        let mut config = create_test_config(Some(42));
617        let fields: IndexMap<String, Field> = IndexMap::new();
618
619        let result = fields.generate(&mut config, None);
620        assert!(result.is_ok());
621
622        if let Ok(result) = result {
623            assert!(result.is_object());
624            if let Value::Object(obj) = result {
625                assert!(obj.is_empty());
626            }
627        }
628    }
629
630    #[test]
631    fn test_string_template_processing() {
632        let mut config = create_test_config(Some(42));
633
634        let template = "Hello ${name.name}!".to_string();
635        let result = template.generate(&mut config, None);
636        assert!(result.is_ok());
637
638        if let Ok(result) = result {
639            // The result should either be the template with replacement or the original string
640            // Since we can't control the exact replacement logic in this test,
641            // we verify it's still a string
642            assert!(result.is_string());
643        }
644    }
645
646    #[test]
647    fn test_string_invalid_template_error() {
648        let mut config = create_test_config(Some(42));
649
650        let template = "Hello ${invalid.key}!".to_string();
651        let result = template.generate(&mut config, None);
652        assert!(result.is_err());
653
654        if let Err(error) = result {
655            // The result should either be the template with replacement or the original string
656            // Since we can't control the exact replacement logic in this test,
657            // we verify it's still a string
658            assert_eq!(error.message, "Error to process the pattern ${invalid.key}".to_string());
659        }
660    }
661
662    #[test]
663    fn test_string_no_placeholders() {
664        let mut config = create_test_config(Some(42));
665        let simple_string = "No placeholders here".to_string();
666
667        let result = simple_string.generate(&mut config, None);
668        assert!(result.is_ok());
669
670        if let Ok(result) = result {
671            assert_eq!(result, Value::String("No placeholders here".to_string()));
672        }
673    }
674
675    #[test]
676    fn test_field_clone() {
677        let field = Field::Str("test".to_string());
678        let cloned = field.clone();
679
680        match (field, cloned) {
681            (Field::Str(original), Field::Str(cloned_str)) => {
682                assert_eq!(original, cloned_str);
683            }
684            _ => panic!("Clone should preserve field type"),
685        }
686    }
687
688    #[test]
689    fn test_field_debug() {
690        let field = Field::Bool(true);
691        let debug_str = format!("{:?}", field);
692        assert!(debug_str.contains("Bool"));
693        assert!(debug_str.contains("true"));
694    }
695
696    #[test]
697    fn test_complex_nested_fields() {
698        let mut config = create_test_config(Some(42));
699
700        // Create a complex nested structure
701        let mut inner_fields = IndexMap::new();
702        inner_fields.insert("inner_str".to_string(), Field::Str("inner_value".to_string()));
703        inner_fields.insert("inner_num".to_string(), Field::I64(99));
704
705        let inner_entity = Entity {
706            count: None,
707            seed: None,
708            unique_by: vec![],
709            fields: inner_fields,
710        };
711
712        let mut outer_fields = IndexMap::new();
713        outer_fields.insert("nested".to_string(), Field::Entity(inner_entity));
714        outer_fields.insert("simple".to_string(), Field::Str("outer_value".to_string()));
715
716        let result = outer_fields.generate(&mut config, None);
717        assert!(result.is_ok());
718
719        if let Ok(result) = result {
720            assert!(result.is_object());
721            if let Value::Object(outer_obj) = result {
722                assert!(outer_obj.contains_key("nested"));
723                assert!(outer_obj.contains_key("simple"));
724
725                if let Some(Value::Object(inner_obj)) = outer_obj.get("nested") {
726                    assert_eq!(inner_obj.get("inner_str"), Some(&Value::String("inner_value".to_string())));
727                    assert_eq!(inner_obj.get("inner_num"), Some(&Value::Number(serde_json::Number::from(99))));
728                } else {
729                    panic!("Expected nested object");
730                }
731            }
732        }
733    }
734
735    #[test]
736    fn test_field_variants_coverage() {
737        let mut config = create_test_config(Some(42));
738
739        config.gen_value.insert("test".to_string(), json!({
740            "path": "found"
741        }));
742
743        // Test all field variants to ensure they can be created and generate values
744        let variants = vec![
745            Field::Str("test".to_string()),
746            Field::Bool(true),
747            Field::I64(42),
748            Field::F64(123.45), // Using arbitrary float to avoid clippy warnings
749            Field::Null,
750            Field::Number { number: NumberSpec::new_integer(1.0, 10.0) },
751            Field::Ref { r#ref: "test.path".to_string() },
752        ];
753
754        for field in variants {
755            let result = field.generate(&mut config, None);
756
757            assert!(result.is_ok());
758
759            if let Ok(result) = result {
760                // Each field should generate some valid JSON value
761                assert!(result.is_string() || result.is_number() || result.is_boolean() || result.is_null());
762            }
763        }
764    }
765}