import fs from "node:fs"; import fsPromises from "node:fs/promises"; import { afterEach, describe, expect, it, vi } from "vitest"; import { resolveLsofCommand, resolveLsofCommandSync } from "./ports-lsof.js"; const LSOF_CANDIDATES = process.platform === "darwin" ? ["/usr/sbin/lsof", "/usr/bin/lsof"] : ["/usr/bin/lsof", "/usr/sbin/lsof"]; describe("lsof command resolution", () => { afterEach(() => { vi.restoreAllMocks(); }); it("prefers the first executable async candidate", async () => { const accessSpy = vi.spyOn(fsPromises, "access").mockImplementation(async (target) => { if (target === LSOF_CANDIDATES[0]) { return; } throw new Error("unexpected"); }); await expect(resolveLsofCommand()).resolves.toBe(LSOF_CANDIDATES[0]); expect(accessSpy).toHaveBeenCalledTimes(1); }); it("falls through async candidates before using the shell fallback", async () => { const accessSpy = vi.spyOn(fsPromises, "access").mockImplementation(async (target) => { if (target === LSOF_CANDIDATES[0]) { throw new Error("missing"); } if (target === LSOF_CANDIDATES[1]) { return; } throw new Error("unexpected"); }); await expect(resolveLsofCommand()).resolves.toBe(LSOF_CANDIDATES[1]); expect(accessSpy).toHaveBeenCalledTimes(2); accessSpy.mockImplementation(async () => { throw new Error("missing"); }); await expect(resolveLsofCommand()).resolves.toBe("lsof"); }); it("mirrors candidate resolution for the sync helper", () => { const accessSpy = vi.spyOn(fs, "accessSync").mockImplementation((target) => { if (target === LSOF_CANDIDATES[0]) { throw new Error("missing"); } if (target === LSOF_CANDIDATES[1]) { return undefined; } throw new Error("unexpected"); }); expect(resolveLsofCommandSync()).toBe(LSOF_CANDIDATES[1]); expect(accessSpy).toHaveBeenCalledTimes(2); accessSpy.mockImplementation(() => { throw new Error("missing"); }); expect(resolveLsofCommandSync()).toBe("lsof"); }); });