/* * Veskslop — unit tests for the pure communication logic. * * Usage: pnpm test:comm */ import assert from "node:assert/strict"; import { MessageLog, TRUSTED_LOG_LIMIT, UNTRUSTED_LOG_LIMIT, assembleContext, compareSnowflakes, extractMentionIds, formatContextLine, hasTier, isTrusted, parseCommand, parsePoll, parseTier, redactSecrets, stripMentions, toCachedMessage, type CachedMessage, type PuppetMessage } from "./communication.js"; import { PACING, planSend } from "./pacing.js"; function cached(id: number, content = `m${id}`): CachedMessage { return { id: String(id), authorId: "1", authorName: "a", content, timestamp: "" }; } function entry(id: number, trusted: boolean): PuppetMessage { return { id: String(id), channelId: "c", authorId: trusted ? "owner" : "stranger", authorName: "tester", content: `msg ${id}`, timestamp: new Date().toISOString(), trusted }; } // ring buffer limits { const log = new MessageLog(); for (let i = 0; i < 150; i++) log.add(entry(i, true)); assert.equal(log.trusted.length, TRUSTED_LOG_LIMIT); assert.equal(log.trusted[0].id, "50"); for (let i = 0; i < 40; i++) log.add(entry(i, false)); assert.equal(log.untrusted.length, UNTRUSTED_LOG_LIMIT); assert.equal(log.untrusted[0].id, "10"); } // mentions { const ids = extractMentionIds("<@!42> hi <@7>", [{ id: "9" }]); assert.deepEqual([...ids].sort(), ["42", "7", "9"]); assert.equal(stripMentions("<@!42> whitelist list", new Set(["42"])), "whitelist list"); assert.equal(stripMentions("<@42> <@99> hey", new Set(["42"])), "<@99> hey"); } // commands { assert.deepEqual(parseCommand(" WHITELIST add <@123> "), { name: "whitelist", args: ["add", "<@123>"] }); assert.deepEqual(parseCommand("whitelist list"), { name: "whitelist", args: ["list"] }); assert.equal(parseCommand(" "), undefined); } // trust { assert.equal(isTrusted("owner", "owner", []), true); assert.equal(isTrusted("trusted", "owner", ["trusted"]), true); assert.equal(isTrusted("stranger", "owner", ["trusted"]), false); } // pacing: fast first send in a burst, 500-2800 ms afterwards, variable reset { for (let i = 0; i < 200; i++) { const first = planSend(1_000_000, 0); assert.ok( first.delay >= PACING.firstMinMs && first.delay <= PACING.firstMaxMs, `first delay out of range: ${first.delay}` ); assert.ok( first.burstUntil - 1_000_000 >= PACING.idleMinMs && first.burstUntil - 1_000_000 <= PACING.idleMaxMs, `burst window out of range: ${first.burstUntil}` ); const followUp = planSend(1_000_000, 1_001_000); assert.ok( followUp.delay >= PACING.burstMinMs && followUp.delay <= PACING.burstMaxMs, `burst delay out of range: ${followUp.delay}` ); // A fresh burst after the window expired is fast again. const resumed = planSend(2_000_000, 1_000_000); assert.ok( resumed.delay >= PACING.firstMinMs && resumed.delay <= PACING.firstMaxMs, `resumed delay out of range: ${resumed.delay}` ); } } // context assembly { const messages = Array.from({ length: 20 }, (_, i) => cached(100 + i)); const byCount = assembleContext(messages, { maxMessages: 15, maxChars: 1_000_000 }); assert.equal(byCount.messages.length, 15); assert.equal(byCount.messages[0].id, "105"); assert.equal(byCount.truncated, true); const long = Array.from({ length: 10 }, (_, i) => cached(i, "y".repeat(50))); const byChars = assembleContext(long, { maxMessages: 15, maxChars: 120 }); assert.equal(byChars.messages.length, 2); assert.ok(byChars.chars <= 120); assert.equal(byChars.truncated, true); // the newest message is always kept, even when it exceeds the budget const single = assembleContext([cached(1, "z".repeat(5000))], { maxChars: 100 }); assert.equal(single.messages.length, 1); // the trigger message can be excluded const excluded = assembleContext([cached(1), cached(2), cached(3)], { excludeId: "3" }); assert.deepEqual( excluded.messages.map(m => m.id), ["1", "2"] ); } // context formatting and snowflake compare { const withFile: CachedMessage = { ...cached(1, "look"), attachments: ["clip.mp4"] }; assert.equal(formatContextLine(withFile), "a: look [file: clip.mp4]"); assert.equal(formatContextLine({ ...cached(2, ""), attachments: ["a.png"] }), "a: [file: a.png]"); assert.equal(compareSnowflakes("10", "9"), 1); assert.equal(compareSnowflakes("9", "10"), -1); assert.equal(compareSnowflakes("5", "5"), 0); } // raw message conversion keeps file names only { const converted = toCachedMessage({ id: 5, author: { id: 7, username: "u" }, content: "see this", timestamp: "t", attachments: [{ filename: "a.png" }, { filename: "b.mp4" }] }); assert.deepEqual(converted, { id: "5", authorId: "7", authorName: "u", content: "see this", timestamp: "t", attachments: ["a.png", "b.mp4"] }); } // timestamps in context lines { const withTime: CachedMessage = { ...cached(1, "hi"), timestamp: "2026-09-11T14:03:00.000Z" }; assert.match(formatContextLine(withTime), /^\[\d\d:\d\d\] a: hi$/); assert.equal(formatContextLine(cached(2, "no time")), "a: no time"); } // secret redaction { const fakeToken = `${"x".repeat(24)}.${"abcde"}.${"y".repeat(25)}`; assert.equal(redactSecrets(`token ${fakeToken} here`), "token [redacted] here"); assert.equal(redactSecrets("mfa." + "z".repeat(30)), "[redacted]"); assert.equal(redactSecrets("nothing to hide"), "nothing to hide"); } // trust tiers { assert.equal(hasTier("admin", "admin"), true); assert.equal(hasTier("trusted", "admin"), false); assert.equal(hasTier("trusted", "user"), true); assert.equal(hasTier(undefined, "user"), false); assert.equal(parseTier("trusted"), "trusted"); assert.equal(parseTier("bogus"), undefined); } // log lookup by ID { const log = new MessageLog(); log.add({ ...entry(1, true), context: [] }); assert.equal(log.find("1")?.id, "1"); assert.equal(log.find("nope"), undefined); } // poll parser { assert.deepEqual(parsePoll("Lunch? | Pizza | Sushi"), { question: "Lunch?", options: ["Pizza", "Sushi"] }); assert.deepEqual(parsePoll("Q | A | B | C | D"), { question: "Q", options: ["A", "B", "C", "D"] }); assert.deepEqual(parsePoll('"What country is best" Sweden // Denmark // Madagaskar'), { question: "What country is best", options: ["Sweden", "Denmark", "Madagaskar"] }); // the whitespace guard keeps URLs together assert.deepEqual(parsePoll('"Links?" https://a.example // https://b.example'), { question: "Links?", options: ["https://a.example", "https://b.example"] }); assert.equal(parsePoll("Q | A"), undefined); assert.equal(parsePoll("Q | A | B | C | D | E"), undefined); assert.equal(parsePoll(`Q | ${"x".repeat(100)} | B`), undefined); } console.log("all communication tests passed");