#include #include "secsgem/gem/module_state.hpp" #include "secsgem/gem/store/modules.hpp" using namespace secsgem::gem; // ---- FSM --------------------------------------------------------------- TEST_CASE("ModuleStateMachine: happy path lifecycle") { ModuleStateMachine fsm; CHECK(fsm.state() == ModuleState::NotExecuting); CHECK(fsm.on_event(ModuleEvent::StartGeneral)); CHECK(fsm.state() == ModuleState::GeneralExecuting); CHECK(fsm.on_event(ModuleEvent::StartStep)); CHECK(fsm.state() == ModuleState::StepExecuting); CHECK(fsm.on_event(ModuleEvent::CompleteStep)); CHECK(fsm.state() == ModuleState::StepCompleted); } TEST_CASE("ModuleStateMachine: Reset returns to NotExecuting from any state") { for (auto start : {ModuleState::GeneralExecuting, ModuleState::StepExecuting, ModuleState::StepCompleted}) { ModuleStateMachine fsm; // Drive into `start`. if (start != ModuleState::NotExecuting) fsm.on_event(ModuleEvent::StartGeneral); if (start == ModuleState::StepExecuting || start == ModuleState::StepCompleted) fsm.on_event(ModuleEvent::StartStep); if (start == ModuleState::StepCompleted) fsm.on_event(ModuleEvent::CompleteStep); REQUIRE(fsm.state() == start); CHECK(fsm.on_event(ModuleEvent::Reset)); CHECK(fsm.state() == ModuleState::NotExecuting); } } TEST_CASE("ModuleStateMachine: Abort lands in StepCompleted") { ModuleStateMachine fsm; fsm.on_event(ModuleEvent::StartGeneral); fsm.on_event(ModuleEvent::StartStep); CHECK(fsm.on_event(ModuleEvent::Abort)); CHECK(fsm.state() == ModuleState::StepCompleted); } // ---- Store ------------------------------------------------------------- TEST_CASE("ModuleStore: create + dedup + bind + fire") { ModuleStore s; CHECK(s.create("MOD-A")); CHECK_FALSE(s.create("MOD-A")); CHECK(s.bind("MOD-A", "W-1", "STEP-1")); CHECK(s.get("MOD-A")->current_substid == "W-1"); CHECK(s.get("MOD-A")->recipe_step == "STEP-1"); CHECK(s.fire("MOD-A", ModuleEvent::StartGeneral)); CHECK(s.get("MOD-A")->fsm->state() == ModuleState::GeneralExecuting); } TEST_CASE("ModuleStore: state-change handler observes per-module") { ModuleStore s; std::vector> log; s.set_state_change_handler( [&](const std::string& id, ModuleState, ModuleState to, ModuleEvent) { log.emplace_back(id, to); }); s.create("M1"); s.create("M2"); s.fire("M1", ModuleEvent::StartGeneral); s.fire("M2", ModuleEvent::StartGeneral); s.fire("M1", ModuleEvent::StartStep); REQUIRE(log.size() == 3); CHECK(log[0].first == "M1"); CHECK(log[2].first == "M1"); CHECK(log[2].second == ModuleState::StepExecuting); }