aerocontext-core 0.4.2

Provider-neutral aeronautical-context model and the pluggable ContextProvider contract
Documentation
#![allow(clippy::expect_used, clippy::panic)]

use super::*;

fn wp(ident: &str, lat: f64, lon: f64) -> RouteWaypoint {
    RouteWaypoint::new(GeoPoint { lat, lon }).with_ident(Some(ident.to_owned()))
}

fn ewr_to_aao() -> RouteBriefingRequest {
    // KEWR → PSB → KAAO, roughly the ForeFlight sample's endpoints.
    RouteBriefingRequest::new(
        vec![
            wp("KEWR", 40.6925, -74.1687),
            wp("PSB", 40.9163, -77.9927),
            wp("KAAO", 37.7461, -97.2211),
        ],
        25.0,
    )
}

#[test]
fn idents_and_distance_track_the_route() {
    let req = ewr_to_aao();
    assert_eq!(req.idents(), vec!["KEWR", "PSB", "KAAO"]);
    // EWR→ICT is ~1080 NM great circle; allow slack.
    let total = req.total_distance_nm();
    assert!((950.0..1200.0).contains(&total), "total was {total}");
}

#[test]
fn short_route_is_one_padded_box_covering_both_ends() {
    let req = RouteBriefingRequest::new(vec![wp("A", 40.0, -75.0), wp("B", 40.5, -75.5)], 25.0);
    let boxes = req.segment_bboxes(500.0);
    assert_eq!(boxes.len(), 1);
    let Area::BoundingBox {
        south_west,
        north_east,
    } = &boxes[0]
    else {
        panic!("expected a bounding box");
    };
    // Both endpoints inside, with the corridor pad beyond them.
    assert!(south_west.lat < 40.0 && north_east.lat > 40.5);
    assert!(south_west.lon < -75.5 && north_east.lon > -75.0);
    assert_eq!(
        boxes[0].contains(GeoPoint {
            lat: 40.25,
            lon: -75.25
        }),
        Some(true)
    );
}

#[test]
fn long_route_is_chunked_into_several_boxes() {
    let req = ewr_to_aao();
    let coarse = req.segment_bboxes(2000.0);
    let fine = req.segment_bboxes(300.0);
    assert_eq!(coarse.len(), 1, "a span above the route length is one box");
    assert!(
        fine.len() >= 3,
        "a ~1080 NM route at 300 NM segments needs several boxes, got {}",
        fine.len()
    );
}

#[test]
fn every_route_waypoint_lands_in_some_segment_box() {
    let req = ewr_to_aao();
    let boxes = req.segment_bboxes(300.0);
    for w in &req.waypoints {
        assert!(
            boxes.iter().any(|b| b.contains(w.position) == Some(true)),
            "{:?} fell outside every box",
            w.ident
        );
    }
}