/** * @file file-manager.test.js * @description server/lib/file-manager.js: the files a file manager's Copy * put on the OS clipboard (Windows GetFileDropList, macOS NSPasteboard, Linux * text/uri-list / gnome-copied-files) and the ones selected in it — what a * drag carries (Windows Shell.Application, macOS Finder) — kept only when * they exist here, with their sizes; a missing reader is no files. * @author Nguyễn Ngọc Trí Vĩ */ const { describe, it, before, after, afterEach } = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); const { clipboardFiles, selectedFiles, uriListPaths, __setExecImpl, } = require("../lib/file-manager"); const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "fm-files-")); const big = path.join(TMP, "big file.mp4"); const dir = path.join(TMP, "folder"); before(() => { fs.writeFileSync(big, Buffer.alloc(1234)); fs.mkdirSync(dir); }); after(() => fs.rmSync(TMP, { recursive: true, force: true })); afterEach(() => __setExecImpl(async () => "")); describe("uriListPaths", () => { it("decodes file URIs and skips a gnome list's verb, comments and other hosts", () => { assert.deepEqual( uriListPaths("copy\nfile:///home/u/a%20b.png\r\n# c\nfile://other/x\nhttps://x/y\n"), ["/home/u/a b.png"] ); }); }); describe("clipboardFiles", () => { it("reads Windows' file drop list with powershell -Sta", async () => { let seen; __setExecImpl(async (cmd, args) => { seen = [cmd, args]; return `${big}\r\n${dir}\r\n${path.join(TMP, "gone.txt")}\r\n`; }); assert.deepEqual(await clipboardFiles("win32"), [ { path: big, size: 1234, dir: false }, { path: dir, size: null, dir: true }, ]); assert.equal(seen[0], "powershell"); assert.ok(seen[1].includes("-Sta")); assert.match(seen[1].at(-1), /GetFileDropList/); }); it("reads macOS file URLs through JXA", async () => { let seen; __setExecImpl(async (cmd, args) => { seen = [cmd, args]; return `${big}\n`; }); assert.deepEqual(await clipboardFiles("darwin"), [{ path: big, size: 1234, dir: false }]); assert.equal(seen[0], "osascript"); assert.deepEqual(seen[1].slice(0, 2), ["-l", "JavaScript"]); }); it("reads Linux text/uri-list with the desktop's display", async () => { const saved = process.env.DISPLAY; process.env.DISPLAY = ":0"; try { const calls = []; __setExecImpl(async (cmd, args, env) => { calls.push([cmd, args.join(" "), env.DISPLAY]); return cmd === "xclip" ? `file://${encodeURI(big)}\n` : ""; }); assert.deepEqual(await clipboardFiles("linux"), [{ path: big, size: 1234, dir: false }]); assert.deepEqual(calls.at(-1), ["xclip", "-selection clipboard -t text/uri-list -o", ":0"]); } finally { if (saved === undefined) delete process.env.DISPLAY; else process.env.DISPLAY = saved; } }); it("answers no files when the reader is missing or prints relative paths", async () => { __setExecImpl(async () => ""); assert.deepEqual(await clipboardFiles("win32"), []); __setExecImpl(async () => "relative/x.txt\n"); assert.deepEqual(await clipboardFiles("darwin"), []); }); it("reads Explorer's selection (and the desktop's) for a drop, once per path", async () => { let seen; __setExecImpl(async (cmd, args) => { seen = [cmd, args]; return `${big}\r\n${big}\r\n`; }); assert.deepEqual(await selectedFiles("win32"), [{ path: big, size: 1234, dir: false }]); assert.equal(seen[0], "powershell"); assert.match(seen[1].at(-1), /Shell\.Application[\s\S]*SelectedItems[\s\S]*FindWindowSW/); }); it("reads Finder's selection on macOS, a folder with its trailing slash", async () => { let seen; __setExecImpl(async (cmd, args) => { seen = [cmd, args]; return `${dir}/\n`; }); assert.deepEqual(await selectedFiles("darwin"), [{ path: `${dir}/`, size: null, dir: true }]); assert.equal(seen[0], "osascript"); assert.ok(seen[1].includes("repeat with a in (selection as alias list)")); }); it("has no selection to read on Linux", async () => { let called = false; __setExecImpl(async () => { called = true; return big; }); assert.deepEqual(await selectedFiles("linux"), []); assert.equal(called, false); }); });