mod common;
use automapper_generator::parsing::ahb_parser::parse_ahb;
use common::test_utils::discover_xml_paths;
use mig_assembly::parsing::parse_mig;
use mig_assembly::pid_filter::filter_mig_for_pid;
use mig_bo4e::engine::MappingEngine;
use mig_bo4e::error_mapping::Bo4eFieldIndex;
use mig_bo4e::path_resolver::PathResolver;
use mig_types::schema::mig::MigSchema;
use std::collections::HashSet;
use std::path::Path;
const MAPPINGS_DIR: &str = "../../mappings/FV2504/UTILMD_Strom/pid_55001";
const MESSAGE_DIR: &str = "../../mappings/FV2504/UTILMD_Strom/message";
const SCHEMA_DIR: &str = "../../crates/mig-types/src/generated/fv2504/utilmd/pids";
fn path_resolver() -> PathResolver {
PathResolver::from_schema_dir(std::path::Path::new(SCHEMA_DIR))
}
fn load_pid_filtered_mig(pid_id: &str) -> Option<MigSchema> {
let (mig_path, ahb_path) = discover_xml_paths("FV2504", "UTILMD", Some("Strom"))?;
let mig = parse_mig(&mig_path, "UTILMD", Some("Strom"), "FV2504").ok()?;
let ahb = parse_ahb(&ahb_path, "UTILMD", Some("Strom"), "FV2504").ok()?;
let pid = ahb.workflows.iter().find(|w| w.id == pid_id)?;
let numbers: HashSet<String> = pid.segment_numbers.iter().cloned().collect();
Some(filter_mig_for_pid(&mig, &numbers))
}
fn load_split_engines() -> Option<(MappingEngine, MappingEngine)> {
let msg_dir = Path::new(MESSAGE_DIR);
let tx_dir = Path::new(MAPPINGS_DIR);
if !msg_dir.exists() || !tx_dir.exists() {
return None;
}
MappingEngine::load_split(msg_dir, tx_dir)
.ok()
.map(|(m, t)| {
let r = path_resolver();
(m.with_path_resolver(r.clone()), t.with_path_resolver(r))
})
}
#[test]
fn test_marktlokation_path_resolution() {
let mig = match load_pid_filtered_mig("55001") {
Some(m) => m,
None => {
eprintln!("Skipping: MIG/AHB XML not available");
return;
}
};
let (msg_engine, tx_engine) = match load_split_engines() {
Some(e) => e,
None => {
eprintln!("Skipping: mapping files not available");
return;
}
};
let mut all_defs: Vec<_> = msg_engine.definitions().to_vec();
all_defs.extend(tx_engine.definitions().iter().cloned());
let index = Bo4eFieldIndex::build(&all_defs, &mig);
let result = index.resolve("SG4/SG5/LOC/C517/3225", None);
assert_eq!(
result.as_deref(),
Some("stammdaten.Marktlokation.marktlokationsId"),
"Should resolve LOC/C517/3225 to Marktlokation.marktlokationsId"
);
}
#[test]
fn test_prozessdaten_path_resolution() {
let mig = match load_pid_filtered_mig("55001") {
Some(m) => m,
None => {
eprintln!("Skipping: MIG/AHB XML not available");
return;
}
};
let (msg_engine, tx_engine) = match load_split_engines() {
Some(e) => e,
None => {
eprintln!("Skipping: mapping files not available");
return;
}
};
let mut all_defs: Vec<_> = msg_engine.definitions().to_vec();
all_defs.extend(tx_engine.definitions().iter().cloned());
let index = Bo4eFieldIndex::build(&all_defs, &mig);
let result = index.resolve("SG4/IDE/C206/7402", None);
assert_eq!(
result.as_deref(),
Some("stammdaten.Prozessdaten.vorgangId"),
"Should resolve IDE/C206/7402 to Prozessdaten.vorgangId"
);
}
#[test]
fn test_prefix_match_for_entity_level() {
let mig = match load_pid_filtered_mig("55001") {
Some(m) => m,
None => {
eprintln!("Skipping: MIG/AHB XML not available");
return;
}
};
let (msg_engine, tx_engine) = match load_split_engines() {
Some(e) => e,
None => {
eprintln!("Skipping: mapping files not available");
return;
}
};
let mut all_defs: Vec<_> = msg_engine.definitions().to_vec();
all_defs.extend(tx_engine.definitions().iter().cloned());
let index = Bo4eFieldIndex::build(&all_defs, &mig);
let result = index.resolve("SG2/NAD/unknown_element", None);
assert!(
result.is_some(),
"Should prefix-match SG2/NAD to a stammdaten entity"
);
let resolved = result.unwrap();
assert!(
resolved.starts_with("stammdaten."),
"SG2 entities should be in stammdaten, got: {resolved}"
);
}
#[test]
fn test_haushaltskunde_path_resolution() {
let mig = match load_pid_filtered_mig("55001") {
Some(m) => m,
None => {
eprintln!("Skipping: MIG/AHB XML not available");
return;
}
};
let (msg_engine, tx_engine) = match load_split_engines() {
Some(e) => e,
None => {
eprintln!("Skipping: mapping files not available");
return;
}
};
let mut all_defs: Vec<_> = msg_engine.definitions().to_vec();
all_defs.extend(tx_engine.definitions().iter().cloned());
let reverse_resolver = mig_bo4e::path_resolver::ReversePathResolver::from_schema_dir(
std::path::Path::new(SCHEMA_DIR),
);
let index = Bo4eFieldIndex::build_with_resolver(&all_defs, &mig, &reverse_resolver);
let result = index.resolve("SG4/SG8/SG10/CCI/C240/7037", None);
assert_eq!(
result.as_deref(),
Some("stammdaten.Marktlokation.marktlokationEdifact.haushaltskunde"),
"Should resolve CCI/C240/7037 to Marktlokation companion haushaltskunde"
);
}
#[test]
fn test_dtm_qualifier_path_resolution() {
let mig = match load_pid_filtered_mig("55001") {
Some(m) => m,
None => {
eprintln!("Skipping: MIG/AHB XML not available");
return;
}
};
let (msg_engine, tx_engine) = match load_split_engines() {
Some(e) => e,
None => {
eprintln!("Skipping: mapping files not available");
return;
}
};
let mut all_defs: Vec<_> = msg_engine.definitions().to_vec();
all_defs.extend(tx_engine.definitions().iter().cloned());
let reverse_resolver = mig_bo4e::path_resolver::ReversePathResolver::from_schema_dir(
std::path::Path::new(SCHEMA_DIR),
);
let index = Bo4eFieldIndex::build_with_resolver(&all_defs, &mig, &reverse_resolver);
let result = index.resolve("SG4/DTM/C507/2005", Some("93"));
assert_eq!(
result.as_deref(),
Some("stammdaten.Prozessdaten.gueltigBis"),
"DTM+93 qualifier should resolve to Prozessdaten.gueltigBis"
);
let result = index.resolve("SG4/DTM/C507/2005", Some("92"));
assert_eq!(
result.as_deref(),
Some("stammdaten.Prozessdaten.gueltigAb"),
"DTM+92 qualifier should resolve to Prozessdaten.gueltigAb"
);
let result = index.resolve("SG4/DTM/C507/2380", Some("93"));
assert_eq!(
result.as_deref(),
Some("stammdaten.Prozessdaten.gueltigBis"),
"DTM+93 data field should resolve to Prozessdaten.gueltigBis"
);
}
#[test]
fn test_unknown_path_returns_none() {
let mig = match load_pid_filtered_mig("55001") {
Some(m) => m,
None => {
eprintln!("Skipping: MIG/AHB XML not available");
return;
}
};
let (msg_engine, tx_engine) = match load_split_engines() {
Some(e) => e,
None => {
eprintln!("Skipping: mapping files not available");
return;
}
};
let mut all_defs: Vec<_> = msg_engine.definitions().to_vec();
all_defs.extend(tx_engine.definitions().iter().cloned());
let index = Bo4eFieldIndex::build(&all_defs, &mig);
assert!(index.resolve("SG99/UNKNOWN/9999", None).is_none());
}