use std::path::PathBuf;
use edifact_mapper::{DataDir, Mapper};
use serde_json::Value;
fn repo_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.canonicalize()
.unwrap()
}
fn input_with_distinct_free_text(fv: &str) -> String {
let fixture = repo_root()
.join("fixtures/generated")
.join(fv.to_lowercase())
.join("iftsta/21039.edi");
let raw = std::fs::read_to_string(&fixture).unwrap();
let mut out = Vec::new();
let mut current_sts: Option<String> = None;
let flush = |out: &mut Vec<String>, sts: &Option<String>| {
if let Some(q) = sts {
out.push(format!("GID+{}", &q[1..]));
out.push(format!("FTX+ACB+++Text {q}"));
}
};
for segment in raw.split('\'').map(str::trim).filter(|s| !s.is_empty()) {
if segment.starts_with("GID+") || segment.starts_with("FTX+") {
continue;
}
if segment.starts_with("STS+") || segment.starts_with("UNT+") {
flush(&mut out, ¤t_sts);
current_sts = segment
.strip_prefix("STS+")
.map(|rest| rest.split('+').next().unwrap().to_string());
}
out.push(segment.to_string());
}
out.iter().map(|s| format!("{s}'")).collect()
}
fn position(haystack: &str, needle: &str) -> usize {
haystack
.find(needle)
.unwrap_or_else(|| panic!("`{needle}` missing in:\n{haystack}"))
}
#[test]
fn free_text_stays_with_its_status_when_statuses_are_swapped() {
let dist = repo_root().join("dist");
for fv in ["FV2504", "FV2510", "FV2604", "FV2610"] {
let mapper = Mapper::from_data_dir(DataDir::path(&dist).eager(&[fv])).unwrap();
let edifact = input_with_distinct_free_text(fv);
let ic = mapper
.from_edifact::<Value, Value>(&edifact, fv, "IFTSTA", "21039")
.unwrap_or_else(|e| panic!("{fv}: forward failed: {e}"));
let nachricht = &ic.nachrichten[0];
let mut txs: Vec<Value> = nachricht
.transaktionen
.iter()
.map(|t| match t.get("stammdaten") {
Some(st) => {
let mut out = st.clone();
mig_bo4e::model::restore_entity(
&mut out,
mig_bo4e::model::TX_METADATA_ENTITY,
t.get("transaktionsdaten").unwrap_or(&Value::Null),
);
out
}
None => t.clone(),
})
.collect();
assert_eq!(txs.len(), 1, "{fv}");
let status = txs[0]
.get_mut("status")
.and_then(Value::as_array_mut)
.unwrap_or_else(|| panic!("{fv}: status array: {}", nachricht.transaktionen[0]));
assert_eq!(status.len(), 2, "{fv}");
for s in status.iter() {
assert!(
s.get("freitext").is_some_and(Value::is_array),
"{fv}: free text must be nested in its status: {s}"
);
}
assert!(
txs[0].get("freitext").is_none(),
"{fv}: no top-level free text paired by position: {}",
txs[0]
);
txs[0]["status"].as_array_mut().unwrap().reverse();
let rendered = mapper
.to_edifact(&nachricht.stammdaten, &txs, fv, "IFTSTA", "21039")
.unwrap_or_else(|e| panic!("{fv}: reverse failed: {e}"));
let z37 = position(&rendered, "STS+Z37");
let text_z37 = position(&rendered, "Text Z37");
let z38 = position(&rendered, "STS+Z38");
let text_z38 = position(&rendered, "Text Z38");
assert!(
z37 < text_z37 && text_z37 < z38 && z38 < text_z38,
"{fv}: each free text must follow its own STS:\n{rendered}"
);
}
}