import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { listIrcAccountIds, resolveDefaultIrcAccountId, resolveIrcAccount } from "./accounts.js"; import type { CoreConfig } from "./types.js"; function asConfig(value: unknown): CoreConfig { return value as CoreConfig; } describe("listIrcAccountIds", () => { it("returns default when no accounts are configured", () => { expect(listIrcAccountIds(asConfig({}))).toEqual(["default"]); }); it("normalizes, deduplicates, and sorts configured account ids", () => { const cfg = asConfig({ channels: { irc: { accounts: { "Ops Team": {}, "ops-team": {}, Work: {}, }, }, }, }); expect(listIrcAccountIds(cfg)).toEqual(["ops-team", "work"]); }); }); describe("resolveDefaultIrcAccountId", () => { it("prefers configured defaultAccount when it matches", () => { const cfg = asConfig({ channels: { irc: { defaultAccount: "Ops Team", accounts: { default: {}, "ops-team": {}, }, }, }, }); expect(resolveDefaultIrcAccountId(cfg)).toBe("ops-team"); }); it("falls back to default when configured defaultAccount is missing", () => { const cfg = asConfig({ channels: { irc: { defaultAccount: "missing", accounts: { default: {}, work: {}, }, }, }, }); expect(resolveDefaultIrcAccountId(cfg)).toBe("default"); }); it("falls back to first sorted account when default is absent", () => { const cfg = asConfig({ channels: { irc: { accounts: { zzz: {}, aaa: {}, }, }, }, }); expect(resolveDefaultIrcAccountId(cfg)).toBe("aaa"); }); }); describe("resolveIrcAccount", () => { it("parses delimited IRC_CHANNELS env values for the default account", () => { const previousChannels = process.env.IRC_CHANNELS; process.env.IRC_CHANNELS = "alpha, beta\ngamma; delta"; try { const account = resolveIrcAccount({ cfg: asConfig({ channels: { irc: { host: "irc.example.com", nick: "claw", }, }, }), }); expect(account.config.channels).toEqual(["alpha", "beta", "gamma", "delta"]); } finally { if (previousChannels === undefined) { delete process.env.IRC_CHANNELS; } else { process.env.IRC_CHANNELS = previousChannels; } } }); it.runIf(process.platform !== "win32")("rejects symlinked password files", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-irc-account-")); const passwordFile = path.join(dir, "password.txt"); const passwordLink = path.join(dir, "password-link.txt"); fs.writeFileSync(passwordFile, "secret-pass\n", "utf8"); fs.symlinkSync(passwordFile, passwordLink); const cfg = asConfig({ channels: { irc: { host: "irc.example.com", nick: "claw", passwordFile: passwordLink, }, }, }); const account = resolveIrcAccount({ cfg }); expect(account.password).toBe(""); expect(account.passwordSource).toBe("none"); fs.rmSync(dir, { recursive: true, force: true }); }); });