/**
* `isSupportedModel()` の期待値表(指示書N 1-5)。
*
* ★期待値表を先に確定させ、実装より先にこのテストを書いている(CLAUDE.md §9.4)★
*
* | # | 入力(maker, model) | 期待 | 意図 |
* |----|---------------------------|-------|----------------------------------------|
* | 1 | ("PUDU", "CC1") | true | 唯一の対応機種 |
* | 2 | ("PUDU", "MT1") | false | 既知だが未対応 |
* | 3 | ("Keenon", "C30") | false | 同上 |
* | 4 | ("Keenon", "C40") | false | 同上 |
* | 5 | ("PUDU", "ZZ9") | false | レジストリに無い組み合わせ(完全に未知)|
* | 6 | ("Keenon", "CC1") | false | メーカーだけ違う |
* | 7 | ("PUDU", "T5") | false | メーカーだけ一致して機種が違う |
* | 8 | ("", "") | false | 空文字で落ちない |
* | 9 | ("PUDU", "") | false | 片方だけ空 |
* | 10 | (" PUDU ", " CC1 ") | true | 前後空白を許容する |
* | 11 | ("pudu", "cc1") | true | 大文字小文字を区別しない |
* | 12 | ("PUDU", "CC10") | false | 部分一致していないことの固定 |
*/
import { describe, expect, it } from "vitest";
import { facilities } from "@/lib/fixtures/facilities";
import { isSupportedModel, stripMakerPrefix } from "@/lib/format/robot-model";
describe("isSupportedModel", () => {
it("1. PUDU CC1 は対応済み(唯一の対応機種)", () => {
expect(isSupportedModel("PUDU", "CC1")).toBe(true);
});
it("2. PUDU MT1 は既知だが未対応", () => {
expect(isSupportedModel("PUDU", "MT1")).toBe(false);
});
it("3. Keenon C30 は既知だが未対応", () => {
expect(isSupportedModel("Keenon", "C30")).toBe(false);
});
it("4. Keenon C40 は既知だが未対応", () => {
expect(isSupportedModel("Keenon", "C40")).toBe(false);
});
it("5. レジストリに無い組み合わせ(完全に未知)はfalse", () => {
expect(isSupportedModel("PUDU", "ZZ9")).toBe(false);
});
it("6. メーカーだけ違う場合はfalse(機種名だけで判定していないことの固定)", () => {
expect(isSupportedModel("Keenon", "CC1")).toBe(false);
});
it("7. メーカーだけ一致して機種が違う場合はfalse", () => {
expect(isSupportedModel("PUDU", "T5")).toBe(false);
});
it("8. 空文字同士でも落ちない", () => {
expect(() => isSupportedModel("", "")).not.toThrow();
expect(isSupportedModel("", "")).toBe(false);
});
it("9. 片方だけ空でもfalse", () => {
expect(isSupportedModel("PUDU", "")).toBe(false);
});
it("10. 前後の空白は許容する(trimしてから比較)", () => {
expect(isSupportedModel(" PUDU ", " CC1 ")).toBe(true);
});
it("11. 大文字小文字は区別しない", () => {
expect(isSupportedModel("pudu", "cc1")).toBe(true);
});
it("12. 部分一致していないこと(CC10 はCC1にヒットしない)", () => {
expect(isSupportedModel("PUDU", "CC10")).toBe(false);
});
});
// ★fixtures の全ロボットが対応機種(ROBOT_MODELS の supported)であることの回帰テスト(指示書N 4-3)★
// 入れる/入れないは実装者判断でよいとされているが、
// 「fixturesはP1のスコープ通りPUDU CC1のみで揃っている」という段階3の成果を固定するために入れた。
// 将来MT1/C30/C40をfixturesにも境界ケースとして足したくなったら、このテストごと見直すこと
// (見直しであってバグ修正ではない)。
describe("fixtures の対応機種チェック(指示書N 4-3)", () => {
it("fixtures のロボットはすべて対応機種(ROBOT_MODELS の supported)である — 意図的に未対応機種を足したい場合はこのテストごと見直すこと", () => {
const unsupported = facilities
.flatMap((f) => f.robots)
.filter((r) => !isSupportedModel(r.maker, r.model));
expect(unsupported).toEqual([]);
});
});
describe("stripMakerPrefix(ユーザー指示 2026-10-29: メーカー名を重ねない)", () => {
it.each([
["PUDU", "PUDU CC1", "CC1"],
["PUDU", "pudu CC1", "CC1"],
["PUDU", "CC1", "CC1"],
["PUDU", "PUDUX1", "PUDUX1"],
["PUDU", "PUDU", "PUDU"],
["PUDU", "PUDU ", "PUDU "],
["Keenon", "Keenon C30", "C30"],
["99", "X1", "X1"],
] as const)("maker=%s model=%s → %s", (maker, model, expected) => {
expect(stripMakerPrefix(maker, model)).toBe(expected);
});
});