edifact-mapper 0.12.0

EDIFACT to BO4E bidirectional conversion for the German energy market
Documentation
//! Integration test for PID validation via Mapper API.

use edifact_mapper::{DataDir, Mapper};
use serde_json::json;

/// The committed bundles under `dist/`.
///
/// This used to read `/tmp/edifact-bundles` and return early when it was not
/// there, which is every fresh checkout and every CI run — so the tests below
/// passed without asserting anything.
fn mapper() -> Mapper {
    let dist = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../dist");
    assert!(
        dist.join("edifact-data-FV2504.bin").exists(),
        "no FV2504 bundle at {}: run `cargo run -p automapper-generator -- bundle-data`",
        dist.display()
    );
    Mapper::from_data_dir(DataDir::path(&dist).eager(&["FV2504"])).expect("load bundle")
}

#[test]
fn test_validate_empty_returns_errors() {
    let mapper = mapper();
    let json = json!({});
    let errors = mapper
        .validate_pid(&json, "FV2504", "UTILMD_Strom", "55001")
        .unwrap();
    assert!(
        !errors.is_empty(),
        "Empty object should have validation errors"
    );
    assert!(errors
        .iter()
        .any(|e| matches!(e, mig_bo4e::PidValidationError::MissingEntity { .. })));
}

#[test]
fn test_validate_provided_entities_not_missing() {
    let mapper = mapper();
    let json = json!({
        "prozessdaten": {
            "pruefidentifikator": "55001",
            "transaktionsnummer": "55001",
            "vorgangId": "V001",
            "transaktionsgrund": "E01",
            "transaktionsgrundErgaenzung": "E01",
            "transaktionsgrundErgaenzungBefristeteAnmeldung": "E01",
            "gueltigAb": "20260101"
        },
        "marktlokation": {
            "marktlokationsId": "51238696781"
        }
    });
    let errors = mapper
        .validate_pid(&json, "FV2504", "UTILMD_Strom", "55001")
        .unwrap();

    // Provided entities should not be missing
    assert!(
        !errors.iter().any(|e| matches!(
            e,
            mig_bo4e::PidValidationError::MissingEntity { entity, .. }
            if entity == "Prozessdaten" || entity == "Marktlokation"
        )),
        "Provided entities should not be missing. Errors: {:?}",
        errors
    );
}

#[test]
fn test_validate_missing_required_field() {
    let mapper = mapper();
    // Provide Ansprechpartner entity but omit required "nachname" field (ahb_status=X)
    let json = json!({
        "ansprechpartner": {
            "vorname": "Max"
        }
    });
    let errors = mapper
        .validate_pid(&json, "FV2504", "UTILMD_Strom", "55001")
        .unwrap();
    assert!(
        errors.iter().any(|e| matches!(
            e,
            mig_bo4e::PidValidationError::MissingField { entity, field, .. }
            if entity == "Ansprechpartner" && field == "nachname"
        )),
        "Should report missing nachname field. Errors: {:?}",
        errors
    );
}

#[test]
fn test_validate_invalid_code() {
    let mapper = mapper();
    let json = json!({
        "ansprechpartner": {
            "anredeCode": "INVALID"
        }
    });
    let errors = mapper
        .validate_pid(&json, "FV2504", "UTILMD_Strom", "55001")
        .unwrap();
    assert!(
        errors.iter().any(|e| matches!(
            e,
            mig_bo4e::PidValidationError::InvalidCode { entity, field, .. }
            if entity == "Ansprechpartner" && field == "anredeCode"
        )),
        "Should report invalid anredeCode. Errors: {:?}",
        errors
    );
}

// ── Condition-aware validation tests ────────────────────────────────────

#[test]
fn test_validate_with_conditions_produces_results() {
    let mapper = mapper();

    let json = json!({
        "prozessdaten": {
            "pruefidentifikator": "55001",
            "transaktionsnummer": "55001",
            "vorgangId": "V001",
            "transaktionsgrund": "E01",
            "transaktionsgrundErgaenzung": "ZW4",
            "transaktionsgrundErgaenzungBefristeteAnmeldung": "E01"
        }
    });

    // Basic validation (no conditions) reports errors
    let basic_errors = mapper
        .validate_pid(&json, "FV2504", "UTILMD_Strom", "55001")
        .unwrap();

    // Condition-aware validation should also produce results (not crash)
    let cond_errors = mapper
        .validate_pid_with_conditions(&json, "FV2504", "UTILMD_Strom", "55001")
        .unwrap();

    // Both should have errors (incomplete data)
    assert!(
        !basic_errors.is_empty(),
        "Basic validation should report errors for incomplete data"
    );
    assert!(
        !cond_errors.is_empty(),
        "Condition-aware validation should report errors for incomplete data"
    );

    // Condition-aware may have fewer errors (some conditional fields evaluate to False)
    // or more (some Unknown conditions become warnings). The key test is it doesn't crash.
    eprintln!("Basic errors: {}", basic_errors.len());
    eprintln!("Condition-aware errors: {}", cond_errors.len());
}

#[test]
fn test_validate_with_conditions_empty_json() {
    let mapper = mapper();
    let json = json!({});
    let result = mapper.validate_pid_with_conditions(&json, "FV2504", "UTILMD_Strom", "55001");
    assert!(result.is_ok());
    let errors = result.unwrap();
    assert!(
        !errors.is_empty(),
        "Empty JSON should produce validation errors"
    );
}

#[test]
fn test_validate_with_conditions_wrong_variant() {
    let mapper = mapper();
    let result = mapper.validate_pid_with_conditions(&json!({}), "FV2504", "NONEXISTENT", "55001");
    assert!(result.is_err());
}

#[test]
fn test_validate_with_conditions_wrong_pid() {
    let mapper = mapper();
    let result = mapper.validate_pid_with_conditions(&json!({}), "FV2504", "UTILMD_Strom", "99999");
    assert!(result.is_err());
}

#[test]
fn test_validate_wrong_variant_returns_error() {
    let mapper = mapper();
    let result = mapper.validate_pid(&json!({}), "FV2504", "NONEXISTENT", "55001");
    assert!(result.is_err());
}

#[test]
fn test_validate_wrong_pid_returns_error() {
    let mapper = mapper();
    let result = mapper.validate_pid(&json!({}), "FV2504", "UTILMD_Strom", "99999");
    assert!(result.is_err());
}