Skip to content
Source
Sign inSign up
Open History to see the last commit

path.test.ts

127 lines6.3 KB

1import { describe, expect, it } from "vite-plus/test";
2import {
3 workspaceRelativeFilePath,
4 newProjectFolderName,
5 normalizeProjectPathForComparison,
6 normalizeProjectPathForDispatch,
7 resolvePastedPath,
8 resolveWorkspaceFilePath,
9} from "./path.ts";
10​
11describe("path helpers", () => {
12 // regression: #17923 literal colons in names are kept, not parsed as positions
13 it.each([
14 ["report:123", "/workspace", "/workspace/report:123"],
15 ["src/file", "C:\\Workspace\\", "C:\\Workspace\\src\\file"],
16 ["~/report:123", "/workspace", "~/report:123"],
17 ])("resolves literal path %s within %s", (path, root, expected) => {
18 expect(resolveWorkspaceFilePath(path, root)).toBe(expected);
19 });
20​
21 it("normalizes a bare Windows drive root the same as one with a trailing separator", () => {
22 expect(normalizeProjectPathForDispatch("C:")).toBe("C:\\");
23 expect(normalizeProjectPathForComparison("C:")).toBe("c:\\");
24 expect(normalizeProjectPathForComparison("C:")).toBe(normalizeProjectPathForComparison("C:\\"));
25 expect(normalizeProjectPathForComparison("C:")).toBe(normalizeProjectPathForComparison("C:/"));
26 expect(normalizeProjectPathForDispatch("C:\\repo\\")).toBe("C:\\repo");
27 });
28​
29 it("names a new project's folder from any typed name", () => {
30 expect(newProjectFolderName("Pinball Stats")).toBe("pinball-stats");
31 expect(newProjectFolderName(" Café & Crème! ")).toBe("cafe-creme");
32 expect(newProjectFolderName("../../etc")).toBe("etc");
33 expect(newProjectFolderName("🎱🎱")).toBe("project");
34 expect(newProjectFolderName(`${"a".repeat(63)} b`)).toBe("a".repeat(63));
35 expect(newProjectFolderName("Con")).toBe("con-project");
36 expect(newProjectFolderName("LPT1")).toBe("lpt1-project");
37 expect(newProjectFolderName("console")).toBe("console");
38 });
39});
40​
41describe("resolvePastedPath", () => {
42 it.each([
43 ["Finder, a space", "", "'/Users/me/Monarch Money'", "/Users/me/Monarch Money"],
44 ["Finder, an apostrophe", "", "/Users/me/Bob\\'s\\ Stuff", "/Users/me/Bob's Stuff"],
45 ["Finder, a backslash", "", "/Users/me/a\\\\\\ b", "/Users/me/a\\ b"],
46 [
47 "Finder, apostrophes around a name",
48 "",
49 "/Users/me/\\'My\\ Folder\\'",
50 "/Users/me/'My Folder'",
51 ],
52 ["Explorer, a drive", "", '"C:\\Users\\me\\My Code"', "C:\\Users\\me\\My Code"],
53 ["Explorer, a share", "", '"\\\\host\\share\\My Code"', "\\\\host\\share\\My Code"],
54 ["an apostrophe in double quotes", "", '"/Users/me/Bob\'s Stuff"', "/Users/me/Bob's Stuff"],
55 ["a shell, home-relative", "", "~/Bob\\'s\\ Stuff", "~/Bob's Stuff"],
56 ["surrounding whitespace", "", " '/Users/me/My Code'\n", "/Users/me/My Code"],
57 ["over a selection", "/Users/me/old", "'/Users/me/My Code'", "/Users/me/My Code"],
58 ["after a prefilled folder", "~/", "~/'/Users/me/My Code'", "/Users/me/My Code"],
59 ["plain, after a prefilled folder", "~/", "~//Users/me/code", "/Users/me/code"],
60 ["after a Windows folder", "C:\\Users\\", 'C:\\Users\\"D:\\My Code"', "D:\\My Code"],
61 ["a shell's quoted apostrophe", "", "'/Users/me/Bob'\\''s Work'", "/Users/me/Bob's Work"],
62 ["after a clone destination", "~/code/repo", "~/code/repo'/a b'", "/a b"],
63 ["over part of the box", "~/code/old", "~/code/'/a b'", "/a b"],
64 ])("reads the path copied from %s", (_source, previous, next, expected) => {
65 expect(resolvePastedPath(previous, next)).toBe(expected);
66 });
67​
68 it.each([
69 ["typing a separator", "/Users/me", "/Users/me/"],
70 ["typing a separator after a folder", "~/", "~//"],
71 ["typing a trailing space", "/Users/My", "/Users/My "],
72 ["deleting", "/Users/me/", "/Users/me"],
73 ["pasting a relative folder", "~/", "~/Documents/code"],
74 ["a longer path over a selection", "/Users/me", "/Users/me/code"],
75 ["a longer path after a folder", "/Users/me/", "/Users/me/code"],
76 ["quoted text that is no path", "", "'hello world'"],
77 ["a quoted relative path", "", "'code/my app'"],
78 ["a search ending in a quoted path", "", "find '/tmp/repo'"],
79 ["a quote left open", "", "'/Users/me/My Code"],
80 ["a quote inside the quotes", "", "'/Users/me/it's here'"],
81 ["Windows separators", "", "C:\\Users\\me\\code"],
82 ["a Windows dot folder", "", "C:\\Users\\me\\.config"],
83 ["a Windows dot folder below home", "", "~/code\\.vscode"],
84 ["a share", "", "\\\\host\\share\\code"],
85 ["a backslash before a letter", "", "/Users/me/a\\b"],
86 ])("keeps %s", (_case, previous, next) => {
87 expect(resolvePastedPath(previous, next)).toBe(next);
88 });
89​
90 it.each(["/Users/me/a\\ b", "~/code\\.vscode", "'/Users/me/My Code'"])(
91 "leaves %s typed one character at a time",
92 (typed) => {
93 const box = [...typed].reduce((text, char) => resolvePastedPath(text, text + char), "");
94 expect(box).toBe(typed);
95 },
96 );
97});
98​
99describe("workspaceRelativeFilePath", () => {
100 // regression: #9309 POSIX paths compare case-sensitively, Windows paths do not
101 it.each([
102 ["/Repo/Project/src/main.ts", "/repo/project", null],
103 ["C:/USERS/mike/t3code/main.ts", "c:/users/MIKE/t3code", "main.ts"],
104 ["/repo/project-two/a.ts", "/repo/project", null],
105 // regression: #16354 a `..` that leaves the root is a host path, not a workspace path
106 ["/repo/project/../other/notes.md", "/repo/project", null],
107 ["C:\\repo\\project\\src\\..\\..\\notes.md", "C:\\repo\\project", null],
108 ["/repo/project/docs/a/../b.md", "/repo/project", "docs/a/../b.md"],
109 ["/repo/a\\b.txt", "/repo", "a\\b.txt"],
110 ["/repo/a/b.txt", "/repo", "a/b.txt"],
111 ["/repo/a\\", "/repo", "a\\"],
112 ["/repo/..\\notes.md", "/repo", "..\\notes.md"],
113 ["/repo/a\\/../../notes.md", "/repo", null],
114 ["/repo\\project/a.txt", "/repo\\project/", "a.txt"],
115 ["/repo/project/a.txt", "/repo\\project", null],
116 ["/repo\\project/a.txt", "/repo/project", null],
117 ["C:\\Repo\\src\\main.ts", "c:/repo/", "src/main.ts"],
118 ["/C:/Repo/src/main.ts", "c:\\repo", "src/main.ts"],
119 ["C:\\Repo\\src\\main.ts", "/c:/repo", "src/main.ts"],
120 ["\\\\SERVER\\Share\\Repo\\src\\main.ts", "\\\\server\\share\\repo", "src/main.ts"],
121 ["\\\\SERVER\\Share\\Repo\\src\\main.ts", "//server/share/repo", "src/main.ts"],
122 ["//server/share/a\\b.txt", "//server/share", "a\\b.txt"],
123 ["\\\\server\\share\\repo\\..\\notes.md", "\\\\server\\share\\repo", null],
124 ])("relates %s to %s", (path, workspaceRoot, relativePath) => {
125 expect(workspaceRelativeFilePath(path, workspaceRoot)).toBe(relativePath);
126 });
127});