Files
dsh-long-skin/src/client/logic.test.ts
kingOfSoySauce f24aa0841d Initial release
2026-08-14 22:30:15 +08:00

68 lines
2.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
frameForEffort,
indicatorLabel,
liangRankForFrame,
nearestEffortIndex,
paletteForFrame,
portraitBlendForLevel,
selectedEffortIndex,
} from "./logic";
const efforts = [
{ id: "off", name: "Off" },
{ id: "high", name: "High" },
{ id: "max", name: "Max" },
];
describe("滑动变祖 effort mapping", () => {
it("spreads dynamic effort metadata across all 241 preview frames", () => {
expect(frameForEffort(0, 3)).toBe(0);
expect(frameForEffort(1, 3)).toBe(120);
expect(frameForEffort(2, 3)).toBe(240);
expect(nearestEffortIndex(119, efforts)).toBe(1);
expect(nearestEffortIndex(181, efforts)).toBe(2);
});
it("recomputes anchors for two-level and five-level models", () => {
expect([0, 1].map((index) => frameForEffort(index, 2))).toEqual([0, 240]);
expect([0, 1, 2, 3, 4].map((index) => frameForEffort(index, 5))).toEqual([
0, 60, 120, 180, 240,
]);
});
it("uses the provider default only when the current selection omits an effort", () => {
expect(selectedEffortIndex(efforts, "max", "high")).toBe(2);
expect(selectedEffortIndex(efforts, undefined, "high")).toBe(1);
expect(selectedEffortIndex(efforts)).toBe(-1);
});
it("carries the original light-to-charcoal-to-gold stage mapping", () => {
expect(paletteForFrame(0)).toMatchObject({ stage: 0, strength: 0 });
expect(paletteForFrame(120)).toMatchObject({ stage: 0, level: 15 });
expect(paletteForFrame(191)).toMatchObject({ stage: 0 });
expect(paletteForFrame(192)).toMatchObject({ stage: 5 });
expect(paletteForFrame(239)).toMatchObject({ stage: 5 });
expect(paletteForFrame(240)).toMatchObject({ stage: 5, strength: 1 });
expect(paletteForFrame(0).accent).toBe("rgb(65 118 230)");
expect(paletteForFrame(240).accent).toBe("rgb(193 154 73)");
});
it("finds the nearest available portrait keys", () => {
const anchors = [0, 6, 12, 15, 18, 24, 27, 30];
expect(portraitBlendForLevel(0, anchors)).toEqual({ lowerIndex: 0, upperIndex: 0, mix: 0 });
expect(portraitBlendForLevel(13.5, anchors)).toEqual({ lowerIndex: 2, upperIndex: 3, mix: 0.5 });
expect(portraitBlendForLevel(31, anchors)).toEqual({ lowerIndex: 7, upperIndex: 7, mix: 0 });
});
it("labels continuous Liang ranks independently from model efforts", () => {
expect(liangRankForFrame(0)).toBe("小难梁");
expect(liangRankForFrame(48)).toBe("牢梁");
expect(liangRankForFrame(191)).toBe("梁圣");
expect(liangRankForFrame(192)).toBe("梁神");
expect(liangRankForFrame(240)).toBe("梁祖");
expect(indicatorLabel(240, efforts)).toBe("梁祖 · Max");
expect(indicatorLabel(119, efforts)).toBe("梁子 · High");
});
});