1import { describe, it, expect } from "vite-plus/test";
2
3import {
4 extractDistroFromUncPath,
5 isValidDistroName,
6 parseWslDistroList,
7 resolveWslPickFolderDefaultPath,
8 wslUncPathToLinuxPath,
9} from "./wslPathParsing.ts";
10
11function makeUtf16LeBuffer(text: string): Buffer {
12 return Buffer.from("" + text, "utf16le");
13}
14
15describe("parseWslDistroList", () => {
16 it("parses standard output with default distro marked", () => {
17 const output = makeUtf16LeBuffer(
18 [
19 " NAME STATE VERSION",
20 "* Ubuntu Running 2",
21 " Debian Stopped 2",
22 " Ubuntu-22.04 Running 1",
23 ].join("\r\n"),
24 );
25 const distros = parseWslDistroList(output);
26 expect(distros).toEqual([
27 { name: "Ubuntu", isDefault: true, version: 2 },
28 { name: "Debian", isDefault: false, version: 2 },
29 { name: "Ubuntu-22.04", isDefault: false, version: 1 },
30 ]);
31 });
32
33 it("returns empty array for empty buffer", () => {
34 expect(parseWslDistroList(Buffer.alloc(0))).toEqual([]);
35 });
36
37 it("returns empty array for header-only output", () => {
38 const output = makeUtf16LeBuffer(" NAME STATE VERSION\r\n");
39 expect(parseWslDistroList(output)).toEqual([]);
40 });
41
42 it("skips malformed lines", () => {
43 const output = makeUtf16LeBuffer(
44 [
45 " NAME STATE VERSION",
46 "* Ubuntu Running 2",
47 " bad line",
48 "",
49 " Debian Stopped 2",
50 ].join("\r\n"),
51 );
52 const distros = parseWslDistroList(output);
53 expect(distros).toEqual([
54 { name: "Ubuntu", isDefault: true, version: 2 },
55 { name: "Debian", isDefault: false, version: 2 },
56 ]);
57 });
58
59 it("handles output without BOM", () => {
60 const text = [
61 " NAME STATE VERSION",
62 "* Ubuntu Running 2",
63 ].join("\r\n");
64 const output = Buffer.from(text, "utf16le");
65 const distros = parseWslDistroList(output);
66 expect(distros).toEqual([{ name: "Ubuntu", isDefault: true, version: 2 }]);
67 });
68
69 it("handles UTF-8 output", () => {
70 const text = [
71 " NAME STATE VERSION",
72 "* Debian Running 2",
73 ].join("\r\n");
74 const distros = parseWslDistroList(Buffer.from(text, "utf8"));
75 expect(distros).toEqual([{ name: "Debian", isDefault: true, version: 2 }]);
76 });
77});
78
79describe("extractDistroFromUncPath", () => {
80 it("extracts the distro from \\\\wsl.localhost UNC paths", () => {
81 expect(extractDistroFromUncPath("\\\\wsl.localhost\\Ubuntu-22.04\\home\\josh")).toBe(
82 "Ubuntu-22.04",
83 );
84 });
85
86 it("extracts the distro from the legacy \\\\wsl$ UNC paths", () => {
87 expect(extractDistroFromUncPath("\\\\wsl$\\Debian\\home\\josh")).toBe("Debian");
88 });
89
90 it("returns null for non-UNC Windows paths", () => {
91 expect(extractDistroFromUncPath("C:\\Users\\Josh\\project")).toBeNull();
92 });
93
94 it("returns null when the segment is not a valid distro name", () => {
95 expect(extractDistroFromUncPath("\\\\wsl.localhost\\bad name!\\home")).toBeNull();
96 });
97});
98
99describe("wslUncPathToLinuxPath", () => {
100 it("maps WSL UNC paths back to Linux absolute paths", () => {
101 expect(wslUncPathToLinuxPath("\\\\wsl.localhost\\Ubuntu-22.04\\home\\josh\\repo")).toBe(
102 "/home/josh/repo",
103 );
104 });
105
106 it("maps a distro UNC root to Linux root", () => {
107 expect(wslUncPathToLinuxPath("\\\\wsl$\\Debian")).toBe("/");
108 expect(wslUncPathToLinuxPath("\\\\wsl.localhost\\Debian\\")).toBe("/");
109 });
110
111 it("rejects invalid distro names and non-WSL paths", () => {
112 expect(wslUncPathToLinuxPath("\\\\wsl.localhost\\bad!name\\home")).toBeNull();
113 expect(wslUncPathToLinuxPath("C:\\Users\\Josh\\repo")).toBeNull();
114 });
115});
116
117describe("resolveWslPickFolderDefaultPath", () => {
118 const config = { distro: null };
119 const distros = [{ name: "Debian", isDefault: true, version: 2 as const }];
120
121 it("uses WSL home when no initial path is provided", () => {
122 expect(resolveWslPickFolderDefaultPath(undefined, config, distros)).toBe(
123 "\\\\wsl.localhost\\Debian\\home",
124 );
125 });
126
127 it("maps Linux initial paths to WSL UNC paths", () => {
128 expect(
129 resolveWslPickFolderDefaultPath({ initialPath: "/home/josh/project" }, config, distros),
130 ).toBe("\\\\wsl.localhost\\Debian\\home\\josh\\project");
131 });
132
133 it("expands ~/path against the user's home dir when known", () => {
134 expect(
135 resolveWslPickFolderDefaultPath({ initialPath: "~/project" }, config, distros, "/home/josh"),
136 ).toBe("\\\\wsl.localhost\\Debian\\home\\josh\\project");
137 });
138
139 it("resolves bare ~ to the user's home dir when known", () => {
140 expect(
141 resolveWslPickFolderDefaultPath({ initialPath: "~" }, config, distros, "/home/josh"),
142 ).toBe("\\\\wsl.localhost\\Debian\\home\\josh");
143 });
144
145 it("falls back to /home parent when the user's home dir isn't known", () => {
146 expect(resolveWslPickFolderDefaultPath({ initialPath: "~/project" }, config, distros)).toBe(
147 "\\\\wsl.localhost\\Debian\\home\\project",
148 );
149 });
150
151 it("preserves existing UNC initial paths", () => {
152 expect(
153 resolveWslPickFolderDefaultPath(
154 { initialPath: "\\\\wsl.localhost\\Ubuntu\\home\\josh" },
155 config,
156 distros,
157 ),
158 ).toBe("\\\\wsl.localhost\\Ubuntu\\home\\josh");
159 });
160});
161
162describe("isValidDistroName", () => {
163 it("accepts common distro names", () => {
164 for (const name of ["Ubuntu", "Ubuntu-22.04", "kali-linux", "Debian", "Ubuntu 22.04"]) {
165 expect(isValidDistroName(name)).toBe(true);
166 }
167 });
168
169 it("rejects names with trailing whitespace, hyphen, or dot", () => {
170 for (const name of ["Ubuntu ", "Ubuntu-", "Ubuntu."]) {
171 expect(isValidDistroName(name)).toBe(false);
172 }
173 });
174
175 it("rejects names containing control or shell-meta characters", () => {
176 for (const name of ["bad\nname", "bad\tname", "bad/name", "bad!name", "bad;name"]) {
177 expect(isValidDistroName(name)).toBe(false);
178 }
179 });
180});