// SPDX-License-Identifier: AGPL-3.0-or-later import { test } from "node:test"; import { strict as assert } from "node:assert"; import { StateMachine } from "../../ui/system/core/state_machine.js"; test("StateMachine — requires initial state", () => { assert.throws(() => new StateMachine(), /initial/); assert.throws(() => new StateMachine({}), /initial/); }); test("StateMachine — initial state set", () => { const sm = new StateMachine({ initial: "a" }); assert.equal(sm.current, "a"); assert.equal(sm.previous, null); }); test("StateMachine — transition updates current + previous", () => { const sm = new StateMachine({ initial: "a" }); sm.transition("b"); assert.equal(sm.current, "b"); assert.equal(sm.previous, "a"); sm.transition("c"); assert.equal(sm.current, "c"); assert.equal(sm.previous, "b"); }); test("StateMachine — without guards, any transition is allowed", () => { const sm = new StateMachine({ initial: "a" }); // Self-transition allowed too. assert.doesNotThrow(() => sm.transition("a")); assert.doesNotThrow(() => sm.transition("anything")); }); test("StateMachine — with guards, valid transitions pass", () => { const sm = new StateMachine({ initial: "ambient", transitions: { ambient: ["dock"], dock: ["ambient", "browser"], browser: ["dock"], }, }); assert.doesNotThrow(() => sm.transition("dock")); assert.doesNotThrow(() => sm.transition("browser")); assert.doesNotThrow(() => sm.transition("dock")); assert.doesNotThrow(() => sm.transition("ambient")); }); test("StateMachine — with guards, invalid transition throws", () => { const sm = new StateMachine({ initial: "ambient", transitions: { ambient: ["dock"], // can ONLY go to dock dock: ["ambient"], }, }); assert.throws(() => sm.transition("browser"), /invalid transition/i); // After a failed transition, state is unchanged. assert.equal(sm.current, "ambient"); assert.equal(sm.previous, null); }); test("StateMachine — guards default to empty for undefined source state", () => { const sm = new StateMachine({ initial: "a", transitions: { a: ["b"] }, // no entry for "b" }); sm.transition("b"); // From "b", nothing is reachable. assert.throws(() => sm.transition("a"), /invalid/i); }); test("StateMachine.is() — checks current", () => { const sm = new StateMachine({ initial: "a" }); assert.equal(sm.is("a"), true); assert.equal(sm.is("b"), false); sm.transition("b"); assert.equal(sm.is("a"), false); assert.equal(sm.is("b"), true); });