use automapper_validation::eval::{
ConditionEvaluator, ConditionResult, EvaluationContext, NoOpExternalProvider,
};
use automapper_validation::validator::validate::{AhbCodeRule, AhbFieldRule, AhbWorkflow};
use automapper_validation::{build_validated_tree, EdifactValidator, ValidationLevel};
use mig_assembly::assembler::{
AssembledGroup, AssembledGroupInstance, AssembledSegment, AssembledTree,
};
use mig_assembly::navigator::AssembledTreeNavigator;
use mig_types::segment::OwnedSegment;
use std::collections::{BTreeMap, HashMap};
struct PerInstanceTestEvaluator;
impl ConditionEvaluator for PerInstanceTestEvaluator {
fn message_type(&self) -> &str {
"TEST"
}
fn format_version(&self) -> &str {
"FV9999"
}
fn evaluate(&self, id: u32, ctx: &EvaluationContext) -> ConditionResult {
if id == 999 {
let any_match = ctx.scoped_find_segments("PIA").iter().any(|s| {
let is_z02 = s
.elements
.first()
.and_then(|e| e.first())
.is_some_and(|v| v == "Z02");
let is_target = s
.elements
.get(1)
.and_then(|e| e.first())
.is_some_and(|v| v == "1-02-0-001");
is_z02 && is_target
});
return ConditionResult::from(any_match);
}
ConditionResult::Unknown
}
fn is_external(&self, _id: u32) -> bool {
false
}
fn is_known(&self, id: u32) -> bool {
id == 999
}
}
fn assembled_pia(qual: &str, code: &str, seg_mig: &str) -> AssembledSegment {
AssembledSegment {
tag: "PIA".to_string(),
elements: vec![vec![qual.to_string()], vec![code.to_string()]],
mig_number: Some(seg_mig.to_string()),
segment_number: None,
}
}
fn flat_pia(code: &str, number: u32) -> OwnedSegment {
OwnedSegment {
id: "PIA".to_string(),
segment_number: number,
elements: vec![vec!["Z02".to_string()], vec![code.to_string()]],
}
}
fn cci_child_group() -> AssembledGroup {
AssembledGroup {
group_id: "SG10".to_string(),
repetitions: vec![AssembledGroupInstance {
segments: vec![AssembledSegment {
tag: "CCI".to_string(),
elements: vec![vec!["Z88".to_string()], vec![String::new()]],
mig_number: Some("0060".to_string()),
segment_number: None,
}],
child_groups: vec![],
entry_mig_number: Some("0060".to_string()),
variant_mig_numbers: vec!["0060".to_string()],
skipped_segments: vec![],
skipped_positions: Vec::new(),
}],
}
}
fn make_test_tree() -> AssembledTree {
AssembledTree {
segments: vec![],
groups: vec![AssembledGroup {
group_id: "SG8".to_string(),
repetitions: vec![
AssembledGroupInstance {
segments: vec![assembled_pia("Z02", "1-02-0-001", "0050")],
child_groups: vec![cci_child_group()],
entry_mig_number: Some("0050".to_string()),
variant_mig_numbers: vec!["0050".to_string(), "0060".to_string()],
skipped_segments: vec![],
skipped_positions: Vec::new(),
},
AssembledGroupInstance {
segments: vec![assembled_pia("Z02", "1-10-1", "0050")],
child_groups: vec![cci_child_group()],
entry_mig_number: Some("0050".to_string()),
variant_mig_numbers: vec!["0050".to_string(), "0060".to_string()],
skipped_segments: vec![],
skipped_positions: Vec::new(),
},
],
}],
post_group_start: 0,
inter_group_segments: BTreeMap::new(),
}
}
fn make_workflow() -> AhbWorkflow {
AhbWorkflow {
pruefidentifikator: "TEST".to_string(),
description: "Test workflow".to_string(),
communication_direction: None,
fields: vec![
AhbFieldRule {
segment_path: "SG8/SG10/CCI/C240/7037".to_string(),
name: "Merkmalcode".to_string(),
ahb_status: "Muss [999]".to_string(),
codes: vec![AhbCodeRule {
value: "Z01".to_string(),
description: "Test code".to_string(),
ahb_status: "X".to_string(),
}],
parent_group_ahb_status: Some("Muss".to_string()),
segment_ahb_status: None,
element_index: Some(1),
component_index: Some(0),
mig_number: Some("0060".to_string()),
},
],
ub_definitions: HashMap::new(),
}
}
#[test]
fn missing_field_only_errors_on_instance_where_parent_condition_fires() {
let tree = make_test_tree();
let workflow = make_workflow();
let flat_segments = vec![flat_pia("1-02-0-001", 1), flat_pia("1-10-1", 2)];
let validated_tree = build_validated_tree(&workflow, &tree);
let evaluator = PerInstanceTestEvaluator;
let validator = EdifactValidator::new(evaluator);
let external = NoOpExternalProvider;
let navigator = AssembledTreeNavigator::new(&tree);
let report = validator.validate_tree(
&validated_tree,
&flat_segments,
&external,
ValidationLevel::Full,
Some(&navigator),
);
let ahb001: Vec<_> = report
.issues
.iter()
.filter(|i| i.code == "AHB001")
.collect();
assert_eq!(
ahb001.len(),
1,
"Expected exactly 1 AHB001 (on SG8[0]); got {}:\n{}",
ahb001.len(),
ahb001
.iter()
.map(|i| format!(
" - {} (instance={:?}): {}",
i.field_path.as_deref().unwrap_or(""),
i.instance_index,
i.message,
))
.collect::<Vec<_>>()
.join("\n"),
);
assert_eq!(
ahb001[0].instance_index,
Some(0),
"The AHB001 should be tagged with instance_index=Some(0); \
SG8[0] is the instance whose PIA triggers [999]=True."
);
}