import { describe, expect, test } from "bun:test"; import { quotePosix, quoteWindows, renderCommand, } from "../src/domain/quote.js"; describe("quotePosix", () => { test("wraps a plain path in single quotes", () => { const r = quotePosix("/roms/snes/Chrono Trigger (USA).sfc"); expect(r).toEqual({ ok: true, value: "'/roms/snes/Chrono Trigger (USA).sfc'", }); }); test("escapes embedded single quotes", () => { const r = quotePosix("it's a rom.sfc"); expect(r.ok && r.value).toBe("'it'\\''s a rom.sfc'"); }); test("neutralises shell metacharacters (no expansion possible)", () => { for (const evil of [ "$(rm -rf ~).sfc", "`id`.sfc", "; rm x.sfc", "a && b.sfc", "$HOME.sfc", ]) { const r = quotePosix(evil); expect(r.ok).toBe(true); // Everything stays inside a single-quoted literal. if (r.ok) expect(r.value.startsWith("'") && r.value.endsWith("'")).toBe(true); } }); test("rejects a NUL byte", () => { expect(quotePosix("a\0b").ok).toBe(false); }); }); describe("quoteWindows", () => { test("double-quotes a normal path", () => { const r = quoteWindows("C:\\Games\\Chrono Trigger (USA).sfc"); expect(r).toEqual({ ok: true, value: '"C:\\Games\\Chrono Trigger (USA).sfc"', }); }); test("refuses each cmd.exe metacharacter", () => { for (const bad of [ 'a"b', "a%b", "a!b", "a^b", "a&b", "a|b", "ab", ]) { expect(quoteWindows(bad).ok).toBe(false); } }); test("refuses control characters", () => { expect(quoteWindows("a\nb").ok).toBe(false); expect(quoteWindows("a\tb").ok).toBe(false); }); test("doubles a trailing backslash run so the closing quote is not escaped", () => { const r = quoteWindows("C:\\dir\\"); expect(r.ok && r.value).toBe('"C:\\dir\\\\"'); }); }); describe("renderCommand", () => { test("POSIX: quotes rom + core, inserts exe verbatim", () => { const r = renderCommand( "{exe} -f -L {core} {rom}", { exe: "flatpak run org.libretro.RetroArch", rom: "/roms/Chrono Trigger (USA).sfc", core: "/cores/snes9x_libretro.so", }, "linux", ); expect(r).toEqual({ ok: true, command: "flatpak run org.libretro.RetroArch -f -L '/cores/snes9x_libretro.so' '/roms/Chrono Trigger (USA).sfc'", }); }); test("Windows: a hostile ROM name fails the whole render", () => { const r = renderCommand( "{exe} {rom}", { exe: '"C:\\ra.exe"', rom: "C:\\roms\\a&b.sfc" }, "windows", ); expect(r.ok).toBe(false); }); test("appends trusted extra args verbatim", () => { const r = renderCommand( "{exe} {rom}", { exe: "mgba", rom: "/x.gba" }, "linux", "--scale 4", ); expect(r.ok && r.command).toBe("mgba '/x.gba' --scale 4"); }); test("errors on an unfilled placeholder", () => { const r = renderCommand( "{exe} -L {core} {rom}", { exe: "ra", rom: "/x.sfc" }, "linux", ); expect(r.ok).toBe(false); }); });