use crate::errors::BntoError;
use crate::missing_fields::missing_fields;
use crate::pipeline::PipelineNode;
pub(super) fn check_field_values(nodes: &[PipelineNode]) -> Result<(), BntoError> {
for node in nodes {
for (name, field) in &node.fields {
field.check_current().map_err(|e| {
BntoError::InvalidInput(format!("Node '{}', field '{name}': {e}", node.id))
})?;
}
if let Some(children) = &node.children {
check_field_values(children)?;
}
}
Ok(())
}
pub(super) fn check_field_refs(nodes: &[PipelineNode]) -> Result<(), BntoError> {
let missing: Vec<String> = missing_fields(nodes)
.iter()
.map(|m| format!("Node '{}': {}", m.node_id, m.message()))
.collect();
if missing.is_empty() {
return Ok(());
}
Err(BntoError::InvalidInput(missing.join("; ")))
}
#[cfg(test)]
mod tests {
use super::*;
fn nodes(json: serde_json::Value) -> Vec<PipelineNode> {
serde_json::from_value(json).unwrap()
}
fn mode_field(default: &str) -> serde_json::Value {
serde_json::json!({
"mode": {
"type": "enum", "label": "Mode", "default": default,
"options": [{ "value": "a", "label": "A" }, { "value": "b", "label": "B" }]
}
})
}
#[test]
fn listed_values_pass() {
let ns = nodes(serde_json::json!([{ "id": "n", "type": "t", "fields": mode_field("b") }]));
assert!(check_field_values(&ns).is_ok());
}
#[test]
fn an_unlisted_value_is_refused_naming_node_and_field() {
let ns = nodes(serde_json::json!([{ "id": "n", "type": "t", "fields": mode_field("-x") }]));
let err = check_field_values(&ns).unwrap_err().to_string();
assert!(err.contains("Node 'n', field 'mode'"), "{err}");
}
#[test]
fn nested_nodes_are_checked() {
let ns = nodes(serde_json::json!([{
"id": "loop", "type": "loop",
"children": [{ "id": "inner", "type": "t", "fields": mode_field("-x") }]
}]));
assert!(check_field_values(&ns).is_err());
}
}