1
5import { describe, expect, it } from "vitest";
6import {
7 ALLOWED_TRANSITIONS,
8 assertTransition,
9 isValidTransition,
10 InvalidTransitionError
11} from "../status.js";
12import type { FileStatus } from "@prisma/client";
13
14const ALL: FileStatus[] = ["UPLOADING", "SCANNING", "READY", "VIRUS_DETECTED", "FAILED"];
15
16describe("files status machine (TASK-0102 §2)", () => {
17 it("allows exactly the spec transitions", () => {
18 expect(ALLOWED_TRANSITIONS.UPLOADING).toEqual(["SCANNING"]);
19 expect(ALLOWED_TRANSITIONS.SCANNING).toEqual(["READY", "VIRUS_DETECTED", "FAILED"]);
20 expect(ALLOWED_TRANSITIONS.READY).toEqual(["FAILED"]);
21 expect(ALLOWED_TRANSITIONS.VIRUS_DETECTED).toEqual([]);
22 expect(ALLOWED_TRANSITIONS.FAILED).toEqual([]);
23 });
24
25 it("isValidTransition matches the table for every (from,to) pair", () => {
26 for (const from of ALL) {
27 for (const to of ALL) {
28 expect(isValidTransition(from, to)).toBe(ALLOWED_TRANSITIONS[from].includes(to));
29 }
30 }
31 });
32
33 it("assertTransition passes on legal transitions", () => {
34 expect(() => assertTransition("UPLOADING", "SCANNING")).not.toThrow();
35 expect(() => assertTransition("SCANNING", "READY")).not.toThrow();
36 expect(() => assertTransition("SCANNING", "VIRUS_DETECTED")).not.toThrow();
37 expect(() => assertTransition("SCANNING", "FAILED")).not.toThrow();
38 expect(() => assertTransition("READY", "FAILED")).not.toThrow();
39 });
40
41 it("assertTransition throws InvalidTransitionError on every illegal transition", () => {
42 for (const from of ALL) {
43 for (const to of ALL) {
44 if (ALLOWED_TRANSITIONS[from].includes(to)) continue;
45 expect(() => assertTransition(from, to), `${from} → ${to}`).toThrow(
46 InvalidTransitionError
47 );
48 expect(() => assertTransition(from, to), `${from} → ${to}`).toThrow(
49 new RegExp(`${from} → ${to}`)
50 );
51 }
52 }
53 });
54
55 it("terminal states have no outgoing transitions", () => {
56 for (const t of ["VIRUS_DETECTED", "FAILED"] as FileStatus[]) {
57 for (const to of ALL) {
58 expect(isValidTransition(t, to)).toBe(false);
59 }
60 }
61 });
62
63 it("READY is terminal for the pipeline (only a later re-scan → FAILED)", () => {
64 expect(isValidTransition("READY", "READY")).toBe(false);
65 expect(isValidTransition("READY", "SCANNING")).toBe(false);
66 expect(isValidTransition("READY", "VIRUS_DETECTED")).toBe(false);
67 expect(isValidTransition("READY", "FAILED")).toBe(true);
68 });
69});
70