bo4e 0.2.0

BO4E (Business Objects for Energy) - Rust implementation
Documentation
//! Golden file tests comparing Rust output to Python fixtures.
//!
//! These tests verify that the Rust implementation can correctly deserialize
//! JSON generated by the BO4E Python library, ensuring compatibility.

use bo4e::prelude::*;
use std::fs;
use std::path::PathBuf;

/// Get the path to a golden fixture file.
fn fixture_path(name: &str) -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("golden")
        .join("fixtures")
        .join(format!("{}.json", name))
}

/// Load a fixture file as a string.
fn load_fixture(name: &str) -> String {
    let path = fixture_path(name);
    fs::read_to_string(&path).unwrap_or_else(|e| panic!("Failed to load fixture {}: {}", name, e))
}

#[test]
fn test_meter_from_german_json() {
    let fixture = load_fixture("meter");
    let mut bytes = fixture.as_bytes().to_vec();

    // Parse Python/German JSON
    let meter: Meter = bo4e::from_json(&mut bytes).expect("Failed to parse meter");

    // Verify fields were correctly parsed
    assert_eq!(meter.meter_number, Some("1EMH0012345678".to_string()));
    assert_eq!(meter.division, Some(Division::Electricity));

    // Verify metadata was parsed
    assert_eq!(meter.meta.typ, Some("Zaehler".to_string()));
}

#[test]
fn test_market_location_from_german_json() {
    let fixture = load_fixture("market_location");
    let mut bytes = fixture.as_bytes().to_vec();

    // Parse Python/German JSON
    let malo: MarketLocation =
        bo4e::from_json(&mut bytes).expect("Failed to parse market_location");

    // Verify fields
    assert_eq!(malo.market_location_id, Some("12345678901".to_string()));
    assert_eq!(malo.division, Some(Division::Electricity));
    assert_eq!(malo.energy_direction, Some(EnergyDirection::FeedOut));

    // Verify metadata
    assert_eq!(malo.meta.typ, Some("Marktlokation".to_string()));
}

#[test]
fn test_business_partner_from_german_json() {
    let fixture = load_fixture("business_partner");
    let mut bytes = fixture.as_bytes().to_vec();

    // Parse Python/German JSON
    let partner: BusinessPartner =
        bo4e::from_json(&mut bytes).expect("Failed to parse business_partner");

    // Verify fields
    assert_eq!(
        partner.name1,
        Some("Stadtwerke Musterstadt GmbH".to_string())
    );
    assert!(partner.roles.contains(&BusinessPartnerRole::Supplier));

    // Verify metadata
    assert_eq!(partner.meta.typ, Some("Geschaeftspartner".to_string()));
}

#[test]
fn test_roundtrip_meter() {
    // Create a Meter in Rust
    let original = Meter {
        meta: Bo4eMeta::with_type("Zaehler"),
        meter_number: Some("TEST123".to_string()),
        division: Some(Division::Electricity),
        ..Default::default()
    };

    // Serialize to English JSON
    let json = bo4e::to_json_english(&original).expect("Failed to serialize");

    // Deserialize back
    let mut bytes = json.into_bytes();
    let parsed: Meter = bo4e::from_json(&mut bytes).expect("Failed to deserialize");

    assert_eq!(original.meter_number, parsed.meter_number);
    assert_eq!(original.division, parsed.division);
}

#[test]
fn test_german_alias_deserialization() {
    // Test that German field names work in deserialization
    let german_json = r#"{
        "_typ": "Zaehler",
        "zaehlernummer": "GERMAN123",
        "sparte": "STROM"
    }"#;

    let mut bytes = german_json.as_bytes().to_vec();
    let meter: Meter = bo4e::from_json(&mut bytes).expect("Failed to parse German JSON");

    assert_eq!(meter.meter_number, Some("GERMAN123".to_string()));
    assert_eq!(meter.division, Some(Division::Electricity));
}

#[test]
fn test_english_deserialization() {
    // Test that English (camelCase) field names also work
    let english_json = r#"{
        "_typ": "Zaehler",
        "meterNumber": "ENGLISH456",
        "division": "STROM"
    }"#;

    let mut bytes = english_json.as_bytes().to_vec();
    let meter: Meter = bo4e::from_json(&mut bytes).expect("Failed to parse English JSON");

    assert_eq!(meter.meter_number, Some("ENGLISH456".to_string()));
    assert_eq!(meter.division, Some(Division::Electricity));
}

#[test]
fn test_address_german_aliases() {
    // Test Address component with German field names
    let german_json = r#"{
        "strasse": "Musterstraße",
        "hausnummer": "42",
        "postleitzahl": "50667",
        "ort": "Köln"
    }"#;

    let address: Address =
        serde_json::from_str(german_json).expect("Failed to parse German address");

    assert_eq!(address.street, Some("Musterstraße".to_string()));
    assert_eq!(address.house_number, Some("42".to_string()));
    assert_eq!(address.postal_code, Some("50667".to_string()));
    assert_eq!(address.city, Some("Köln".to_string()));
}

#[test]
fn test_market_location_german_aliases() {
    let german_json = r#"{
        "_typ": "Marktlokation",
        "marktlokationsId": "98765432109",
        "sparte": "GAS",
        "energierichtung": "EINSP",
        "jahresverbrauchsprognose": 5000.0
    }"#;

    let mut bytes = german_json.as_bytes().to_vec();
    let malo: MarketLocation =
        bo4e::from_json(&mut bytes).expect("Failed to parse German MarketLocation");

    assert_eq!(malo.market_location_id, Some("98765432109".to_string()));
    assert_eq!(malo.division, Some(Division::Gas));
    assert_eq!(malo.energy_direction, Some(EnergyDirection::FeedIn));
    assert_eq!(malo.annual_consumption, Some(5000.0));
}

#[test]
fn test_business_partner_german_aliases() {
    let german_json = r#"{
        "_typ": "Geschaeftspartner",
        "geschaeftspartnerId": "GP-001",
        "name1": "Test GmbH",
        "geschaeftspartnerrollen": ["KUNDE", "LIEFERANT"],
        "steuernummer": "12345/67890",
        "umsatzsteuerId": "DE123456789"
    }"#;

    let mut bytes = german_json.as_bytes().to_vec();
    let partner: BusinessPartner =
        bo4e::from_json(&mut bytes).expect("Failed to parse German BusinessPartner");

    assert_eq!(partner.partner_id, Some("GP-001".to_string()));
    assert_eq!(partner.name1, Some("Test GmbH".to_string()));
    assert!(partner.roles.contains(&BusinessPartnerRole::Customer));
    assert!(partner.roles.contains(&BusinessPartnerRole::Supplier));
    assert_eq!(partner.tax_id, Some("12345/67890".to_string()));
    assert_eq!(partner.vat_id, Some("DE123456789".to_string()));
}