import { describe, expect, test } from "bun:test"; import { rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { loadServerConfig, parseRuntimeArgs } from "../../src/server/config"; describe("parseRuntimeArgs", () => { test("无参数返回空对象", () => { const result = parseRuntimeArgs([]); expect(result).toEqual({}); }); test("有参数返回 configPath", () => { const result = parseRuntimeArgs(["config.yaml"]); expect(result).toEqual({ configPath: "config.yaml" }); }); test("--help 输出用法并退出", () => { const logs: string[] = []; let exitCode: number | undefined; const originalLog = console.log; console.log = (...args: unknown[]) => logs.push(args.join(" ")); Object.defineProperty(process, "exit", { configurable: true, value: (code: number) => { exitCode = code; }, writable: true, }); try { parseRuntimeArgs(["--help"]); } finally { Object.defineProperty(process, "exit", { configurable: true, value: process.exit.bind(process), writable: true, }); console.log = originalLog; } expect(exitCode).toBe(0); expect(logs.some((l) => l.includes("用法"))).toBe(true); }); test("-h 输出用法并退出", () => { const logs: string[] = []; let exitCode: number | undefined; const originalLog = console.log; console.log = (...args: unknown[]) => logs.push(args.join(" ")); Object.defineProperty(process, "exit", { configurable: true, value: (code: number) => { exitCode = code; }, writable: true, }); try { parseRuntimeArgs(["-h"]); } finally { Object.defineProperty(process, "exit", { configurable: true, value: process.exit.bind(process), writable: true, }); console.log = originalLog; } expect(exitCode).toBe(0); expect(logs.some((l) => l.includes("用法"))).toBe(true); }); }); describe("loadServerConfig", () => { test("无 configPath 使用默认值", async () => { const config = await loadServerConfig(); expect(config.host).toBe("127.0.0.1"); expect(config.port).toBe(3000); }); test("环境变量 HOST 不影响默认值(无隐式覆盖)", async () => { const prev = process.env["HOST"]; process.env["HOST"] = "0.0.0.0"; try { const config = await loadServerConfig(); expect(config.host).toBe("127.0.0.1"); } finally { if (prev === undefined) { delete process.env["HOST"]; } else { process.env["HOST"] = prev; } } }); test("环境变量 PORT 不影响默认值(无隐式覆盖)", async () => { const prev = process.env["PORT"]; process.env["PORT"] = "8080"; try { const config = await loadServerConfig(); expect(config.port).toBe(3000); } finally { if (prev === undefined) { delete process.env["PORT"]; } else { process.env["PORT"] = prev; } } }); test("YAML 配置文件不存在时报错", async () => { try { await loadServerConfig("/nonexistent/path/config.yaml"); expect.unreachable(); } catch (error) { expect((error as Error).message).toContain("配置文件不存在"); } }); test("新布局 server.listen 加载成功", async () => { const temp = tmpdir(); const yamlPath = join(temp, "test-listen.yaml"); const yamlContent = 'server:\n listen:\n host: "0.0.0.0"\n port: 9999\n'; await writeFile(yamlPath, yamlContent); try { const config = await loadServerConfig(yamlPath); expect(config.host).toBe("0.0.0.0"); expect(config.port).toBe(9999); } finally { await rm(yamlPath, { force: true }); } }); test("旧布局 server.host/server.port 被拒绝", async () => { const temp = tmpdir(); const yamlPath = join(temp, "test-old-layout.yaml"); const yamlContent = 'server:\n host: "0.0.0.0"\n port: 9999\n'; await writeFile(yamlPath, yamlContent); try { await loadServerConfig(yamlPath); expect.unreachable(); } catch (error) { expect((error as Error).message).toContain("未知字段"); } finally { await rm(yamlPath, { force: true }); } }); test("非法端口被拒绝", async () => { const temp = tmpdir(); const yamlPath = join(temp, "test-bad-port.yaml"); const yamlContent = "server:\n listen:\n port: 99999\n"; await writeFile(yamlPath, yamlContent); try { await loadServerConfig(yamlPath); expect.unreachable(); } catch (error) { expect((error as Error).message).toBeTruthy(); } finally { await rm(yamlPath, { force: true }); } }); test("显式变量引用环境变量生效", async () => { const prevHost = process.env["HOST"]; const prevPort = process.env["PORT"]; process.env["HOST"] = "10.0.0.1"; process.env["PORT"] = "4000"; const temp = tmpdir(); const yamlPath = join(temp, "test-env-var.yaml"); const yamlContent = 'server:\n listen:\n host: "${HOST}"\n port: ${PORT}\n'; await writeFile(yamlPath, yamlContent); try { const config = await loadServerConfig(yamlPath); expect(config.host).toBe("10.0.0.1"); expect(config.port).toBe(4000); } finally { await rm(yamlPath, { force: true }); if (prevHost === undefined) delete process.env["HOST"]; else process.env["HOST"] = prevHost; if (prevPort === undefined) delete process.env["PORT"]; else process.env["PORT"] = prevPort; } }); test("变量带默认值生效", async () => { delete process.env["MY_HOST"]; const temp = tmpdir(); const yamlPath = join(temp, "test-default.yaml"); const yamlContent = 'server:\n listen:\n host: "${MY_HOST|0.0.0.0}"\n port: ${MY_PORT|5000}\n'; await writeFile(yamlPath, yamlContent); try { const config = await loadServerConfig(yamlPath); expect(config.host).toBe("0.0.0.0"); expect(config.port).toBe(5000); } finally { await rm(yamlPath, { force: true }); } }); });