use edifact_mapper::charset::{encode_interchange, CharsetError};
use edifact_mapper::{
DataDir, EdifactParty, InterchangeEnvelope, InterchangeMessage, Mapper, MapperError,
};
use std::path::PathBuf;
type Dynamic = mig_bo4e::model::Interchange<serde_json::Value, serde_json::Value>;
fn repo_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..")
}
fn mapper() -> Option<Mapper> {
Mapper::from_data_dir(DataDir::path(repo_root().join("dist"))).ok()
}
fn sample_with_umlaut() -> Option<String> {
let edi =
std::fs::read_to_string(repo_root().join("fixtures/generated/fv2504/utilmd/55001.edi"))
.ok()?;
let mut out = String::new();
let mut done = false;
for seg in edi.split_inclusive('\'') {
if !done && seg.starts_with("NAD+Z") {
let mut parts: Vec<String> = seg
.trim_end_matches('\'')
.split('+')
.map(String::from)
.collect();
if parts.len() > 4 {
let mut name: Vec<String> = parts[4].split(':').map(String::from).collect();
name[0] = "Müller".to_string();
parts[4] = name.join(":");
out.push_str(&parts.join("+"));
out.push('\'');
done = true;
continue;
}
}
out.push_str(seg);
}
done.then_some(out)
}
fn render_bytes(mapper: &Mapper, ic: &Dynamic) -> Result<Vec<u8>, MapperError> {
let msg = &ic.nachrichten[0];
mapper.to_edifact_interchange_bytes(
&InterchangeEnvelope {
sender: EdifactParty::bdew("9900000000001"),
receiver: EdifactParty::bdew("9900000000002"),
interchange_ref: "1".to_string(),
},
&[InterchangeMessage {
message_ref: "1".to_string(),
msg_stammdaten: msg.stammdaten.clone(),
tx_stammdaten: msg.transaktionen.clone(),
fv: "FV2504".to_string(),
variant: "UTILMD_Strom".to_string(),
pid: "55001".to_string(),
..Default::default()
}],
)
}
#[test]
fn latin1_bytes_convert_and_render_back_as_latin1() {
let (Some(mapper), Some(text)) = (mapper(), sample_with_umlaut()) else {
eprintln!("skipping: bundle or sample missing");
return;
};
assert!(text.contains("UNB+UNOC:3"));
let latin1 = encode_interchange(&text).expect("the sample fits ISO 8859-1");
assert!(
latin1.windows(2).any(|w| w == [b'M', 0xFC]),
"ü is the byte 0xFC"
);
let ic: Dynamic = mapper
.from_edifact_bytes(&latin1, "FV2504", "UTILMD_Strom", "55001")
.expect("a UNOC interchange given as bytes converts");
let json = serde_json::to_string(&ic).unwrap();
assert!(json.contains("Müller"), "the umlaut is read as itself");
let bytes = render_bytes(&mapper, &ic).expect("renders");
assert!(
bytes.windows(2).any(|w| w == [b'M', 0xFC]),
"rendered as ISO 8859-1"
);
assert!(
std::str::from_utf8(&bytes).is_err(),
"not UTF-8 under a UNOC header"
);
}
#[test]
fn a_character_outside_latin1_is_refused_not_sent() {
let Some(mapper) = mapper() else {
return;
};
let Some(text) = sample_with_umlaut() else {
return;
};
let ic: Dynamic = mapper
.from_edifact(
&text.replace("Müller", "Müller €"),
"FV2504",
"UTILMD_Strom",
"55001",
)
.expect("converts");
let err = render_bytes(&mapper, &ic).unwrap_err();
assert!(
matches!(
err,
MapperError::Charset(CharsetError::Unrepresentable {
character: '€', ..
})
),
"{err}"
);
}