use serde::Serialize;
use serde_evaluate::{
error::EvaluateError, extractor::NestedFieldExtractor, value::FieldScalarValue,
};
use std::collections::BTreeMap;
#[derive(Serialize)]
struct Level3 {
target_field: i32,
other_field: String,
}
#[derive(Serialize)]
struct Level2 {
level3: Level3,
another_val: bool,
}
#[derive(Serialize)]
struct Level1 {
level2: Level2,
id: u64,
}
#[derive(Serialize)]
struct Inner {
value: i32,
another_value: Option<String>,
nested_struct: InnerMost,
}
#[derive(Serialize)]
struct InnerMost {
deep_value: bool,
}
#[derive(Serialize)]
struct Middle {
inner: Inner,
primitive: u64,
}
#[derive(Serialize)]
struct Outer {
middle: Middle,
name: String,
}
#[derive(Serialize)]
struct MapValueStruct {
value: i32,
description: Option<String>,
}
#[derive(Serialize)]
struct MapTestData {
id: String,
data_map: BTreeMap<String, MapValueStruct>,
simple_map: BTreeMap<String, u32>,
}
#[test]
fn test_extract_deeply_nested_field() {
let data = Level1 {
id: 101,
level2: Level2 {
another_val: true,
level3: Level3 {
target_field: 999,
other_field: "hello".to_string(),
},
},
};
let path = vec!["level2", "level3", "target_field"];
let extractor = serde_evaluate::NestedFieldExtractor::new_from_path(&path)
.expect("Failed to create extractor");
let result = extractor.evaluate(&data);
assert_eq!(result, Ok(FieldScalarValue::I32(999)));
}
#[test]
fn test_extract_deeply_nested_field_comprehensive() {
let data = Outer {
middle: Middle {
inner: Inner {
value: 123,
another_value: Some("test".to_string()),
nested_struct: InnerMost { deep_value: true },
},
primitive: 999,
},
name: "outer_name".to_string(),
};
let extractor = serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&[
"middle", "inner", "value",
])
.unwrap();
let result = extractor.evaluate(&data);
assert_eq!(result.unwrap(), FieldScalarValue::I32(123));
let extractor_option = serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&[
"middle",
"inner",
"another_value",
])
.unwrap();
let result_option = extractor_option.evaluate(&data);
assert_eq!(
result_option.unwrap(),
FieldScalarValue::Option(Some(Box::new(FieldScalarValue::String("test".to_string()))))
);
let extractor_deepest = serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&[
"middle",
"inner",
"nested_struct",
"deep_value",
])
.unwrap();
let result_deepest = extractor_deepest.evaluate(&data);
assert_eq!(result_deepest.unwrap(), FieldScalarValue::Bool(true));
let extractor_bad_intermediate =
serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&[
"middle",
"non_existent",
"value",
])
.unwrap();
let result_bad_intermediate = extractor_bad_intermediate.evaluate(&data);
assert!(
matches!(result_bad_intermediate, Err(EvaluateError::NestedFieldNotFound { ref path, .. }) if path == &vec!["middle".to_string(), "non_existent".to_string(), "value".to_string()]),
"Unexpected result for bad intermediate path: {:?}",
result_bad_intermediate
);
let extractor_bad_final = serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&[
"middle",
"inner",
"non_existent",
])
.unwrap();
let result_bad_final = extractor_bad_final.evaluate(&data);
assert!(
matches!(result_bad_final, Err(EvaluateError::NestedFieldNotFound { ref path, .. }) if path == &vec!["middle".to_string(), "inner".to_string(), "non_existent".to_string()]),
"Unexpected result for bad final path: {:?}",
result_bad_final
);
let extractor_traverse_primitive =
serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&[
"middle",
"primitive",
"should_fail",
])
.unwrap();
let result_traverse_primitive = extractor_traverse_primitive.evaluate(&data);
assert!(
matches!(result_traverse_primitive, Err(EvaluateError::NestedFieldNotFound { ref path, .. }) if path == &vec!["middle".to_string(), "primitive".to_string(), "should_fail".to_string()]),
"Expected NestedFieldNotFound, got {:?}",
result_traverse_primitive
);
let extractor_non_scalar = serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&[
"middle",
"inner",
"nested_struct",
])
.unwrap();
let result_non_scalar = extractor_non_scalar.evaluate(&data);
assert!(matches!(
result_non_scalar,
Err(EvaluateError::UnsupportedType { type_name: _ })
));
assert!(
serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&Vec::<&str>::new())
.is_err()
); assert!(
serde_evaluate::extractor::NestedFieldExtractor::new_from_path(&["field1", "", "field3"])
.is_err()
); }
#[test]
fn test_extract_nested_map_field() {
let mut data_map = BTreeMap::new();
data_map.insert(
"entry1".to_string(),
MapValueStruct {
value: -10,
description: None,
},
);
data_map.insert(
"entry2".to_string(),
MapValueStruct {
value: 20,
description: Some("Second".to_string()),
},
);
let mut simple_map = BTreeMap::new();
simple_map.insert("simple1".to_string(), 100);
simple_map.insert("simple2".to_string(), 200);
let data = MapTestData {
id: "map_test_data".to_string(),
data_map,
simple_map,
};
let extractor1 = NestedFieldExtractor::new_from_path(&["data_map", "entry1", "value"]).unwrap();
let result1 = extractor1.evaluate(&data).unwrap();
assert_eq!(result1, FieldScalarValue::I32(-10));
let extractor2 =
NestedFieldExtractor::new_from_path(&["data_map", "entry2", "description"]).unwrap();
let result2 = extractor2.evaluate(&data).unwrap();
assert_eq!(
result2,
FieldScalarValue::Option(Some(Box::new(FieldScalarValue::String(
"Second".to_string()
))))
);
let extractor3 =
NestedFieldExtractor::new_from_path(&["data_map", "entry1", "description"]).unwrap();
let result3 = extractor3.evaluate(&data).unwrap();
assert_eq!(result3, FieldScalarValue::Option(None));
let extractor_simple = NestedFieldExtractor::new_from_path(&["simple_map", "simple2"]).unwrap();
let result_simple = extractor_simple.evaluate(&data).unwrap();
assert_eq!(result_simple, FieldScalarValue::U32(200));
let extractor_missing_key =
NestedFieldExtractor::new_from_path(&["data_map", "missing_key", "value"]).unwrap();
let result_missing_key = extractor_missing_key.evaluate(&data);
assert!(
matches!(result_missing_key, Err(EvaluateError::NestedFieldNotFound { ref path, .. }) if path == &vec!["data_map".to_string(), "missing_key".to_string(), "value".to_string()]),
"Unexpected result for missing key: {:?}",
result_missing_key
);
let extractor_missing_inner =
NestedFieldExtractor::new_from_path(&["data_map", "entry1", "bad_field"]).unwrap();
let result_missing_inner = extractor_missing_inner.evaluate(&data);
assert!(
matches!(result_missing_inner, Err(EvaluateError::NestedFieldNotFound { ref path, .. }) if path == &vec!["data_map".to_string(), "entry1".to_string(), "bad_field".to_string()]),
"Unexpected result for missing inner field: {:?}",
result_missing_inner
);
let extractor_map = NestedFieldExtractor::new_from_path(&["data_map"]).unwrap();
let result_map = extractor_map.evaluate(&data);
assert!(
matches!(result_map, Err(EvaluateError::UnsupportedType { .. })),
"Unexpected result for extracting map: {:?}",
result_map
);
let extractor_map_value = NestedFieldExtractor::new_from_path(&["data_map", "entry1"]).unwrap();
let result_map_value = extractor_map_value.evaluate(&data);
assert!(
matches!(result_map_value, Err(EvaluateError::UnsupportedType { .. })),
"Unexpected result for extracting map value: {:?}",
result_map_value
);
let extractor_simple_missing =
NestedFieldExtractor::new_from_path(&["simple_map", "missing"]).unwrap();
let result_simple_missing = extractor_simple_missing.evaluate(&data);
assert!(
matches!(result_simple_missing, Err(EvaluateError::NestedFieldNotFound { ref path, .. }) if path == &vec!["simple_map".to_string(), "missing".to_string()]),
"Unexpected result for missing simple key: {:?}",
result_simple_missing
);
}
#[test]
fn test_extract_nested_pure_maps() {
let mut leaf = BTreeMap::new();
leaf.insert("leaf".to_string(), 42);
let mut inner = BTreeMap::new();
inner.insert("inner".to_string(), leaf);
let mut outer: BTreeMap<String, BTreeMap<String, BTreeMap<String, i32>>> = BTreeMap::new();
outer.insert("outer".to_string(), inner);
let extractor = NestedFieldExtractor::new_from_path(&["outer", "inner", "leaf"]).unwrap();
let result = extractor.evaluate(&outer);
assert_eq!(result, Ok(FieldScalarValue::I32(42)));
let extractor_missing =
NestedFieldExtractor::new_from_path(&["outer", "inner", "missing"]).unwrap();
let result_missing = extractor_missing.evaluate(&outer);
assert!(
matches!(
result_missing,
Err(EvaluateError::NestedFieldNotFound { .. })
),
"Expected NestedFieldNotFound for missing leaf key, got {:?}",
result_missing
);
}
#[test]
fn test_extract_from_empty_map_intermediate() {
let mut data_map: BTreeMap<String, BTreeMap<String, i32>> = BTreeMap::new();
data_map.insert("empty_map".to_string(), BTreeMap::new());
let extractor = NestedFieldExtractor::new_from_path(&["empty_map", "key"]).unwrap();
let result = extractor.evaluate(&data_map);
assert!(
matches!(result, Err(EvaluateError::NestedFieldNotFound { .. })),
"Expected NestedFieldNotFound for empty map intermediate, got {:?}",
result
);
}
#[test]
fn test_extract_map_with_non_string_keys_error() {
#[derive(Serialize)]
struct Record {
int_map: BTreeMap<i32, String>,
}
let mut map = BTreeMap::new();
map.insert(42, "value".to_string());
let record = Record { int_map: map };
let extractor = NestedFieldExtractor::new_from_path(&["int_map", "42"]).unwrap();
let result = extractor.evaluate(&record);
assert!(
matches!(result, Err(EvaluateError::UnsupportedType { .. })),
"Expected UnsupportedType error for non-string map keys, got {:?}",
result
);
}