import { describe, expect, it } from "vitest"; import { parseIrcLine, parseIrcPrefix, sanitizeIrcOutboundText, sanitizeIrcTarget, splitIrcText, } from "./protocol.js"; describe("irc protocol", () => { it("parses PRIVMSG lines with prefix and trailing", () => { const parsed = parseIrcLine(":alice!u@host PRIVMSG #room :hello world"); expect(parsed).toEqual({ raw: ":alice!u@host PRIVMSG #room :hello world", prefix: "alice!u@host", command: "PRIVMSG", params: ["#room"], trailing: "hello world", }); expect(parseIrcPrefix(parsed?.prefix)).toEqual({ nick: "alice", user: "u", host: "host", }); }); it("sanitizes outbound text to prevent command injection", () => { expect(sanitizeIrcOutboundText("hello\\r\\nJOIN #oops")).toBe("hello JOIN #oops"); expect(sanitizeIrcOutboundText("\\u0001test\\u0000")).toBe("test"); }); it("validates targets and rejects control characters", () => { expect(sanitizeIrcTarget("#openclaw")).toBe("#openclaw"); expect(() => sanitizeIrcTarget("#bad\\nPING")).toThrow(/Invalid IRC target/); expect(() => sanitizeIrcTarget(" user")).toThrow(/Invalid IRC target/); }); it("splits long text on boundaries", () => { const chunks = splitIrcText("a ".repeat(300), 120); expect(chunks.length).toBeGreaterThan(2); expect( chunks .map((chunk, index) => ({ index, length: chunk.length })) .filter((chunk) => chunk.length > 120), ).toEqual([]); }); });