import { describe, expect, it } from "vitest";
import {
countConsecutiveProblemDays,
judgeEscalation,
judgeEscalationLevel,
type ScheduleDayResult,
} from "@/lib/judge";
/** 読みやすさのための組み立てヘルパー。"1" = 問題あり / "0" = 問題なし */
function days(pattern: string): ScheduleDayResult[] {
return pattern.split("").map((c, i) => ({
date: `2026-08-${String(i + 1).padStart(2, "0")}`,
isProblem: c === "1",
}));
}
describe("countConsecutiveProblemDays", () => {
it("直近から遡って連続数を数える", () => {
expect(countConsecutiveProblemDays(days("1"))).toBe(1);
expect(countConsecutiveProblemDays(days("11"))).toBe(2);
expect(countConsecutiveProblemDays(days("111"))).toBe(3);
expect(countConsecutiveProblemDays(days("11111"))).toBe(5);
});
it("最新日が問題なしなら0", () => {
expect(countConsecutiveProblemDays(days("1110"))).toBe(0);
expect(countConsecutiveProblemDays(days("0000"))).toBe(0);
});
it("途中で問題なしの日があれば、そこで連続は途切れる", () => {
expect(countConsecutiveProblemDays(days("11011"))).toBe(2);
expect(countConsecutiveProblemDays(days("10111"))).toBe(3);
});
it("空配列は0", () => {
expect(countConsecutiveProblemDays([])).toBe(0);
});
});
describe("judgeEscalationLevel", () => {
const table: Array<{ name: string; consecutive: number; level: string | null }> = [
{ name: "問題なし", consecutive: 0, level: null },
{ name: "初回の問題", consecutive: 1, level: "L1" },
{ name: "2日連続", consecutive: 2, level: "L2" },
{ name: "3日連続", consecutive: 3, level: "L3" },
{ name: "5日連続(長期化してもL3のまま)", consecutive: 5, level: "L3" },
];
it.each(table)("$name: $consecutive日 → $level", ({ consecutive, level }) => {
expect(judgeEscalationLevel(consecutive)).toBe(level);
});
});
describe("judgeEscalation — スケジュール存在日ベースの連続 ★最重要★", () => {
it("スケジュール非存在日を挟んでも連続は途切れない", () => {
// 月水金スケジュールの施設。8/3(月)・8/5(水)・8/7(金)に清掃予定があり、いずれも失敗。
// カレンダー上は5日間だが、スケジュール存在日の連続は3日なのでL3。
//
// ★この関数には「スケジュール存在日だけ」を渡すこと★
// 火・木は清掃予定がないため、そもそも配列に含めない。
const scheduleDays: ScheduleDayResult[] = [
{ date: "2026-08-03", isProblem: true }, // 月
{ date: "2026-08-05", isProblem: true }, // 水
{ date: "2026-08-07", isProblem: true }, // 金
];
const result = judgeEscalation(scheduleDays);
expect(result.consecutiveDays).toBe(3);
expect(result.level).toBe("L3");
});
it("カレンダー日で数えると誤ってL1になることを確認(アンチパターンの記録)", () => {
// もし火・木を「問題なし」として配列に含めてしまうと、連続が途切れて L1 になる。
// データ取得側でスケジュール存在日に絞り込むのを忘れるとこうなる。
const wrong: ScheduleDayResult[] = [
{ date: "2026-08-03", isProblem: true },
{ date: "2026-08-04", isProblem: false }, // ← 本来含めてはいけない
{ date: "2026-08-05", isProblem: true },
{ date: "2026-08-06", isProblem: false }, // ← 本来含めてはいけない
{ date: "2026-08-07", isProblem: true },
];
expect(judgeEscalation(wrong).level).toBe("L1");
});
it("初回の出発失敗はL1", () => {
expect(judgeEscalation(days("1")).level).toBe("L1");
});
it("2日連続△以下はL2", () => {
expect(judgeEscalation(days("11")).level).toBe("L2");
});
it("問題が解消した施設はレベルなし", () => {
expect(judgeEscalation(days("1110")).level).toBeNull();
});
});