import test from "node:test"; import assert from "node:assert/strict"; import * as fs from "fs"; import * as os from "os"; import * as path from "path"; import { ConfigService } from "./service"; import { DEFAULT_CONFIG, RUNTIME_OPTION_REGISTRY } from "./definitions"; import { generateConfigTemplate } from "./template"; function makeTempDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), "subminer-config-test-")); } test("loads defaults when config is missing", () => { const dir = makeTempDir(); const service = new ConfigService(dir); const config = service.getConfig(); assert.equal(config.websocket.port, DEFAULT_CONFIG.websocket.port); assert.equal(config.ankiConnect.behavior.autoUpdateNewCards, true); }); test("parses jsonc and warns/falls back on invalid value", () => { const dir = makeTempDir(); fs.writeFileSync( path.join(dir, "config.jsonc"), `{ // invalid websocket port "websocket": { "port": "bad" } }`, "utf-8", ); const service = new ConfigService(dir); const config = service.getConfig(); assert.equal(config.websocket.port, DEFAULT_CONFIG.websocket.port); assert.ok(service.getWarnings().some((w) => w.path === "websocket.port")); }); test("parses invisible overlay config and new global shortcuts", () => { const dir = makeTempDir(); fs.writeFileSync( path.join(dir, "config.jsonc"), `{ "shortcuts": { "toggleVisibleOverlayGlobal": "Alt+Shift+U", "toggleInvisibleOverlayGlobal": "Alt+Shift+I", "openJimaku": "Ctrl+Alt+J" }, "invisibleOverlay": { "startupVisibility": "hidden" }, "bind_visible_overlay_to_mpv_sub_visibility": false, "youtubeSubgen": { "primarySubLanguages": ["ja", "jpn", "jp"] } }`, "utf-8", ); const service = new ConfigService(dir); const config = service.getConfig(); assert.equal(config.shortcuts.toggleVisibleOverlayGlobal, "Alt+Shift+U"); assert.equal(config.shortcuts.toggleInvisibleOverlayGlobal, "Alt+Shift+I"); assert.equal(config.shortcuts.openJimaku, "Ctrl+Alt+J"); assert.equal(config.invisibleOverlay.startupVisibility, "hidden"); assert.equal(config.bind_visible_overlay_to_mpv_sub_visibility, false); assert.deepEqual(config.youtubeSubgen.primarySubLanguages, ["ja", "jpn", "jp"]); }); test("runtime options registry is centralized", () => { const ids = RUNTIME_OPTION_REGISTRY.map((entry) => entry.id); assert.deepEqual(ids, ["anki.autoUpdateNewCards", "anki.kikuFieldGrouping"]); }); test("template generator includes known keys", () => { const output = generateConfigTemplate(DEFAULT_CONFIG); assert.match(output, /"ankiConnect":/); assert.match(output, /"websocket":/); assert.match(output, /"youtubeSubgen":/); assert.match(output, /auto-generated from src\/config\/definitions.ts/); });