use json_eval_rs::jsoneval::JSONEval;
use serde_json::json;
#[test]
fn test_hidden_field_filtering() {
let schema = json!({
"type": "object",
"properties": {
"visible_field": {
"type": "string",
"value": "visible"
},
"simple_hidden": {
"type": "string",
"condition": {
"hidden": true
},
"value": "hidden"
},
"parent_hidden": {
"type": "object",
"condition": {
"hidden": true
},
"properties": {
"child_hidden": {
"type": "string",
"value": "child_hidden"
}
}
},
"layout_hidden": {
"type": "object",
"$layout": {
"hideLayout": {
"all": true
}
},
"properties": {
"child_layout_hidden": {
"type": "string",
"value": "child_layout_hidden"
}
}
},
"nested_visible": {
"type": "object",
"properties": {
"child_visible": {
"type": "string",
"value": "child_visible"
}
}
}
}
});
let data = json!({
"visible_field": "user_visible",
"simple_hidden": "user_hidden", "parent_hidden": {
"child_hidden": "user_child_hidden" },
"layout_hidden": {
"child_layout_hidden": "user_child_layout_hidden" },
"nested_visible": {
"child_visible": "user_child_visible"
}
});
let schema_str = schema.to_string();
let data_str = data.to_string();
let mut eval =
JSONEval::new(&schema_str, Some("{}"), Some(&data_str)).expect("Failed to create JSONEval");
eval.evaluate(&data_str, None, None, None)
.expect("Evaluation failed");
let result_value = eval.get_schema_value(None);
assert_eq!(
result_value.pointer("/visible_field"),
Some(&json!("user_visible"))
);
assert_eq!(
result_value.pointer("/nested_visible/child_visible"),
Some(&json!("user_child_visible"))
);
assert_eq!(
result_value.pointer("/simple_hidden"),
None,
"Simple hidden field should be removed"
);
assert_eq!(
result_value.pointer("/parent_hidden/child_hidden"),
None,
"Child of hidden parent should be removed"
);
assert_eq!(
result_value.pointer("/parent_hidden"),
None,
"Hidden parent object should be removed"
);
assert_eq!(
result_value.pointer("/layout_hidden/child_layout_hidden"),
None,
"Child of layout hidden parent should be removed"
);
assert_eq!(
result_value.pointer("/layout_hidden"),
None,
"Layout hidden parent object should be removed"
);
let result_obj = eval.get_schema_value_object();
let obj_map = result_obj.as_object().unwrap();
assert!(obj_map.contains_key("visible_field"));
assert!(obj_map.contains_key("nested_visible.child_visible"));
assert!(!obj_map.contains_key("simple_hidden"));
assert!(!obj_map.contains_key("parent_hidden.child_hidden"));
assert!(!obj_map.contains_key("layout_hidden.child_layout_hidden"));
let result_arr = eval.get_schema_value_array();
let arr = result_arr.as_array().unwrap();
let paths: Vec<&str> = arr
.iter()
.map(|item| item["path"].as_str().unwrap())
.collect();
assert!(paths.contains(&"visible_field"));
assert!(paths.contains(&"nested_visible.child_visible"));
assert!(!paths.contains(&"simple_hidden"));
assert!(!paths.contains(&"parent_hidden.child_hidden"));
assert!(!paths.contains(&"layout_hidden.child_layout_hidden"));
}
#[test]
fn get_schema_value_prefers_calculation_only_for_disabled_fields() {
let schema = json!({
"type": "object",
"$layout": {
"elements": [
{ "$ref": "#/properties/editable_calculated" }
]
},
"properties": {
"disabled_calculated": {
"type": "number",
"condition": { "disabled": true },
"value": { "$evaluation": { "+": [1, 1] } }
},
"editable_calculated": {
"type": "number",
"condition": { "disabled": false },
"value": { "$evaluation": { "+": [1, 1] } }
},
"unmapped_calculated": {
"type": "number",
"condition": { "disabled": false },
"value": { "$evaluation": { "+": [1, 1] } }
}
}
});
let data = json!({
"disabled_calculated": 0,
"editable_calculated": 7,
"unmapped_calculated": 0
});
let schema_str = schema.to_string();
let data_str = data.to_string();
let mut eval = JSONEval::new(&schema_str, None, Some(&data_str)).unwrap();
eval.evaluate(&data_str, None, None, None).unwrap();
let values = eval.get_schema_value(None);
assert_eq!(
values.pointer("/disabled_calculated"),
Some(&json!(2)),
"disabled computed field must override stale caller data"
);
assert_eq!(
values.pointer("/editable_calculated"),
Some(&json!(7)),
"editable field mapped by $layout must preserve caller input over library calculation"
);
assert_eq!(
values.pointer("/unmapped_calculated"),
Some(&json!(2)),
"unmapped calculated field must override stale caller data"
);
}
#[test]
fn get_schema_value_uses_cached_layout_field_mapping() {
let mut properties = serde_json::Map::new();
let mut elements = Vec::new();
let mut data = serde_json::Map::new();
for index in 0..2_000 {
let name = format!("field_{index}");
properties.insert(
name.clone(),
json!({
"type": "number",
"value": { "$evaluation": { "+": [1, 1] } }
}),
);
data.insert(name.clone(), json!(0));
if index % 2 == 0 {
elements.push(json!({ "$ref": format!("#/properties/{name}") }));
}
}
let schema = json!({
"type": "object",
"$layout": { "elements": elements },
"properties": properties
});
let schema_str = schema.to_string();
let data_str = serde_json::Value::Object(data).to_string();
let mut eval = JSONEval::new(&schema_str, None, Some(&data_str)).unwrap();
eval.evaluate(&data_str, None, None, None).unwrap();
let values = eval.get_schema_value(None);
assert_eq!(values.pointer("/field_0"), Some(&json!(0)));
assert_eq!(values.pointer("/field_1"), Some(&json!(2)));
}
#[test]
fn test_hidden_field_validation() {
let schema = json!({
"type": "object",
"properties": {
"visible_required": {
"type": "string",
"rules": {
"required": true
}
},
"hidden_required": {
"type": "string",
"condition": {
"hidden": true
},
"rules": {
"required": true
}
},
"parent_hidden_required": {
"type": "object",
"condition": {
"hidden": true
},
"properties": {
"child_required": {
"type": "string",
"rules": {
"required": true
}
}
}
},
"layout_hidden_required": {
"type": "object",
"$layout": {
"hideLayout": {
"all": true
}
},
"properties": {
"child_layout_required": {
"type": "string",
"rules": {
"required": true
}
}
}
}
}
});
let data = json!({});
let schema_str = schema.to_string();
let data_str = data.to_string();
let mut eval =
JSONEval::new(&schema_str, Some("{}"), Some(&data_str)).expect("Failed to create JSONEval");
eval.evaluate(&data_str, None, None, None)
.expect("Evaluation failed");
let result = eval
.validate(&data_str, None, None, None, None, None)
.expect("Validation failed");
assert!(
result.errors.contains_key("visible_required"),
"Should have error for visible_required"
);
assert!(
!result.errors.contains_key("hidden_required"),
"Should NOT have error for hidden_required"
);
assert!(
!result
.errors
.contains_key("parent_hidden_required.child_required"),
"Should NOT have error for hidden parent child"
);
assert!(
!result
.errors
.contains_key("layout_hidden_required.child_layout_required"),
"Should NOT have error for hidden layout parent child"
);
}
#[test]
fn test_layout_structure_hiding() {
let schema_with_root_layout = json!({
"type": "object",
"properties": {
"section": {
"type": "object",
"condition": { "hidden": true },
"$layout": {
"elements": [
{ "$ref": "#/properties/target_field" }
]
}
},
"target_field": {
"type": "string",
"rules": { "required": true }
}
},
"$layout": {
"elements": [
{ "$ref": "#/properties/section" }
]
}
});
let data = json!({});
let schema_str = schema_with_root_layout.to_string();
let data_str = data.to_string();
let mut eval =
JSONEval::new(&schema_str, Some("{}"), Some(&data_str)).expect("Failed to create JSONEval");
let result = eval
.validate(&data_str, None, None, None, None, None)
.expect("Validation failed");
assert!(
!result.errors.contains_key("target_field"),
"Should NOT have error for target_field hidden via layout nesting"
);
}