use std::collections::BTreeMap;
use automapper_validation::eval::{
ConditionResult, EvaluationContext, GroupScope, MapExternalProvider,
};
use automapper_validation::evaluator_factory::evaluator_for;
use mig_assembly::assembler::{
AssembledGroup, AssembledGroupInstance, AssembledSegment, AssembledTree,
};
use mig_assembly::navigator::AssembledTreeNavigator;
use mig_types::segment::OwnedSegment;
use ConditionResult::{False, True, Unknown};
fn seg(text: &str) -> AssembledSegment {
let mut parts = text.split('+');
let tag = parts.next().unwrap().to_string();
AssembledSegment {
tag,
elements: parts
.map(|e| e.split(':').map(str::to_string).collect())
.collect(),
mig_number: None,
segment_number: None,
}
}
fn inst(segments: &[&str], child_groups: Vec<AssembledGroup>) -> AssembledGroupInstance {
AssembledGroupInstance {
segments: segments.iter().map(|s| seg(s)).collect(),
child_groups,
entry_mig_number: None,
variant_mig_numbers: vec![],
skipped_segments: vec![],
skipped_positions: Vec::new(),
}
}
fn grp(id: &str, repetitions: Vec<AssembledGroupInstance>) -> AssembledGroup {
AssembledGroup {
group_id: id.to_string(),
repetitions,
}
}
fn tree(groups: Vec<AssembledGroup>) -> AssembledTree {
AssembledTree {
segments: vec![],
groups,
post_group_start: 0,
inter_group_segments: BTreeMap::new(),
}
}
fn flat(tree: &AssembledTree) -> Vec<OwnedSegment> {
fn walk(groups: &[AssembledGroup], out: &mut Vec<OwnedSegment>) {
for group in groups {
for instance in &group.repetitions {
for s in &instance.segments {
out.push(OwnedSegment {
id: s.tag.clone(),
elements: s.elements.clone(),
segment_number: out.len() as u32,
});
}
walk(&instance.child_groups, out);
}
}
}
let mut out = Vec::new();
walk(&tree.groups, &mut out);
out
}
type Case = (u32, &'static [(&'static str, usize)], ConditionResult);
fn check(
variant: &str,
fvs: &[&str],
tree: &AssembledTree,
cases: &[Case],
wrong: &mut Vec<String>,
) {
let navigator = AssembledTreeNavigator::new(tree);
let external = MapExternalProvider::new(Default::default());
let segments = flat(tree);
let ctx = EvaluationContext::with_navigator("00000", &external, &segments, &navigator);
for fv in fvs {
let evaluator = evaluator_for(variant, fv).unwrap_or_else(|| panic!("{variant} {fv}"));
for &(condition, path, expected) in cases {
let got = evaluator.evaluate(condition, &ctx.with_scope(GroupScope { path }));
if got != expected {
wrong.push(format!(
"{variant} {fv} [{condition}] at {path:?}: {got:?}, expected {expected:?}"
));
}
}
}
}
#[test]
fn each_instance_answers_for_itself() {
let mut wrong = Vec::new();
let aperak = tree(vec![grp(
"SG4",
vec![
inst(
&["ERC+Z10"],
vec![grp("SG5", vec![inst(&["RFF+TN:1"], vec![])])],
),
inst(
&["ERC+Z10"],
vec![grp("SG5", vec![inst(&["RFF+ACW:2"], vec![])])],
),
],
)]);
check(
"APERAK",
&["FV2504"],
&aperak,
&[(4, &[("SG4", 0)], False), (4, &[("SG4", 1)], True)],
&mut wrong,
);
let iftsta = tree(vec![grp(
"SG14",
vec![
inst(
&["CNI+1"],
vec![grp(
"SG15",
vec![inst(
&[
"STS+Z37",
"STS+Z21++A99",
"RFF+Z45:1",
"RFF+Z17:1",
"STS+Z20+Z32+A99:E_0278",
],
vec![],
)],
)],
),
inst(
&["CNI+2"],
vec![grp(
"SG15",
vec![inst(
&[
"STS+Z38",
"STS+Z21++B01",
"RFF+Z13:1",
"STS+Z20+Z32+A99:E_0281",
],
vec![],
)],
)],
),
inst(
&["CNI+3"],
vec![grp("SG15", vec![inst(&["STS+Z15+Z13+A99:E_0286"], vec![])])],
),
],
)]);
const SG15_0: &[(&str, usize)] = &[("SG14", 0), ("SG15", 0)];
const SG15_1: &[(&str, usize)] = &[("SG14", 1), ("SG15", 0)];
const SG15_2: &[(&str, usize)] = &[("SG14", 2), ("SG15", 0)];
let iftsta_cases: &[Case] = &[
(135, SG15_0, True),
(135, SG15_1, False),
(144, SG15_0, False),
(144, SG15_1, True),
(145, SG15_0, False),
(145, SG15_1, True),
(78, SG15_0, True),
(78, SG15_1, False),
(79, SG15_0, False),
(79, SG15_1, True),
];
check(
"IFTSTA",
&["FV2504", "FV2510"],
&iftsta,
iftsta_cases,
&mut wrong,
);
check(
"IFTSTA",
&["FV2510"],
&iftsta,
&[
(149, SG15_0, False),
(149, SG15_1, True),
(150, SG15_0, True),
(150, SG15_1, False),
(151, SG15_0, True),
(151, SG15_1, False),
(152, SG15_0, False),
(152, SG15_1, True),
(154, SG15_2, True),
(154, SG15_0, False),
],
&mut wrong,
);
let insrpt = tree(vec![grp(
"SG3",
vec![inst(
&["DOC+Z01"],
vec![grp(
"SG7",
vec![
inst(&["LIN+1", "STS+Z06+Z10"], vec![]),
inst(&["LIN+2", "STS+Z06+Z11"], vec![]),
],
)],
)],
)]);
check(
"INSRPT",
&["FV2510"],
&insrpt,
&[
(8, &[("SG3", 0), ("SG7", 0)], True),
(8, &[("SG3", 0), ("SG7", 1)], False),
],
&mut wrong,
);
let sg9 = |sts: &str| {
inst(
&["LIN+1"],
vec![grp("SG10", vec![inst(&["QTY+220:1", sts], vec![])])],
)
};
let mscons = tree(vec![grp(
"SG5",
vec![inst(
&["NAD+DP"],
vec![grp(
"SG6",
vec![inst(
&["LOC+172+DE0001"],
vec![grp(
"SG9",
vec![
sg9("STS+10+Z38"),
sg9("STS+10+Z39"),
sg9("STS+10+Z36"),
sg9("STS+10+Z37"),
],
)],
)],
)],
)],
)]);
const M0: &[(&str, usize)] = &[("SG5", 0), ("SG6", 0), ("SG9", 0), ("SG10", 0)];
const M1: &[(&str, usize)] = &[("SG5", 0), ("SG6", 0), ("SG9", 1), ("SG10", 0)];
const M2: &[(&str, usize)] = &[("SG5", 0), ("SG6", 0), ("SG9", 2), ("SG10", 0)];
const M3: &[(&str, usize)] = &[("SG5", 0), ("SG6", 0), ("SG9", 3), ("SG10", 0)];
check(
"MSCONS",
&["FV2504", "FV2510", "FV2604"],
&mscons,
&[
(83, M0, False),
(83, M1, True),
(84, M0, True),
(84, M1, False),
(85, M0, True),
(85, M2, False),
(86, M0, True),
(86, M3, False),
],
&mut wrong,
);
let orders = tree(vec![grp(
"SG29",
vec![
inst(
&["LIN++Z54", "PIA+5+9991000000078:Z11"],
vec![grp("SG30", vec![inst(&["CCI+Z01", "CAV+ZH9"], vec![])])],
),
inst(&["LIN++Z54", "PIA+5+9991000000086:Z11"], vec![]),
],
)]);
const O0: &[(&str, usize)] = &[("SG29", 0)];
const O1: &[(&str, usize)] = &[("SG29", 1)];
check(
"ORDERS",
&["FV2504", "FV2510", "FV2604"],
&orders,
&[
(81, O0, True),
(81, O1, False),
(112, O0, True),
(112, O1, False),
(85, O0, False),
(85, O1, True),
(161, O0, False),
(161, O1, True),
],
&mut wrong,
);
let quotes = tree(vec![grp(
"SG27",
vec![inst(
&["LIN+1"],
vec![grp(
"SG31",
vec![
inst(&["PRI+CAL:1", "RNG+Z03"], vec![]),
inst(&["PRI+CAL:2", "RNG+Z04"], vec![]),
],
)],
)],
)]);
const Q0: &[(&str, usize)] = &[("SG27", 0), ("SG31", 0)];
const Q1: &[(&str, usize)] = &[("SG27", 0), ("SG31", 1)];
check(
"QUOTES",
&["FV2510"],
"es,
&[
(93, Q0, False),
(93, Q1, True),
(94, Q0, True),
(94, Q1, False),
],
&mut wrong,
);
let utilts = tree(vec![grp(
"SG5",
vec![inst(
&["IDE+24+1"],
vec![grp(
"SG8",
vec![
inst(&["SEQ+Z37", "RFF+Z19:1"], vec![]),
inst(&["SEQ+Z37", "RFF+Z23:1"], vec![]),
],
)],
)],
)]);
const U0: &[(&str, usize)] = &[("SG5", 0), ("SG8", 0)];
const U1: &[(&str, usize)] = &[("SG5", 0), ("SG8", 1)];
check(
"UTILTS",
&["FV2504"],
&utilts,
&[
(5, U0, False),
(5, U1, True),
(6, U0, True),
(6, U1, False),
(7, U0, True),
(7, U1, False),
],
&mut wrong,
);
let pricat = tree(vec![grp(
"SG17",
vec![inst(
&["PGI+Z01"],
vec![grp(
"SG36",
vec![
inst(&["LIN+1++1-01:Z12"], vec![]),
inst(&["LIN+2++1-02:Z12"], vec![]),
],
)],
)],
)]);
const P0: &[(&str, usize)] = &[("SG17", 0), ("SG36", 0)];
const P1: &[(&str, usize)] = &[("SG17", 0), ("SG36", 1)];
check(
"PRICAT",
&["FV2510"],
&pricat,
&[
(61, P0, False),
(61, P1, True),
(65, P0, False),
(65, P1, True),
],
&mut wrong,
);
let _ = Unknown;
assert!(wrong.is_empty(), "{wrong:#?}");
}