Skip to content
Merged
161 changes: 150 additions & 11 deletions apps/server/src/open.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,42 @@ import { assert, describe, it } from "@effect/vitest";
import {
isCommandAvailable,
launchDetached,
normalizeWindowsExecutablePath,
resolveAvailableEditors,
resolveEditorLaunch,
} from "./open";
import { Effect } from "effect";
import { assertSuccess } from "@effect/vitest/utils";

function withTempDir(run: (dir: string) => void): void {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-"));
try {
run(dir);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
}

describe("resolveEditorLaunch", () => {
it.effect("returns commands for command-based editors", () =>
Effect.gen(function* () {
withTempDir((dir) => {
const agyPath = path.join(dir, "agy");
fs.writeFileSync(agyPath, "#!/bin/sh\nexit 0\n", "utf8");
fs.chmodSync(agyPath, 0o755);
const env = {
PATH: dir,
} satisfies NodeJS.ProcessEnv;

const antigravityLaunch = Effect.runSync(
resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "antigravity" }, "darwin", env),
);
assert.deepEqual(antigravityLaunch, {
command: "agy",
args: ["/tmp/workspace"],
});
});

const cursorLaunch = yield* resolveEditorLaunch(
{ cwd: "/tmp/workspace", editor: "cursor" },
"darwin",
Expand Down Expand Up @@ -45,6 +72,70 @@ describe("resolveEditorLaunch", () => {
}),
);

it.effect("falls back to the Antigravity app bundle on macOS", () =>
Effect.sync(() => {
withTempDir((dir) => {
const env = {
HOME: dir,
PATH: "",
} satisfies NodeJS.ProcessEnv;
fs.mkdirSync(path.join(dir, "Applications", "Antigravity.app"), { recursive: true });

const launch = Effect.runSync(
resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "antigravity" }, "darwin", env),
);
assert.deepEqual(launch, {
command: "open",
args: ["-b", "com.google.antigravity", "/tmp/workspace"],
});
});
}),
);

it.effect("falls back to the Antigravity executable on Windows", () =>
Effect.sync(() => {
withTempDir((dir) => {
const exePath = path.join(dir, "Programs", "Antigravity", "Antigravity.exe");
fs.mkdirSync(path.dirname(exePath), { recursive: true });
fs.writeFileSync(exePath, "MZ", "utf8");
const env = {
PATH: "",
LOCALAPPDATA: dir,
PATHEXT: ".COM;.EXE;.BAT;.CMD",
} satisfies NodeJS.ProcessEnv;

const launch = Effect.runSync(
resolveEditorLaunch({ cwd: "C:\\workspace", editor: "antigravity" }, "win32", env),
);
assert.deepEqual(launch, {
command: exePath,
args: ["C:\\workspace"],
});
});
}),
);

it.effect("falls back to the Antigravity launcher on Linux", () =>
Effect.sync(() => {
withTempDir((dir) => {
const launcherPath = path.join(dir, "antigravity");
fs.writeFileSync(launcherPath, "#!/bin/sh\nexit 0\n", "utf8");
fs.chmodSync(launcherPath, 0o755);
const env = {
PATH: dir,
} satisfies NodeJS.ProcessEnv;

const launch = Effect.runSync(
resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "antigravity" }, "linux", env),
);
assert.deepEqual(launch, {
command: "antigravity",
args: ["/tmp/workspace"],
});
});
}),
);

it.effect("uses --goto when editor supports line/column suffixes", () =>
Effect.gen(function* () {
const lineOnly = yield* resolveEditorLaunch(
Expand Down Expand Up @@ -140,15 +231,6 @@ describe("launchDetached", () => {
});

describe("isCommandAvailable", () => {
function withTempDir(run: (dir: string) => void): void {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-"));
try {
run(dir);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
}

it("resolves win32 commands with PATHEXT", () => {
withTempDir((dir) => {
fs.writeFileSync(path.join(dir, "code.CMD"), "@echo off\r\n", "utf8");
Expand Down Expand Up @@ -204,17 +286,74 @@ describe("isCommandAvailable", () => {
});
});

describe("normalizeWindowsExecutablePath", () => {
it("parses quoted DisplayIcon values with a trailing index", () => {
withTempDir((dir) => {
const executablePath = path.join(dir, "Antigravity.exe");
fs.writeFileSync(executablePath, "MZ", "utf8");
const env = {
PATHEXT: ".COM;.EXE;.BAT;.CMD",
} satisfies NodeJS.ProcessEnv;

assert.equal(
normalizeWindowsExecutablePath(`"${executablePath}",0`, env),
executablePath,
);
});
});
});

describe("resolveAvailableEditors", () => {
it("returns only editors whose launch commands are available", () => {
it("returns Antigravity when the app bundle exists on macOS", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-editors-"));
try {
fs.mkdirSync(path.join(dir, "Applications", "Antigravity.app"), { recursive: true });
fs.writeFileSync(path.join(dir, "cursor"), "#!/bin/sh\nexit 0\n", "utf8");
fs.chmodSync(path.join(dir, "cursor"), 0o755);
fs.writeFileSync(path.join(dir, "open"), "#!/bin/sh\nexit 0\n", "utf8");
fs.chmodSync(path.join(dir, "open"), 0o755);
const editors = resolveAvailableEditors("darwin", {
HOME: dir,
PATH: dir,
});
assert.deepEqual(editors, ["cursor", "antigravity", "file-manager"]);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});

it("returns installed editors for Windows app and command launches", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-editors-"));
try {
fs.writeFileSync(path.join(dir, "cursor.CMD"), "@echo off\r\n", "utf8");
fs.writeFileSync(path.join(dir, "explorer.EXE"), "MZ", "utf8");
const exePath = path.join(dir, "Programs", "Antigravity", "Antigravity.exe");
fs.mkdirSync(path.dirname(exePath), { recursive: true });
fs.writeFileSync(exePath, "MZ", "utf8");
const editors = resolveAvailableEditors("win32", {
PATH: dir,
LOCALAPPDATA: dir,
PATHEXT: ".COM;.EXE;.BAT;.CMD",
});
assert.deepEqual(editors, ["cursor", "file-manager"]);
assert.deepEqual(editors, ["cursor", "antigravity", "file-manager"]);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});

it("returns installed editors for Linux command launches", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-editors-"));
try {
fs.writeFileSync(path.join(dir, "cursor"), "#!/bin/sh\nexit 0\n", "utf8");
fs.chmodSync(path.join(dir, "cursor"), 0o755);
fs.writeFileSync(path.join(dir, "antigravity"), "#!/bin/sh\nexit 0\n", "utf8");
fs.chmodSync(path.join(dir, "antigravity"), 0o755);
fs.writeFileSync(path.join(dir, "xdg-open"), "#!/bin/sh\nexit 0\n", "utf8");
fs.chmodSync(path.join(dir, "xdg-open"), 0o755);
const editors = resolveAvailableEditors("linux", {
PATH: dir,
});
assert.deepEqual(editors, ["cursor", "antigravity", "file-manager"]);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
Expand Down
Loading