ocpi-tariffs 0.46.1

OCPI tariff calculations
Documentation
use assert_matches::assert_matches;
use chrono::TimeDelta;

use crate::generate::EventCollector;

use super::{generate_time_events, v2x::TimeRestrictions};

use super::test::date_time_span;

#[test]
fn should_emit_no_events_before_start_time() {
    // The chargesession takes place before the `start_time`
    let cdr_time_range = date_time_span("2025-11-10", "12:02:00", "2025-11-10", "14:00:00");
    let mut events = EventCollector::from_time_range(&cdr_time_range);

    generate_time_events(
        &mut events,
        chrono_tz::Tz::Europe__Amsterdam,
        cdr_time_range,
        TimeRestrictions {
            start_time: Some("15:00".parse().unwrap()),
            ..TimeRestrictions::default()
        },
    );

    assert_matches!(events.into_inner().as_slice(), []);
}

#[test]
fn should_emit_no_events_finishes_at_start_time_precisely() {
    let cdr_time_range = date_time_span("2025-11-10", "12:02:00", "2025-11-10", "14:00:00");
    let mut events = EventCollector::from_time_range(&cdr_time_range);

    // The chargesession takes place before the `start_time`
    generate_time_events(
        &mut events,
        chrono_tz::Tz::Europe__Amsterdam,
        cdr_time_range,
        TimeRestrictions {
            start_time: Some("15:00".parse().unwrap()),
            ..TimeRestrictions::default()
        },
    );

    assert_matches!(events.into_inner().as_slice(), []);
}

#[test]
fn should_emit_one_event_precise_overlap_with_start_time() {
    let cdr_time_range = date_time_span("2025-11-10", "15:00:00", "2025-11-10", "17:00:00");
    let mut events = EventCollector::from_time_range(&cdr_time_range);

    // The chargesession starts precisely when the `start_time` generates an event.
    generate_time_events(
        &mut events,
        chrono_tz::Tz::Europe__Amsterdam,
        cdr_time_range,
        TimeRestrictions {
            start_time: Some("15:00".parse().unwrap()),
            ..TimeRestrictions::default()
        },
    );

    let [event] = events.into_inner().try_into().unwrap();
    assert_eq!(event.duration_from_start, TimeDelta::zero());
}

#[test]
fn should_emit_one_event_hour_before_start_time() {
    let cdr_time_range = date_time_span("2025-11-10", "14:00:00", "2025-11-10", "17:00:00");
    let mut events = EventCollector::from_time_range(&cdr_time_range);

    // The chargesession starts an hour before the `start_time` generates an event.
    generate_time_events(
        &mut events,
        chrono_tz::Tz::Europe__Amsterdam,
        cdr_time_range,
        TimeRestrictions {
            start_time: Some("15:00".parse().unwrap()),
            ..TimeRestrictions::default()
        },
    );

    let [event] = events.into_inner().try_into().unwrap();
    assert_eq!(event.duration_from_start, TimeDelta::hours(1));
}

#[test]
fn should_emit_one_event_almost_full_day() {
    let cdr_time_range = date_time_span("2025-11-10", "15:00:00", "2025-11-11", "14:59:00");
    let mut events = EventCollector::from_time_range(&cdr_time_range);

    // The chargesession last from precisely the `start_time` of one day
    // until just before the `start_time` of the next.
    generate_time_events(
        &mut events,
        chrono_tz::Tz::Europe__Amsterdam,
        cdr_time_range,
        TimeRestrictions {
            start_time: Some("15:00".parse().unwrap()),
            ..TimeRestrictions::default()
        },
    );

    let [event] = events.into_inner().try_into().unwrap();
    assert_eq!(event.duration_from_start, TimeDelta::zero());
}

#[test]
fn should_emit_two_events_full_day_precisely() {
    let cdr_time_range = date_time_span("2025-11-10", "15:00:00", "2025-11-11", "15:00:00");
    let mut events = EventCollector::from_time_range(&cdr_time_range);

    generate_time_events(
        &mut events,
        chrono_tz::Tz::Europe__Amsterdam,
        cdr_time_range,
        TimeRestrictions {
            start_time: Some("15:00".parse().unwrap()),
            ..TimeRestrictions::default()
        },
    );

    let [event_0, event_1] = events.into_inner().try_into().unwrap();
    assert_eq!(event_0.duration_from_start, TimeDelta::zero());
    assert_eq!(event_1.duration_from_start, TimeDelta::days(1));
}

#[test]
fn should_emit_two_events_full_day_with_hour_margin() {
    let cdr_time_range = date_time_span("2025-11-10", "14:00:00", "2025-11-11", "16:00:00");
    let mut events = EventCollector::from_time_range(&cdr_time_range);

    generate_time_events(
        &mut events,
        chrono_tz::Tz::Europe__Amsterdam,
        cdr_time_range,
        TimeRestrictions {
            start_time: Some("15:00".parse().unwrap()),
            ..TimeRestrictions::default()
        },
    );

    let [event_0, event_1] = events.into_inner().try_into().unwrap();
    assert_eq!(event_0.duration_from_start, TimeDelta::hours(1));
    assert_eq!(
        event_1.duration_from_start,
        TimeDelta::days(1) + TimeDelta::hours(1)
    );
}