relmath-rs 0.7.0

Relation-first mathematics and scientific computing in Rust.
Documentation
//! Integration tests for the first G5 interval foundation.

use std::collections::BTreeSet;

use relmath::temporal::{Interval, IntervalError};

#[test]
fn rejects_empty_or_inverted_intervals() {
    assert_eq!(
        Interval::new(2, 2),
        Err(IntervalError::InvalidBounds { start: 2, end: 2 })
    );
    assert_eq!(
        Interval::new(5, 3),
        Err(IntervalError::InvalidBounds { start: 5, end: 3 })
    );
}

#[test]
fn contains_uses_half_open_boundary_semantics() {
    let window = Interval::new(10, 13).expect("expected valid interval");

    assert!(window.contains(&10));
    assert!(window.contains(&12));
    assert!(!window.contains(&9));
    assert!(!window.contains(&13));
}

#[test]
fn overlaps_distinguishes_adjacent_from_intersecting_intervals() {
    let left = Interval::new(1, 3).expect("expected valid interval");
    let overlap = Interval::new(2, 4).expect("expected valid interval");
    let adjacent = Interval::new(3, 5).expect("expected valid interval");
    let disjoint = Interval::new(6, 8).expect("expected valid interval");

    assert!(left.overlaps(&overlap));
    assert!(!left.overlaps(&adjacent));
    assert!(!left.overlaps(&disjoint));
    assert!(left.is_adjacent_to(&adjacent));
    assert!(left.can_coalesce_with(&adjacent));
    assert!(!left.can_coalesce_with(&disjoint));
}

#[test]
fn intersection_and_restriction_return_none_for_boundary_only_contact() {
    let base = Interval::new(4, 9).expect("expected valid interval");
    let overlap = Interval::new(6, 11).expect("expected valid interval");
    let adjacent = Interval::new(9, 12).expect("expected valid interval");

    assert_eq!(
        base.intersection(&overlap),
        Some(Interval::new(6, 9).expect("expected valid interval"))
    );
    assert_eq!(
        base.restrict_to(&overlap),
        Some(Interval::new(6, 9).expect("expected valid interval"))
    );
    assert_eq!(base.intersection(&adjacent), None);
    assert_eq!(base.restrict_to(&adjacent), None);
}

#[test]
fn coalesce_merges_overlapping_or_adjacent_intervals() {
    let overlap_left = Interval::new(1, 4).expect("expected valid interval");
    let overlap_right = Interval::new(3, 6).expect("expected valid interval");
    let adjacent = Interval::new(6, 8).expect("expected valid interval");
    let disjoint = Interval::new(10, 12).expect("expected valid interval");

    assert_eq!(
        overlap_left.coalesce(&overlap_right),
        Some(Interval::new(1, 6).expect("expected valid interval"))
    );
    assert_eq!(
        overlap_right.coalesce(&adjacent),
        Some(Interval::new(3, 8).expect("expected valid interval"))
    );
    assert_eq!(overlap_left.coalesce(&disjoint), None);
}

#[test]
fn intervals_iterate_in_deterministic_lexicographic_order() {
    let ordered = BTreeSet::from([
        Interval::new(3, 5).expect("expected valid interval"),
        Interval::new(1, 4).expect("expected valid interval"),
        Interval::new(1, 3).expect("expected valid interval"),
        Interval::new(2, 7).expect("expected valid interval"),
    ])
    .into_iter()
    .collect::<Vec<_>>();

    assert_eq!(
        ordered,
        vec![
            Interval::new(1, 3).expect("expected valid interval"),
            Interval::new(1, 4).expect("expected valid interval"),
            Interval::new(2, 7).expect("expected valid interval"),
            Interval::new(3, 5).expect("expected valid interval"),
        ]
    );
}