返回 DeepSeek-Reasonix
file-paths.test.ts
根目录 / desktop / frontend / src / __tests__ / file-paths.test.ts
1 // Cross-platform path identity used by chat file recognition. The flavor rules
2 // here are what keep a Windows drive path and a POSIX path with a literal
3 // backslash from collapsing into each other.
4 import assert from "node:assert/strict";
5 import {
6 declaredPathFlavor, fileIdentity, fileURLToPath, isAbsolutePath, isUncPath,
7 isWindowsDrivePath, pathBasename, pathExtension,
8 } from "../lib/filePaths";
9
10 // ── Windows drive, UNC, and separators ──────────────────────────────────────
11 assert.equal(fileIdentity("C:\\Users\\me\\out.svg"), "C:/Users/me/out.svg");
12 assert.equal(fileIdentity("c:/users/me/out.svg"), "C:/users/me/out.svg", "drive letter folds case");
13 assert.equal(fileIdentity("C:\\Users\\me\\out.svg"), fileIdentity("c:/Users/me/out.svg"));
14 assert.equal(fileIdentity("C:\\a\\..\\b\\c.go"), "C:/b/c.go");
15 assert.equal(fileIdentity("C:\\..\\..\\b.go"), "C:/b.go", "a drive root is never folded away");
16 assert.equal(fileIdentity("C:\\.."), "C:/");
17 assert.equal(fileIdentity("\\\\server\\share\\dir\\a.txt"), "//server/share/dir/a.txt");
18 assert.equal(fileIdentity("//server/share/dir/a.txt"), "//server/share/dir/a.txt");
19 assert.equal(fileIdentity("\\\\server\\share\\a\\..\\b.txt"), "//server/share/b.txt");
20 assert.equal(fileIdentity("\\\\server\\share\\..\\..\\b.txt"), "//server/share/b.txt", "a UNC share root is preserved");
21 assert(isUncPath("\\\\server\\share"), "UNC detection");
22 assert(isUncPath("//server/share"), "UNC forward-slash detection");
23 assert(isWindowsDrivePath("C:/x"), "forward-slash drive path detection");
24 assert.equal(declaredPathFlavor("C:\\x"), "windows");
25 assert.equal(declaredPathFlavor("/home/x"), "posix");
26 assert.equal(declaredPathFlavor("src/x.ts"), undefined, "relative paths declare no flavor");
27
28 // ── POSIX, including the backslash rule ─────────────────────────────────────
29 assert.equal(fileIdentity("/home/me/out.svg"), "/home/me/out.svg");
30 assert.equal(fileIdentity("/home/me/./sub/../out.svg"), "/home/me/out.svg");
31 assert.equal(fileIdentity("/../../etc/passwd"), "/etc/passwd", ".. never escapes the POSIX root");
32 assert.equal(fileIdentity("/tmp/a\\b.svg"), "/tmp/a\\b.svg", "a POSIX path keeps literal backslashes");
33 assert.notEqual(fileIdentity("/tmp/a\\b.svg"), fileIdentity("/tmp/a/b.svg"));
34 assert.equal(fileIdentity("out/a.svg", "posix"), "out/a.svg");
35 assert.equal(fileIdentity("out\\a.svg", "posix"), "out\\a.svg", "a POSIX host keeps the backslash");
36 assert.equal(fileIdentity("out\\a.svg", "windows"), "out/a.svg");
37 assert.equal(fileIdentity("out\\a.svg"), "out\\a.svg", "an ambiguous relative path preserves a literal backslash");
38 assert.notEqual(fileIdentity("out\\a.svg"), fileIdentity("out/a.svg"), "the renderer never merges host-ambiguous paths");
39
40 // ── file:// URLs decode once, ordinary paths never decode ───────────────────
41 assert.equal(fileURLToPath("file:///home/me/a%20b.svg"), "/home/me/a b.svg");
42 assert.equal(fileURLToPath("file:///C:/Users/me/a.svg"), "C:/Users/me/a.svg");
43 assert.equal(fileURLToPath("file://localhost/home/me/a.svg"), "/home/me/a.svg");
44 assert.equal(fileURLToPath("file://server/share/a.svg"), "//server/share/a.svg", "an authority form is a UNC file URL");
45 assert.equal(fileURLToPath("file:///home/me/a.svg?v=1"), undefined);
46 assert.equal(fileURLToPath("file:////./PhysicalDrive0"), undefined, "a device authority is never a file path");
47 assert.equal(fileURLToPath("FILE:///home/me/a.svg"), undefined, "the scheme match is case-sensitive like the link allowlist");
48 assert.equal(fileIdentity("file:///home/me/a%20b.svg"), "/home/me/a b.svg");
49 assert.equal(fileIdentity("file://server/share/a.svg"), "//server/share/a.svg", "a UNC file URL keeps its share root");
50 assert.equal(fileIdentity("/home/me/a%20b.svg"), "/home/me/a%20b.svg", "a literal %20 is not an escape");
51 assert.notEqual(fileIdentity("/home/me/a%20b.svg"), fileIdentity("/home/me/a b.svg"));
52 assert.equal(fileIdentity(" /tmp/x.svg "), "/tmp/x.svg", "surrounding whitespace is trimmed");
53
54 // ── Space, CJK, parentheses, and other legal filename bytes survive ─────────
55 assert.equal(fileIdentity("/Users/me/我的 项目/图 (1).svg"), "/Users/me/我的 项目/图 (1).svg");
56 assert.equal(fileIdentity("C:\\我的 项目\\图 (1).svg"), "C:/我的 项目/图 (1).svg");
57 assert.equal(pathBasename("/Users/me/我的 项目/图 (1).svg"), "图 (1).svg");
58
59 // ── Case is preserved, so a case-sensitive volume is never merged ───────────
60 assert.notEqual(fileIdentity("/Users/me/Out.svg"), fileIdentity("/Users/me/out.svg"));
61 assert.notEqual(fileIdentity("/home/me/Readme.md"), fileIdentity("/home/me/readme.md"));
62
63 // ── Basename, extension, and absoluteness ───────────────────────────────────
64 assert.equal(pathBasename("C:\\a\\b\\c.tar.gz"), "c.tar.gz");
65 assert.equal(pathBasename("/a/b/"), "b");
66 assert.equal(pathBasename("file:///a/b/c.svg"), "c.svg");
67 assert.equal(pathExtension("a/b/c.TAR.GZ"), "gz");
68 assert.equal(pathExtension("/a/.gitignore"), "", "a dotfile has no extension");
69 assert.equal(pathExtension("a/b."), "");
70 assert(isAbsolutePath("/home/x"));
71 assert(isAbsolutePath("C:\\x"));
72 assert(isAbsolutePath("\\\\server\\share\\x"));
73 assert(isAbsolutePath("file:///home/x"));
74 assert(!isAbsolutePath("src/x.ts"));
75 assert(!isAbsolutePath("src\\x.ts"), "a relative path is not absolute on either flavor");
76
77 // ── Same-file aliases and same-name ambiguity ───────────────────────────────
78 assert.equal(
79 fileIdentity("./out/diagram.svg"),
80 fileIdentity("out/diagram.svg"),
81 "a ./ prefix names the same relative file",
82 );
83 assert.equal(
84 fileIdentity("C:\\repo\\out\\diagram.svg"),
85 fileIdentity("c:/repo/./out/../out/diagram.svg"),
86 );
87 assert.equal(
88 fileIdentity("/repo/out/diagram.svg"),
89 fileIdentity("/repo/out/../out/diagram.svg"),
90 );
91 assert.notEqual(fileIdentity("out/diagram.svg"), fileIdentity("/repo/out/diagram.svg"), "a relative and an absolute spelling stay distinct until the host resolves them");
92 assert.equal(pathBasename("/a/diagram.svg"), pathBasename("/b/diagram.svg"), "two files can share a basename");
93
94 console.log("file paths: three-platform identity and URL decoding passed");
95
95 lines TYPESCRIPT