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("skips malformed lines", () => {
34 const output = makeUtf16LeBuffer(
35 [
36 " NAME STATE VERSION",
37 "* Ubuntu Running 2",
38 " bad line",
39 "",
40 " Debian Stopped 2",
41 ].join("\r\n"),
42 );
43 const distros = parseWslDistroList(output);
44 expect(distros).toEqual([
45 { name: "Ubuntu", isDefault: true, version: 2 },
46 { name: "Debian", isDefault: false, version: 2 },
47 ]);
48 });
49
50 it("handles UTF-8 output", () => {
51 const text = [
52 " NAME STATE VERSION",
53 "* Debian Running 2",
54 ].join("\r\n");
55 const distros = parseWslDistroList(Buffer.from(text, "utf8"));
56 expect(distros).toEqual([{ name: "Debian", isDefault: true, version: 2 }]);
57 });
58});
59
60describe("extractDistroFromUncPath", () => {
61 it("extracts the distro from \\\\wsl.localhost UNC paths", () => {
62 expect(extractDistroFromUncPath("\\\\wsl.localhost\\Ubuntu-22.04\\home\\josh")).toBe(
63 "Ubuntu-22.04",
64 );
65 });
66});
67
68describe("wslUncPathToLinuxPath", () => {
69 it("maps WSL UNC paths back to Linux absolute paths", () => {
70 expect(wslUncPathToLinuxPath("\\\\wsl.localhost\\Ubuntu-22.04\\home\\josh\\repo")).toBe(
71 "/home/josh/repo",
72 );
73 });
74
75 it("maps a distro UNC root to Linux root", () => {
76 expect(wslUncPathToLinuxPath("\\\\wsl$\\Debian")).toBe("/");
77 expect(wslUncPathToLinuxPath("\\\\wsl.localhost\\Debian\\")).toBe("/");
78 });
79
80 it("maps UNC paths of distros whose names start or end with a dot or hyphen", () => {
81 for (const name of ["Ubuntu-", "Ubuntu.", ".Ubuntu", "-Ubuntu"]) {
82 expect(wslUncPathToLinuxPath(`\\\\wsl.localhost\\${name}\\home\\josh`)).toBe("/home/josh");
83 }
84 });
85
86 it("rejects invalid distro names and non-WSL paths", () => {
87 expect(wslUncPathToLinuxPath("\\\\wsl.localhost\\bad!name\\home")).toBeNull();
88 expect(wslUncPathToLinuxPath("\\\\wsl.localhost\\..\\home")).toBeNull();
89 expect(wslUncPathToLinuxPath("C:\\Users\\Josh\\repo")).toBeNull();
90 });
91});
92
93describe("resolveWslPickFolderDefaultPath", () => {
94 const config = { distro: null };
95 const distros = [{ name: "Debian", isDefault: true, version: 2 as const }];
96
97 it("maps Linux initial paths to WSL UNC paths", () => {
98 expect(
99 resolveWslPickFolderDefaultPath({ initialPath: "/home/josh/project" }, config, distros),
100 ).toBe("\\\\wsl.localhost\\Debian\\home\\josh\\project");
101 });
102
103 it("expands ~/path against the user's home dir when known", () => {
104 expect(
105 resolveWslPickFolderDefaultPath({ initialPath: "~/project" }, config, distros, "/home/josh"),
106 ).toBe("\\\\wsl.localhost\\Debian\\home\\josh\\project");
107 });
108
109 it("falls back to /home parent when the user's home dir isn't known", () => {
110 expect(resolveWslPickFolderDefaultPath({ initialPath: "~/project" }, config, distros)).toBe(
111 "\\\\wsl.localhost\\Debian\\home\\project",
112 );
113 });
114});
115
116describe("isValidDistroName", () => {
117 it("rejects names with trailing whitespace", () => {
118 expect(isValidDistroName("Ubuntu ")).toBe(false);
119 });
120
121 it("accepts names WSL registers with a leading or trailing dot or hyphen", () => {
122 for (const name of ["Ubuntu-", "Ubuntu.", ".Ubuntu", "-Ubuntu"]) {
123 expect(isValidDistroName(name)).toBe(true);
124 }
125 });
126
127 it("rejects names containing control or shell-meta characters", () => {
128 for (const name of ["bad\nname", "bad\tname", "bad/name", "bad!name", "bad;name"]) {
129 expect(isValidDistroName(name)).toBe(false);
130 }
131 });
132});