Files
flightplanner/crates/core/tests/routing.rs
T
Alexandre 2cb633e99d Initial commit: offline flight planner (Rust, PFPX-class)
Clean-room reproduction of PFPX: route generation + IFPS validation + OFP.
Independent design — official ICAO/EUROCONTROL data only (RAD, FRA points,
IFPUV oracle); no community FPL sources.

Workspace crates: core (routing/discover/rad/navdata/perf/export),
cli, server, rad (Annex parser), gui (Tauri v2 + React + MapLibre).
Route discovery: oracle-in-the-loop repair against Eurocontrol IFPUV.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-21 11:10:35 +02:00

90 lines
3.1 KiB
Rust

//! End-to-end step-3 test: import the fixtures, then route LFPG→EGLL through the
//! hand-made airway network and check the result is sensible.
use std::path::PathBuf;
use flightplanner_core::routing::graph::RouteGraph;
use flightplanner_core::{db, routing};
use rusqlite::Connection;
fn fixtures_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures")
}
fn fixtures_db() -> Connection {
let mut conn = Connection::open_in_memory().unwrap();
db::import_navdata(&mut conn, &fixtures_dir()).unwrap();
conn
}
#[test]
fn routes_lfpg_to_egll_via_airways() {
let conn = fixtures_db();
let route = routing::plan_route(&conn, "LFPG", "EGLL", None).unwrap();
assert!(route.via_airways, "expected an airway route, got {route:?}");
assert_eq!(route.legs.first().unwrap().from, "LFPG");
assert_eq!(route.legs.last().unwrap().to, "EGLL");
// The fixture network forces travel over the T100/U200 airways.
let airways: Vec<&str> = route.legs.iter().map(|l| l.airway.as_str()).collect();
assert!(
airways.iter().any(|a| *a != "DCT"),
"route used no airway: {airways:?}"
);
// Sanity on total distance (direct LFPG-EGLL ≈ 188 nm; via fixtures a bit more).
assert!(
route.total_nm > 150.0 && route.total_nm < 400.0,
"total = {} nm",
route.total_nm
);
}
#[test]
fn unknown_airport_is_reported() {
let conn = fixtures_db();
let err = routing::plan_route(&conn, "LFPG", "ZZZZ", None).unwrap_err();
assert!(err.to_string().contains("ZZZZ"), "{err}");
}
#[test]
fn graph_filters_airways_by_flight_level() {
let conn = fixtures_db();
// Fixtures: T100 (low, FL35..245) links ABEAM/BEACN/CROSS,
// U200 (high, FL245..460) links CROSS/DOVER/ENTRY.
assert_eq!(RouteGraph::build(&conn, None).unwrap().node_count(), 5);
assert_eq!(RouteGraph::build(&conn, Some(200)).unwrap().node_count(), 3); // T100 only
assert_eq!(RouteGraph::build(&conn, Some(300)).unwrap().node_count(), 3); // U200 only
assert_eq!(RouteGraph::build(&conn, Some(500)).unwrap().node_count(), 0); // above both
}
#[test]
fn fra_produces_a_dct_chain() {
let conn = fixtures_db();
let route = routing::fra::plan_fra(&conn, "LFPG", "EGLL", &[], &[], 360, None).unwrap();
assert!(!route.via_airways, "FRA is DCT-based: {route:?}");
assert!(route.legs.iter().all(|l| l.airway == "DCT"), "{route:?}");
assert_eq!(route.legs.first().unwrap().from, "LFPG");
assert_eq!(route.legs.last().unwrap().to, "EGLL");
assert!(
route.total_nm > 150.0 && route.total_nm < 400.0,
"total = {} nm",
route.total_nm
);
}
#[test]
fn connects_departure_via_given_fix() {
let conn = fixtures_db();
// Force LFPG to join the network at CROSS (a SID exit fix, say) rather than
// the nearest airway point.
let route =
routing::plan_route_conn(&conn, "LFPG", "EGLL", None, &["CROSS".to_string()], &[]).unwrap();
assert!(route.via_airways, "{route:?}");
let first = route.legs.first().unwrap();
assert_eq!(first.from, "LFPG");
assert_eq!(first.to, "CROSS", "should connect via the given fix: {route:?}");
}