1import { describe, expect, it } from "vite-plus/test";
2
3import {
4 fileRoutePathSegments,
5 isAudioPreviewFile,
6 isMarkdownPreviewFile,
7 needsWorkspaceFileContents,
8 resolveFileLinkPath,
9 resolveWorkspaceRelativeFilePath,
10} from "./filePath";
11
12describe("resolveFileLinkPath", () => {
13 it.each([
14 ["/home/maria/project", "~/.agents/AGENTS.md", "/home/maria/.agents/AGENTS.md"],
15 ["/Users/maria/project", "~/notes.md", "/Users/maria/notes.md"],
16 ["C:\\Users\\maria\\project", "~\\.agents\\AGENTS.md", "C:\\Users\\maria\\.agents\\AGENTS.md"],
17 ])("expands a home link from %s", (cwd, path, expected) => {
18 expect(resolveFileLinkPath(cwd, path)).toBe(expected);
19 expect(fileRoutePathSegments(expected).join("/")).toBe(expected);
20 });
21
22 it("does not turn an unresolved home into a workspace path", () => {
23 expect(resolveFileLinkPath("/repo", "~/notes.md")).toBeNull();
24 expect(resolveFileLinkPath(null, "~/notes.md")).toBeNull();
25 expect(resolveFileLinkPath("/repo", "../notes.md")).toBeNull();
26 });
27});
28
29describe("resolveWorkspaceRelativeFilePath", () => {
30 it("converts absolute paths inside the workspace", () => {
31 expect(
32 resolveWorkspaceRelativeFilePath("/Users/julius/repo", "/Users/julius/repo/src/main.ts"),
33 ).toBe("src/main.ts");
34 expect(resolveWorkspaceRelativeFilePath("C:\\repo", "c:\\repo\\src\\main.ts")).toBe(
35 "src/main.ts",
36 );
37 });
38
39 it("recognizes home links inside the workspace", () => {
40 expect(resolveWorkspaceRelativeFilePath("/home/maria/project", "~/project/src/main.ts")).toBe(
41 "src/main.ts",
42 );
43 expect(
44 resolveWorkspaceRelativeFilePath("/home/maria/project", "~/.agents/AGENTS.md"),
45 ).toBeNull();
46 });
47
48 it("rejects paths outside the workspace", () => {
49 expect(resolveWorkspaceRelativeFilePath("/repo", "/other/main.ts")).toBeNull();
50 expect(resolveWorkspaceRelativeFilePath("/repo", "../other/main.ts")).toBeNull();
51 expect(resolveWorkspaceRelativeFilePath("/repo", "/repo/../outside.txt")).toBeNull();
52 expect(resolveWorkspaceRelativeFilePath(null, "/repo/main.ts")).toBeNull();
53 });
54});
55
56describe("needsWorkspaceFileContents", () => {
57 it("reads a text file while its metadata is still pending, but not a directory", () => {
58 const input = { relativePath: "package.json", activeMode: "source" } as const;
59 expect(needsWorkspaceFileContents({ ...input, metadataKind: undefined })).toBe(true);
60 expect(needsWorkspaceFileContents({ ...input, metadataKind: "directory" })).toBe(false);
61 });
62});
63
64describe("workspace preview classifiers", () => {
65 it("treat # and ? as literal filename characters", () => {
66 for (const path of ["notes/clip#1.wav", "notes/clip?1.wav", "notes#old/clip.wav"]) {
67 expect(isAudioPreviewFile(path)).toBe(true);
68 }
69 for (const path of ["docs/draft#1.md", "docs/draft?1.md", "docs#old/draft.md"]) {
70 expect(isMarkdownPreviewFile(path)).toBe(true);
71 }
72 });
73});