#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use std::sync::atomic::{AtomicBool, Ordering};
use state_machines::state_machine;
static FLIGHT_PLAN_VERIFIED: AtomicBool = AtomicBool::new(false);
state_machine! {
name: FlightDeckController,
initial: Docked,
states: [Docked, ClearanceGranted, Launching, InFlight, Emergency],
events {
request_clearance {
transition: { from: Docked, to: ClearanceGranted }
}
launch {
transition: { from: ClearanceGranted, to: Launching, guards: [flight_plan_verified] }
}
stabilize {
transition: { from: Launching, to: InFlight }
}
abort_mission {
transition: { from: [Docked, ClearanceGranted, Launching, InFlight], to: Emergency }
}
}
}
impl<C, S> FlightDeckController<C, S> {
fn flight_plan_verified(&self, _ctx: &C) -> bool {
FLIGHT_PLAN_VERIFIED.load(Ordering::SeqCst)
}
fn toggle_flight_plan(value: bool) {
FLIGHT_PLAN_VERIFIED.store(value, Ordering::SeqCst);
}
}
#[test]
fn launch_sequence_obeys_guards() {
FlightDeckController::<(), Docked>::toggle_flight_plan(false);
let controller = FlightDeckController::new(());
let controller = controller
.request_clearance()
.expect("clearance request should succeed from Docked");
let err = controller
.launch()
.expect_err("launch should fail without a verified flight plan");
let (controller, guard_err) = err;
assert_eq!(guard_err.guard, "flight_plan_verified");
assert_eq!(guard_err.event, "launch");
FlightDeckController::<(), Docked>::toggle_flight_plan(true);
let controller = controller
.launch()
.expect("launch should succeed once plan verified");
let _controller = controller
.stabilize()
.expect("stabilize should move to InFlight");
}