use indexmap::IndexMap;
use serde::Deserialize;
use serde_json::Value;
use crate::{type_spec::{ArraySpec, Entity, GeneratorConfig, JsonGenerator, NumberSpec, OptionalSpec, ReplacerCollection}, JgdGeneratorError, LocalConfig};
#[derive(Debug, Deserialize, Clone)]
#[serde(untagged)]
pub enum Field {
Array {
array: ArraySpec
},
Entity(Entity),
Number {
number: NumberSpec
},
Optional {
optional: OptionalSpec
},
Ref {
r#ref: String
},
Str(String),
Bool(bool),
I64(i64),
F64(f64),
Null,
}
impl Field {
fn generate_for_ref(&self, r#ref: &str, config: &mut GeneratorConfig, local_config: Option<&mut LocalConfig>
) -> Result<Value, JgdGeneratorError> {
let value = config.get_value_from_path(r#ref.to_string());
if let Some(value) = value {
return Ok(value.clone());
}
let (entity_name, field_name) = if let Some(local_config) = local_config {
let entity_name = local_config.entity_name.clone();
let field_name = local_config.field_name.clone();
(entity_name, field_name)
} else {
(None, None)
};
Err(JgdGeneratorError {
message: format!("The path {} is not found", r#ref),
entity: entity_name,
field: field_name,
})
}
}
impl JsonGenerator for Field {
fn generate(&self, config: &mut super::GeneratorConfig, local_config: Option<&mut LocalConfig>
) -> Result<Value, JgdGeneratorError> {
match self {
Field::Array { array } => array.generate(config, local_config),
Field::Entity(entity) => entity.generate(config, local_config),
Field::Number { number } => number.generate(config, local_config),
Field::Optional { optional } => optional.generate(config, local_config),
Field::Ref { r#ref } => self.generate_for_ref(r#ref, config, local_config),
Field::Str(value) => value.generate(config, local_config),
Field::Bool(value) => Ok(Value::Bool(*value)),
Field::I64(value) => Ok(Value::Number(serde_json::Number::from(*value))),
Field::F64(value) => Ok(Value::Number(serde_json::Number::from_f64(*value).unwrap())),
Field::Null => Ok(Value::Null),
}
}
}
impl JsonGenerator for IndexMap<String, Field> {
fn generate(&self, config: &mut super::GeneratorConfig, local_config: Option<&mut LocalConfig>
) -> Result<Value, JgdGeneratorError> {
let mut local_config = LocalConfig::from_current_with_config(None, None, local_config);
let mut map = serde_json::Map::new();
for (key, field) in self {
local_config.field_name = Some(key.clone());
let generated = field.generate(config, Some(&mut local_config))?;
map.insert(key.clone(), generated);
}
Ok(Value::Object(map))
}
}
impl JsonGenerator for String {
fn generate(&self, config: &mut super::GeneratorConfig, local_config: Option<&mut LocalConfig>
) -> Result<Value, JgdGeneratorError> {
let value = self.to_string();
let replacers = ReplacerCollection::new(value.clone());
if replacers.is_empty() {
return Ok(Value::String(value));
}
replacers.replace(config, local_config)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::type_spec::{Count, NumberSpec};
use serde_json::json;
fn create_test_config(seed: Option<u64>) -> GeneratorConfig {
GeneratorConfig::new("EN", seed)
}
#[test]
fn test_field_str_without_placeholders() {
let mut config = create_test_config(Some(42));
let field = Field::Str("Hello World".to_string());
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert_eq!(result, Value::String("Hello World".to_string()));
}
}
#[test]
fn test_field_bool_true() {
let mut config = create_test_config(Some(42));
let field = Field::Bool(true);
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert_eq!(result, Value::Bool(true));
}
}
#[test]
fn test_field_bool_false() {
let mut config = create_test_config(Some(42));
let field = Field::Bool(false);
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert_eq!(result, Value::Bool(false));
}
}
#[test]
fn test_field_i64() {
let mut config = create_test_config(Some(42));
let field = Field::I64(12345);
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert_eq!(result, Value::Number(serde_json::Number::from(12345)));
}
}
#[test]
fn test_field_f64() {
let mut config = create_test_config(Some(42));
let field = Field::F64(123.45);
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
if let Value::Number(num) = result {
assert_eq!(num.as_f64(), Some(123.45));
} else {
panic!("Expected number value");
}
}
}
#[test]
fn test_field_null() {
let mut config = create_test_config(Some(42));
let field = Field::Null;
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert_eq!(result, Value::Null);
}
}
#[test]
fn test_field_number() {
let mut config = create_test_config(Some(42));
let number_spec = NumberSpec::new_integer(1.0, 10.0);
let field = Field::Number { number: number_spec };
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.is_number());
if let Value::Number(num) = result {
let value = num.as_i64().unwrap();
assert!((1..=10).contains(&value));
}
}
}
#[test]
fn test_field_array() {
let mut config = create_test_config(Some(42));
let array_spec = ArraySpec {
count: Some(Count::Fixed(3)),
of: Box::new(Field::Str("test".to_string())),
};
let field = Field::Array { array: array_spec };
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.is_array());
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 3);
for item in arr {
assert_eq!(item, Value::String("test".to_string()));
}
}
}
}
#[test]
fn test_field_ref_existing_path() {
let mut config = create_test_config(Some(42));
config.gen_value.insert("users".to_string(), json!({
"id": 12345,
"name": "John Doe"
}));
let field = Field::Ref { r#ref: "users.name".to_string() };
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert_eq!(result, Value::String("John Doe".to_string()));
}
}
#[test]
fn test_field_ref_missing_path() {
let mut config = create_test_config(Some(42));
let field = Field::Ref { r#ref: "nonexistent.path".to_string() };
let result = field.generate(&mut config, None);
assert!(result.is_err());
if let Err(error) = result {
assert_eq!(error.message, "The path nonexistent.path is not found".to_string());
}
}
#[test]
fn test_field_entity() {
let mut config = create_test_config(Some(42));
let mut fields = IndexMap::new();
fields.insert("name".to_string(), Field::Str("Test User".to_string()));
fields.insert("age".to_string(), Field::I64(25));
let entity = Entity {
count: None,
seed: None,
unique_by: vec![],
fields,
};
let field = Field::Entity(entity);
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.is_object());
if let Value::Object(obj) = result {
assert_eq!(obj.get("name"), Some(&Value::String("Test User".to_string())));
assert_eq!(obj.get("age"), Some(&Value::Number(serde_json::Number::from(25))));
}
}
}
#[test]
fn test_indexmap_field_generation() {
let mut config = create_test_config(Some(42));
let mut fields = IndexMap::new();
fields.insert("string_field".to_string(), Field::Str("Hello".to_string()));
fields.insert("number_field".to_string(), Field::I64(42));
fields.insert("bool_field".to_string(), Field::Bool(true));
fields.insert("null_field".to_string(), Field::Null);
let result = fields.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.is_object());
if let Value::Object(obj) = result {
assert_eq!(obj.get("string_field"), Some(&Value::String("Hello".to_string())));
assert_eq!(obj.get("number_field"), Some(&Value::Number(serde_json::Number::from(42))));
assert_eq!(obj.get("bool_field"), Some(&Value::Bool(true)));
assert_eq!(obj.get("null_field"), Some(&Value::Null));
let keys: Vec<&String> = obj.keys().collect();
assert_eq!(keys, vec!["string_field", "number_field", "bool_field", "null_field"]);
}
}
}
#[test]
fn test_indexmap_empty_generation() {
let mut config = create_test_config(Some(42));
let fields: IndexMap<String, Field> = IndexMap::new();
let result = fields.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.is_object());
if let Value::Object(obj) = result {
assert!(obj.is_empty());
}
}
}
#[test]
fn test_string_template_processing() {
let mut config = create_test_config(Some(42));
let template = "Hello ${name.name}!".to_string();
let result = template.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.is_string());
}
}
#[test]
fn test_string_invalid_template_error() {
let mut config = create_test_config(Some(42));
let template = "Hello ${invalid.key}!".to_string();
let result = template.generate(&mut config, None);
assert!(result.is_err());
if let Err(error) = result {
assert_eq!(error.message, "Error to process the pattern ${invalid.key}".to_string());
}
}
#[test]
fn test_string_no_placeholders() {
let mut config = create_test_config(Some(42));
let simple_string = "No placeholders here".to_string();
let result = simple_string.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert_eq!(result, Value::String("No placeholders here".to_string()));
}
}
#[test]
fn test_field_clone() {
let field = Field::Str("test".to_string());
let cloned = field.clone();
match (field, cloned) {
(Field::Str(original), Field::Str(cloned_str)) => {
assert_eq!(original, cloned_str);
}
_ => panic!("Clone should preserve field type"),
}
}
#[test]
fn test_field_debug() {
let field = Field::Bool(true);
let debug_str = format!("{:?}", field);
assert!(debug_str.contains("Bool"));
assert!(debug_str.contains("true"));
}
#[test]
fn test_complex_nested_fields() {
let mut config = create_test_config(Some(42));
let mut inner_fields = IndexMap::new();
inner_fields.insert("inner_str".to_string(), Field::Str("inner_value".to_string()));
inner_fields.insert("inner_num".to_string(), Field::I64(99));
let inner_entity = Entity {
count: None,
seed: None,
unique_by: vec![],
fields: inner_fields,
};
let mut outer_fields = IndexMap::new();
outer_fields.insert("nested".to_string(), Field::Entity(inner_entity));
outer_fields.insert("simple".to_string(), Field::Str("outer_value".to_string()));
let result = outer_fields.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.is_object());
if let Value::Object(outer_obj) = result {
assert!(outer_obj.contains_key("nested"));
assert!(outer_obj.contains_key("simple"));
if let Some(Value::Object(inner_obj)) = outer_obj.get("nested") {
assert_eq!(inner_obj.get("inner_str"), Some(&Value::String("inner_value".to_string())));
assert_eq!(inner_obj.get("inner_num"), Some(&Value::Number(serde_json::Number::from(99))));
} else {
panic!("Expected nested object");
}
}
}
}
#[test]
fn test_field_variants_coverage() {
let mut config = create_test_config(Some(42));
config.gen_value.insert("test".to_string(), json!({
"path": "found"
}));
let variants = vec![
Field::Str("test".to_string()),
Field::Bool(true),
Field::I64(42),
Field::F64(123.45), Field::Null,
Field::Number { number: NumberSpec::new_integer(1.0, 10.0) },
Field::Ref { r#ref: "test.path".to_string() },
];
for field in variants {
let result = field.generate(&mut config, None);
assert!(result.is_ok());
if let Ok(result) = result {
assert!(result.is_string() || result.is_number() || result.is_boolean() || result.is_null());
}
}
}
}