import { describe, it, expect } from "vitest"; import { isUnderRoot, selectionRejection } from "../src/workspacePath"; describe("isUnderRoot", () => { const root = "/a/vscode-cowriting-plugin/sandbox"; it("accepts the root itself and files inside it", () => { expect(isUnderRoot(root, root)).toBe(true); expect(isUnderRoot(`${root}/docs/x.md`, root)).toBe(true); }); it("rejects files outside the root", () => { expect(isUnderRoot("/a/other/x.md", root)).toBe(false); }); it("rejects a SIBLING whose path is a string-prefix of the root's parent (the prefix-collision bug)", () => { // The reported case: EDH root is .../vscode-cowriting-plugin/sandbox, the file // is in the sibling content repo. Plain startsWith on the plugin-repo prefix // would falsely match; the separator boundary must reject it. const pluginRoot = "/a/vscode-cowriting-plugin"; const contentFile = "/a/vscode-cowriting-plugin-content/issues/x.md"; expect(contentFile.startsWith(pluginRoot)).toBe(true); // the latent bug expect(isUnderRoot(contentFile, pluginRoot)).toBe(false); // fixed }); }); describe("selectionRejection", () => { const root = "/ws"; const ok = { hasEditor: true, selectionEmpty: false, scheme: "file", fsPath: "/ws/a.md", root }; it("returns null when everything is valid", () => { expect(selectionRejection(ok)).toBeNull(); }); it("names the missing editor", () => { const msg = selectionRejection({ ...ok, hasEditor: false }); expect(msg).toMatch(/focus a text editor/i); }); it("names the empty selection (only when there IS an editor)", () => { const msg = selectionRejection({ ...ok, selectionEmpty: true }); expect(msg).toMatch(/select some text/i); }); it("names an unsaved/non-file document", () => { const msg = selectionRejection({ ...ok, scheme: "untitled" }); expect(msg).toMatch(/save this document/i); }); it("names an out-of-workspace file (the reported bug — NOT a selection problem)", () => { const msg = selectionRejection({ ...ok, fsPath: "/elsewhere/a.md" }); expect(msg).toMatch(/outside your workspace folder/i); expect(msg).not.toMatch(/select some text/i); }); });