#[cfg(test)]
mod tests {
use statig::blocking::*;
use std::fmt;
type Outcome = statig::Outcome<State>;
#[derive(Clone, Debug)]
enum Event {
A,
B,
C,
D,
}
#[derive(Copy, Clone, Debug)]
enum Action {
Entry,
Exit,
}
#[derive(Debug)]
enum StateWrapper {
Leaf(State),
Super(Superstate),
}
#[derive(Default)]
struct Foo {
pub path: Vec<(StateWrapper, Action)>,
}
#[state_machine(
initial = "State::s11()",
event_identifier = "event",
state(derive(Eq, PartialEq, Debug)),
superstate(derive(Eq, PartialEq, Debug))
)]
impl Foo {
#[state(
superstate = "s1",
entry_action = "enter_s11",
exit_action = "exit_s11"
)]
pub fn s11(&mut self, event: &Event) -> Outcome {
match event {
Event::A => Transition(State::s11()),
Event::B => Transition(State::s12()),
_ => Super,
}
}
#[action]
fn enter_s11(&mut self) {
self.path
.push((StateWrapper::Leaf(State::s11()), Action::Entry));
}
#[action]
fn exit_s11(&mut self) {
self.path
.push((StateWrapper::Leaf(State::s11()), Action::Exit));
}
#[state(
superstate = "s1",
entry_action = "enter_s12",
exit_action = "exit_s12"
)]
pub fn s12(&mut self, event: &Event) -> Outcome {
match event {
Event::C => Transition(State::s211()),
_ => Super,
}
}
#[action]
fn enter_s12(&mut self) {
self.path
.push((StateWrapper::Leaf(State::s12()), Action::Entry));
}
#[action]
fn exit_s12(&mut self) {
self.path
.push((StateWrapper::Leaf(State::s12()), Action::Exit));
}
#[allow(unused)]
#[superstate(superstate = "s", entry_action = "enter_s1", exit_action = "exit_s1")]
pub fn s1(&mut self, event: &Event) -> Outcome {
Super
}
#[action]
fn enter_s1(&mut self) {
self.path
.push((StateWrapper::Super(Superstate::S1 {}), Action::Entry));
}
#[action]
fn exit_s1(&mut self) {
self.path
.push((StateWrapper::Super(Superstate::S1 {}), Action::Exit));
}
#[allow(unused)]
#[state(
superstate = "s21",
entry_action = "enter_s211",
exit_action = "exit_s211"
)]
pub fn s211(&mut self, event: &Event) -> Outcome {
Super
}
#[action]
fn enter_s211(&mut self) {
self.path
.push((StateWrapper::Leaf(State::s211()), Action::Entry));
}
#[action]
fn exit_s211(&mut self) {
self.path
.push((StateWrapper::Leaf(State::s211()), Action::Exit));
}
#[allow(unused)]
#[superstate(
superstate = "s2",
entry_action = "enter_s21",
exit_action = "exit_s21"
)]
pub fn s21(&mut self, event: &Event) -> Outcome {
Super
}
#[action]
fn enter_s21(&mut self) {
self.path
.push((StateWrapper::Super(Superstate::S21 {}), Action::Entry));
}
#[action]
fn exit_s21(&mut self) {
self.path
.push((StateWrapper::Super(Superstate::S21 {}), Action::Exit));
}
#[superstate(superstate = "s", entry_action = "enter_s2", exit_action = "exit_s2")]
pub fn s2(&mut self, event: &Event) -> Outcome {
match event {
Event::D => Transition(State::s11()),
_ => Super,
}
}
#[action]
fn enter_s2(&mut self) {
self.path
.push((StateWrapper::Super(Superstate::S2 {}), Action::Entry));
}
#[action]
fn exit_s2(&mut self) {
self.path
.push((StateWrapper::Super(Superstate::S2 {}), Action::Exit));
}
#[allow(unused)]
#[superstate(entry_action = "enter_s", exit_action = "exit_s")]
pub fn s(&mut self, event: &Event) -> Outcome {
Handled
}
#[action]
fn enter_s(&mut self) {
self.path
.push((StateWrapper::Super(Superstate::S {}), Action::Entry));
}
#[action]
fn exit_s(&mut self) {
self.path
.push((StateWrapper::Super(Superstate::S {}), Action::Exit));
}
}
impl fmt::Debug for Foo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "StatorComponent")
}
}
#[test]
fn test_transition_path() {
let mut state_machine = Foo::default().uninitialized_state_machine().init();
state_machine.handle(&Event::A);
state_machine.handle(&Event::B);
state_machine.handle(&Event::C);
state_machine.handle(&Event::D);
let expected_path: [(StateWrapper, Action); 17] = [
(StateWrapper::Super(Superstate::S {}), Action::Entry),
(StateWrapper::Super(Superstate::S1 {}), Action::Entry),
(StateWrapper::Leaf(State::s11()), Action::Entry),
(StateWrapper::Leaf(State::s11()), Action::Exit),
(StateWrapper::Leaf(State::s11()), Action::Entry),
(StateWrapper::Leaf(State::s11()), Action::Exit),
(StateWrapper::Leaf(State::s12()), Action::Entry),
(StateWrapper::Leaf(State::s12()), Action::Exit),
(StateWrapper::Super(Superstate::S1 {}), Action::Exit),
(StateWrapper::Super(Superstate::S2 {}), Action::Entry),
(StateWrapper::Super(Superstate::S21 {}), Action::Entry),
(StateWrapper::Leaf(State::s211()), Action::Entry),
(StateWrapper::Leaf(State::s211()), Action::Exit),
(StateWrapper::Super(Superstate::S21 {}), Action::Exit),
(StateWrapper::Super(Superstate::S2 {}), Action::Exit),
(StateWrapper::Super(Superstate::S1 {}), Action::Entry),
(StateWrapper::Leaf(State::s11()), Action::Entry),
];
for (i, expected) in expected_path.iter().enumerate() {
use StateWrapper::*;
match (&expected.0, &state_machine.path[i].0) {
(Super(expected), Super(actual)) if actual == expected => continue,
(Leaf(expected), Leaf(actual)) if actual == expected => continue,
_ => panic!(
"Transition path at {} is wrong: Actual: {:?}, Expected: {:?}",
i, &state_machine.path[i], &expected_path[i]
),
};
}
}
}