ocpi-tariffs 0.52.0

OCPI tariff calculations
Documentation
//! Tests for lowering the tariffs embedded in a CDR via `cdr::Versioned::tariffs_to_v221`.

use std::assert_matches;

use crate::{cdr, json, schema, tariff, test, Version};

/// A minimal, valid `v2.2.1` CDR carrying a single embedded tariff.
const CDR: &str = r#"{
    "country_code": "NL",
    "party_id": "ENE",
    "start_date_time": "2022-01-13T16:00:00Z",
    "end_date_time": "2022-01-13T19:12:00Z",
    "currency": "EUR",
    "tariffs": [
        {
            "country_code": "NL",
            "party_id": "TNM",
            "currency": "EUR",
            "id": "ID",
            "last_updated": "2024-01-01T00:00:00Z",
            "elements": [
                {"price_components": [{"price": 0.25, "step_size": 1, "type": "ENERGY"}]}
            ]
        }
    ],
    "cdr_location": {"country": "NLD"},
    "charging_periods": [
        {
            "start_date_time": "2022-01-13T16:00:00Z",
            "dimensions": [{"type": "TIME", "volume": 2.5}]
        }
    ],
    "total_cost": {"excl_vat": 11.25, "incl_vat": 12.75},
    "total_time": 3.2,
    "total_energy": 0,
    "last_updated": "2022-01-13T00:00:00Z"
}"#;

#[test]
fn embedded_tariffs_lower_from_schema() {
    test::setup();

    let doc = json::parse_object(CDR).unwrap();
    let cdr = cdr::from_json(doc, Version::V221).ignore_warnings();

    let tariffs = cdr.tariffs_to_v221().unwrap().ignore_warnings();

    assert_eq!(tariffs.len(), 1);
    let tariff = tariffs.into_iter().next().unwrap().ignore_warnings();
    assert_eq!(&*tariff.id, "ID");
}

#[test]
fn absent_tariffs_field_yields_no_tariffs() {
    test::setup();

    let src = CDR.replace(r#""tariffs": ["#, r#""unused": [1], "not_tariffs": ["#);
    let doc = json::parse_object(&src).unwrap();
    let cdr = cdr::from_json(doc, Version::V221).ignore_warnings();

    let tariffs = cdr.tariffs_to_v221().unwrap().ignore_warnings();

    assert!(tariffs.is_empty());
}

#[test]
fn wrong_kind_tariffs_field_is_rejected() {
    test::setup();

    // The schema walk locates the cause; the lowering only refuses to carry on.
    let src = CDR.replace(
        r#""tariffs": [
        {
            "country_code": "NL",
            "party_id": "TNM",
            "currency": "EUR",
            "id": "ID",
            "last_updated": "2024-01-01T00:00:00Z",
            "elements": [
                {"price_components": [{"price": 0.25, "step_size": 1, "type": "ENERGY"}]}
            ]
        }
    ]"#,
        r#""tariffs": 5"#,
    );
    let doc = json::parse_object(&src).unwrap();
    let (cdr, schema_warnings) = cdr::from_json(doc, Version::V221).into_parts();

    let type_mismatches = schema_warnings
        .into_path_as_str_map()
        .remove("$.tariffs")
        .expect("the schema should report the `tariffs` field");
    assert_matches!(
        type_mismatches.as_slice(),
        [schema::Warning::TypeMismatch { .. }]
    );

    let err = cdr.tariffs_to_v221().unwrap_err();
    let error = err.unwrap();

    assert_matches!(error.into_warning(), tariff::Warning::Rejected);
}

#[test]
fn an_embedded_tariff_without_elements_is_rejected() {
    test::setup();

    let src = CDR.replace(
        r#"[
                {"price_components": [{"price": 0.25, "step_size": 1, "type": "ENERGY"}]}
            ]"#,
        "[]",
    );
    let doc = json::parse_object(&src).unwrap();
    let cdr = cdr::from_json(doc, Version::V221).ignore_warnings();

    let err = cdr.tariffs_to_v221().unwrap_err();
    let error = err.unwrap();

    assert_matches!(error.into_warning(), tariff::Warning::NoElements);
}