use edifact_mapper::{DataDir, Mapper, ValidationLevel};
use std::path::PathBuf;
const FV: &str = "FV2604";
const VARIANT: &str = "UTILMD_Strom";
const PID: &str = "55001";
fn setup() -> Option<(Mapper, Vec<String>)> {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.and_then(|p| p.parent())
.unwrap()
.to_path_buf();
if !root.join(format!("dist/edifact-data-{FV}.bin")).exists() {
eprintln!("skipping: build the {FV} bundle first");
return None;
}
let mapper =
Mapper::from_data_dir(DataDir::path(root.join("dist")).eager(&[FV])).expect("load bundle");
let edifact =
std::fs::read_to_string(root.join(format!("fixtures/generated/fv2604/utilmd/{PID}.edi")))
.expect("fixture");
let segments = edifact
.split('\'')
.map(str::trim)
.filter(|s| !s.is_empty())
.map(str::to_string)
.collect();
Some((mapper, segments))
}
fn message(mut segments: Vec<String>) -> String {
let unh = segments.iter().position(|s| s.starts_with("UNH")).unwrap();
let unt = segments.iter().position(|s| s.starts_with("UNT")).unwrap();
let reference = segments[unt].rsplit('+').next().unwrap().to_string();
segments[unt] = format!("UNT+{}+{reference}", unt - unh + 1);
segments.join("'") + "'"
}
fn structure_codes(mapper: &Mapper, edifact: &str) -> Vec<(String, String, String)> {
let report = mapper
.validate_edifact_for_pid(edifact, FV, VARIANT, PID, ValidationLevel::Full)
.expect("validate");
report
.issues
.iter()
.filter(|i| matches!(i.code(), "STR001" | "STR002" | "STR005" | "STR006"))
.map(|i| {
let detail = match &i.kind {
automapper_validation::IssueKind::StructureDiagnostic { detail, .. } => {
detail.clone()
}
_ => String::new(),
};
(i.code().to_string(), detail, format!("{:?}", i.severity))
})
.collect()
}
#[test]
fn a_well_formed_sample_has_no_structure_findings() {
let Some((mapper, segments)) = setup() else {
return;
};
let found = structure_codes(&mapper, &message(segments));
assert!(found.is_empty(), "{found:?}");
}
#[test]
fn a_second_sender_is_a_group_repeating_too_often() {
let Some((mapper, mut segments)) = setup() else {
return;
};
let ms = segments
.iter()
.position(|s| s.starts_with("NAD+MS"))
.expect("NAD+MS");
let copy = segments[ms].clone();
segments.insert(ms + 1, copy);
let found = structure_codes(&mapper, &message(segments));
assert!(
found.iter().any(|(code, detail, severity)| code == "STR006"
&& detail.contains("NAD+MS")
&& severity == "Warning"),
"{found:?}"
);
}
#[test]
fn a_missing_recipient_is_a_missing_mandatory_group() {
let Some((mapper, mut segments)) = setup() else {
return;
};
let mr = segments
.iter()
.position(|s| s.starts_with("NAD+MR"))
.expect("NAD+MR");
segments.remove(mr);
while segments
.get(mr)
.is_some_and(|s| s.starts_with("CTA") || s.starts_with("COM"))
{
segments.remove(mr);
}
let found = structure_codes(&mapper, &message(segments));
assert!(
found
.iter()
.any(|(code, detail, severity)| code == "STR005"
&& detail.contains("NAD+MR")
&& severity == "Error"),
"{found:?}"
);
}