
























@@ -1,13 +1,22 @@
11import fs from "node:fs/promises";
22import path from "node:path";
3-import { describe, expect, it } from "vitest";
3+import { afterEach, describe, expect, it, vi } from "vitest";
44import { withTempDir } from "../test-helpers/temp-dir.js";
55import {
66isExecutableFile,
7+resolveExecutable,
78resolveExecutableFromPathEnv,
89resolveExecutablePath,
910} from "./executable-path.js";
101112+function restoreEnvValue(name: string, value: string | undefined): void {
13+if (value === undefined) {
14+delete process.env[name];
15+} else {
16+process.env[name] = value;
17+}
18+}
19+1120describe("executable path helpers", () => {
1221it("detects executable files and rejects directories or non-executables", async () => {
1322await withTempDir({ prefix: "openclaw-exec-path-" }, async (base) => {
@@ -95,3 +104,95 @@ describe("executable path helpers", () => {
95104).toBeUndefined();
96105});
97106});
107+108+describe("resolveExecutable", () => {
109+afterEach(() => {
110+vi.restoreAllMocks();
111+});
112+113+it("returns cmd unchanged on non-Windows platforms", () => {
114+const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("linux");
115+expect(resolveExecutable("gcloud")).toBe("gcloud");
116+platformSpy.mockRestore();
117+});
118+119+it("returns cmd unchanged when it already carries a known PATHEXT extension on Windows", () => {
120+const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
121+expect(resolveExecutable("gcloud.cmd")).toBe("gcloud.cmd");
122+expect(resolveExecutable("gcloud.exe")).toBe("gcloud.exe");
123+expect(resolveExecutable("gcloud.bat")).toBe("gcloud.bat");
124+expect(resolveExecutable("gcloud.com")).toBe("gcloud.com");
125+platformSpy.mockRestore();
126+});
127+128+it("resolves to the first .cmd result from PATH on Windows without executing where.exe", async () => {
129+const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
130+await withTempDir({ prefix: "openclaw-exec-path-" }, async (base) => {
131+const binDir = path.join(base, "bin");
132+await fs.mkdir(binDir, { recursive: true });
133+const cmdPath = path.join(binDir, "gcloud.cmd");
134+const exePath = path.join(binDir, "gcloud.exe");
135+await fs.writeFile(cmdPath, "@echo off\n", "utf8");
136+await fs.writeFile(exePath, "exe\n", "utf8");
137+138+const originalPath = process.env.PATH;
139+const originalPathext = process.env.PATHEXT;
140+process.env.PATH = binDir;
141+process.env.PATHEXT = ".EXE;.CMD;.BAT;.COM";
142+try {
143+expect(resolveExecutable("gcloud")).toBe(cmdPath);
144+} finally {
145+restoreEnvValue("PATH", originalPath);
146+restoreEnvValue("PATHEXT", originalPathext);
147+}
148+});
149+platformSpy.mockRestore();
150+});
151+152+it("falls back to .exe when no .cmd match exists on Windows", async () => {
153+const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
154+await withTempDir({ prefix: "openclaw-exec-path-" }, async (base) => {
155+const binDir = path.join(base, "bin");
156+await fs.mkdir(binDir, { recursive: true });
157+const exePath = path.join(binDir, "tailscale.exe");
158+await fs.writeFile(exePath, "exe\n", "utf8");
159+160+const originalPath = process.env.PATH;
161+process.env.PATH = binDir;
162+try {
163+expect(resolveExecutable("tailscale")).toBe(exePath);
164+} finally {
165+restoreEnvValue("PATH", originalPath);
166+}
167+});
168+platformSpy.mockRestore();
169+});
170+171+it("falls back to first PATH result when no .cmd or .exe match exists on Windows", async () => {
172+const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
173+await withTempDir({ prefix: "openclaw-exec-path-" }, async (base) => {
174+const binDir = path.join(base, "bin");
175+await fs.mkdir(binDir, { recursive: true });
176+const ps1Path = path.join(binDir, "gcloud.ps1");
177+await fs.writeFile(ps1Path, "Write-Output ok\n", "utf8");
178+179+const originalPath = process.env.PATH;
180+const originalPathext = process.env.PATHEXT;
181+process.env.PATH = binDir;
182+process.env.PATHEXT = ".PS1";
183+try {
184+expect(resolveExecutable("gcloud")).toBe(ps1Path);
185+} finally {
186+restoreEnvValue("PATH", originalPath);
187+restoreEnvValue("PATHEXT", originalPathext);
188+}
189+});
190+platformSpy.mockRestore();
191+});
192+193+it("returns original cmd when no PATH match exists on Windows", () => {
194+const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
195+expect(resolveExecutable("gog")).toBe("gog");
196+platformSpy.mockRestore();
197+});
198+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。