import { test, expect } from "bun:test"; import { encodeCommand, parseReply, concat } from "../src/resp.ts"; const enc = new TextEncoder(); const dec = new TextDecoder(); test("encodeCommand produces a RESP array of bulk strings", () => { const bytes = encodeCommand(["PUBLISH", "order:created", '{"id":7}']); expect(dec.decode(bytes)).toBe( '*3\r\n$7\r\nPUBLISH\r\n$13\r\norder:created\r\n$8\r\n{"id":7}\r\n', ); }); test("parseReply reads a Redis message push", () => { const wire = enc.encode("*3\r\n$7\r\nmessage\r\n$5\r\ntopic\r\n$5\r\nhello\r\n"); const r = parseReply(wire); expect(r).not.toBeNull(); expect(r!.value).toEqual(["message", "topic", "hello"]); expect(r!.next).toBe(wire.length); }); test("parseReply reads a pmessage push (pattern, channel, payload)", () => { const wire = enc.encode( "*4\r\n$8\r\npmessage\r\n$6\r\norder:*\r\n$13\r\norder:created\r\n$2\r\n{}\r\n".replace( "$6\r\norder:*", "$7\r\norder:*", ), ); const r = parseReply(wire)!; expect(r.value).toEqual(["pmessage", "order:*", "order:created", "{}"]); }); test("parseReply returns null for an incomplete buffer, then completes", () => { const full = enc.encode("*1\r\n$5\r\nhello\r\n"); // Half the bytes → incomplete. expect(parseReply(full.subarray(0, 8))).toBeNull(); // Full → parses. expect(parseReply(full)!.value).toEqual(["hello"]); }); test("parseReply handles integers and simple strings (subscribe confirmations)", () => { const sub = enc.encode("*3\r\n$9\r\nsubscribe\r\n$5\r\ntopic\r\n:1\r\n"); expect(parseReply(sub)!.value).toEqual(["subscribe", "topic", 1]); const ok = enc.encode("+OK\r\n"); expect(parseReply(ok)!.value).toBe("OK"); }); test("concat joins byte chunks in order", () => { const joined = concat([enc.encode("ab"), enc.encode("cd")]); expect(dec.decode(joined)).toBe("abcd"); });