From 775a0721c00e74ed75bd608410f4406345a53f81 Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Sun, 26 Apr 2026 21:21:02 +0800 Subject: [PATCH] test: enforce scene state machine transitions Made-with: Cursor --- src/scene/SceneStateMachine.ts | 21 +++++++++++++++++++-- tests/kernel/scene-state-machine.test.ts | 28 +++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/scene/SceneStateMachine.ts b/src/scene/SceneStateMachine.ts index e703020..6026014 100644 --- a/src/scene/SceneStateMachine.ts +++ b/src/scene/SceneStateMachine.ts @@ -1,13 +1,30 @@ -export type SceneState = "idle" | "loading"; +export const SCENE_STATES = { + IDLE: "idle", + LOADING: "loading", +} as const; + +export type SceneState = (typeof SCENE_STATES)[keyof typeof SCENE_STATES]; + +const SCENE_STATE_TRANSITIONS: Readonly> = { + [SCENE_STATES.IDLE]: [SCENE_STATES.LOADING], + [SCENE_STATES.LOADING]: [SCENE_STATES.IDLE], +}; export class SceneStateMachine { - private state: SceneState = "idle"; + private state: SceneState = SCENE_STATES.IDLE; getState(): SceneState { return this.state; } transitionTo(nextState: SceneState): void { + const allowedNextStates = SCENE_STATE_TRANSITIONS[this.state]; + if (!allowedNextStates.includes(nextState)) { + throw new Error( + `Invalid scene transition: "${this.state}" -> "${nextState}"` + ); + } + this.state = nextState; } } diff --git a/tests/kernel/scene-state-machine.test.ts b/tests/kernel/scene-state-machine.test.ts index ec97df2..47161bb 100644 --- a/tests/kernel/scene-state-machine.test.ts +++ b/tests/kernel/scene-state-machine.test.ts @@ -2,12 +2,38 @@ import { describe, expect, it } from "vitest"; import { SceneStateMachine } from "@/scene/SceneStateMachine"; describe("SceneStateMachine", () => { - it("starts in idle state and supports transitioning", () => { + it("starts in idle state for every new instance", () => { const machine = new SceneStateMachine(); + const anotherMachine = new SceneStateMachine(); expect(machine.getState()).toBe("idle"); + expect(anotherMachine.getState()).toBe("idle"); + }); + + it("allows legal transitions defined by the state machine", () => { + const machine = new SceneStateMachine(); machine.transitionTo("loading"); expect(machine.getState()).toBe("loading"); + + machine.transitionTo("idle"); + expect(machine.getState()).toBe("idle"); + }); + + it("throws on illegal transitions and keeps current state", () => { + const machine = new SceneStateMachine(); + + expect(() => machine.transitionTo("idle")).toThrowError( + 'Invalid scene transition: "idle" -> "idle"' + ); + expect(machine.getState()).toBe("idle"); + + machine.transitionTo("loading"); + expect(machine.getState()).toBe("loading"); + + expect(() => machine.transitionTo("loading")).toThrowError( + 'Invalid scene transition: "loading" -> "loading"' + ); + expect(machine.getState()).toBe("loading"); }); });