d6cf5f3d36
- bun workspaces: contract/ (Schemas = source of truth: config raw↔resolved,
domain DTOs, HttpApi contract, API errors) + plugin/ + ui/
- pure domain moved src/{engine,art}→plugin/src/{domain,art}, types now
imported from @rom-manager/contract and @punktfunk/plugin-kit/wire (the
hand-copied wire.ts dies), loggers injected instead of module-global
- ui.* and devEntry dropped from the config shape (standalone server is
gone; stale keys tolerated on decode, dropped by the next save)
- all 48 domain tests ported and green BEFORE any Effect wiring
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
68 lines
1.9 KiB
TypeScript
68 lines
1.9 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import {
|
|
dedupeKey,
|
|
parseTitle,
|
|
pickBestRelease,
|
|
} from "../src/domain/titles.js";
|
|
|
|
describe("parseTitle", () => {
|
|
test("strips No-Intro tags and keeps region + revision metadata", () => {
|
|
const p = parseTitle("Chrono Trigger (USA) (Rev 1) [!]");
|
|
expect(p.displayTitle).toBe("Chrono Trigger");
|
|
expect(p.noIntroName).toBe("Chrono Trigger (USA) (Rev 1) [!]");
|
|
expect(p.region).toBe("USA");
|
|
expect(p.revision).toBe("Rev 1");
|
|
});
|
|
|
|
test("normalises a trailing article", () => {
|
|
expect(parseTitle("Legend of Zelda, The (USA)").displayTitle).toBe(
|
|
"The Legend of Zelda",
|
|
);
|
|
});
|
|
|
|
test("recognises multi-region tags", () => {
|
|
const p = parseTitle("Sonic (USA, Europe)");
|
|
expect(p.regions).toEqual(["USA", "Europe"]);
|
|
expect(p.region).toBe("USA");
|
|
});
|
|
|
|
test("converts underscores and collapses whitespace", () => {
|
|
expect(parseTitle("Super_Mario__World").displayTitle).toBe(
|
|
"Super Mario World",
|
|
);
|
|
});
|
|
|
|
test("a tagless name is its own title", () => {
|
|
const p = parseTitle("Tetris");
|
|
expect(p.displayTitle).toBe("Tetris");
|
|
expect(p.region).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("region dedupe", () => {
|
|
test("groups by base title", () => {
|
|
expect(dedupeKey(parseTitle("Sonic (USA)"))).toBe(
|
|
dedupeKey(parseTitle("Sonic (Europe)")),
|
|
);
|
|
});
|
|
|
|
test("pickBestRelease honors region priority, then shortest name", () => {
|
|
const items = [
|
|
{ parsed: parseTitle("Sonic (Europe)") },
|
|
{ parsed: parseTitle("Sonic (USA)") },
|
|
{ parsed: parseTitle("Sonic (Japan)") },
|
|
];
|
|
const best = pickBestRelease(items, ["USA", "World", "Europe", "Japan"]);
|
|
expect(best.parsed.region).toBe("USA");
|
|
});
|
|
|
|
test("falls back to shortest name when no region matches priority", () => {
|
|
const items = [
|
|
{ parsed: parseTitle("Game (Korea) (Beta)") },
|
|
{ parsed: parseTitle("Game (Korea)") },
|
|
];
|
|
const best = pickBestRelease(items, ["USA"]);
|
|
expect(best.parsed.noIntroName).toBe("Game (Korea)");
|
|
});
|
|
});
|