mirror of
https://github.com/bendtherules/opencode-multi-model.git
synced 2026-08-18 13:42:21 +00:00
Add more tests
This commit is contained in:
@@ -14,8 +14,11 @@ import {
|
||||
sanitizeName,
|
||||
runCommand,
|
||||
getWorktreePath,
|
||||
getSessionPath,
|
||||
undoWorktree,
|
||||
launchModelInWindow,
|
||||
getWorktreesForSession,
|
||||
getBinaryName,
|
||||
} from "../src/core/utils";
|
||||
|
||||
let originalBun$: typeof Bun.$ = (globalThis as any).Bun?.$;
|
||||
@@ -351,6 +354,19 @@ describe("multi-model launch", () => {
|
||||
});
|
||||
|
||||
describe("core utils", () => {
|
||||
let bunMock: ReturnType<typeof setupMockBun$>;
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(os, "homedir").mockReturnValue("/mock/home");
|
||||
bunMock = setupMockBun$();
|
||||
executedCommands = [];
|
||||
mockCommandResponses = {};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
restoreOriginalBun$();
|
||||
});
|
||||
|
||||
describe("shellQuote", () => {
|
||||
test("normal string without special characters", () => {
|
||||
expect(shellQuote("test")).toBe("'test'");
|
||||
@@ -556,4 +572,138 @@ describe("core utils", () => {
|
||||
expect(sanitizeName("-test-session-")).toBe("test-session");
|
||||
});
|
||||
});
|
||||
|
||||
describe("runCommand", () => {
|
||||
test("returns ok true for successful command", async () => {
|
||||
mockCommandResponses["echo hello"] = { ok: true, stdout: "hello", stderr: "" };
|
||||
const result = await runCommand(["echo", "hello"]);
|
||||
expect(result.ok).toBe(true);
|
||||
expect(result.stdout).toBe("hello");
|
||||
expect(result.stderr).toBe("");
|
||||
});
|
||||
|
||||
test("returns ok false for failed command", async () => {
|
||||
mockCommandResponses["false"] = { ok: false, stdout: "", stderr: "error" };
|
||||
const result = await runCommand(["false"]);
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.stderr).toBe("error");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getWorktreePath", () => {
|
||||
test("returns correct worktree path", () => {
|
||||
spyOn(os, "homedir").mockReturnValue("/home/user");
|
||||
const result = getWorktreePath("my-session", "gpt-4o");
|
||||
expect(result).toBe("/home/user/.local/share/opencode/multi-model/my-session/gpt-4o");
|
||||
});
|
||||
|
||||
test("handles nested session names", () => {
|
||||
spyOn(os, "homedir").mockReturnValue("/home/user");
|
||||
const result = getWorktreePath("parent/child", "window");
|
||||
expect(result).toBe("/home/user/.local/share/opencode/multi-model/parent/child/window");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getSessionPath", () => {
|
||||
test("returns correct session path", () => {
|
||||
spyOn(os, "homedir").mockReturnValue("/home/user");
|
||||
const result = getSessionPath("my-session");
|
||||
expect(result).toBe("/home/user/.local/share/opencode/multi-model/my-session");
|
||||
});
|
||||
});
|
||||
|
||||
describe("undoWorktree", () => {
|
||||
test("returns empty array on success", async () => {
|
||||
mockCommandResponses["git worktree remove -f /path/to/worktree"] = { ok: true, stdout: "", stderr: "" };
|
||||
mockCommandResponses["git branch -D opencode/session/window"] = { ok: true, stdout: "", stderr: "" };
|
||||
|
||||
const errors = await undoWorktree("/path/to/worktree", "opencode/session/window");
|
||||
expect(errors).toEqual([]);
|
||||
});
|
||||
|
||||
test("returns error when worktree remove fails", async () => {
|
||||
mockCommandResponses["git worktree remove -f /path/to/worktree"] = { ok: false, stdout: "", stderr: "remove failed" };
|
||||
mockCommandResponses["git branch -D opencode/session/window"] = { ok: true, stdout: "", stderr: "" };
|
||||
|
||||
const errors = await undoWorktree("/path/to/worktree", "opencode/session/window");
|
||||
expect(errors.length).toBe(1);
|
||||
expect(errors[0]).toContain("Failed to remove worktree");
|
||||
});
|
||||
|
||||
test("returns error when branch delete fails", async () => {
|
||||
mockCommandResponses["git worktree remove -f /path/to/worktree"] = { ok: true, stdout: "", stderr: "" };
|
||||
mockCommandResponses["git branch -D opencode/session/window"] = { ok: false, stdout: "", stderr: "branch delete failed" };
|
||||
|
||||
const errors = await undoWorktree("/path/to/worktree", "opencode/session/window");
|
||||
expect(errors.length).toBe(1);
|
||||
expect(errors[0]).toContain("Failed to delete branch");
|
||||
});
|
||||
|
||||
test("returns both errors when both operations fail", async () => {
|
||||
mockCommandResponses["git worktree remove -f /path/to/worktree"] = { ok: false, stdout: "", stderr: "remove failed" };
|
||||
mockCommandResponses["git branch -D opencode/session/window"] = { ok: false, stdout: "", stderr: "branch delete failed" };
|
||||
|
||||
const errors = await undoWorktree("/path/to/worktree", "opencode/session/window");
|
||||
expect(errors.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("launchModelInWindow", () => {
|
||||
test("sends correct tmux command", async () => {
|
||||
mockCommandResponses["tmux send-keys -t session:window opencode --model 'openai/gpt-4o' C-m"] = { ok: true, stdout: "", stderr: "" };
|
||||
|
||||
const result = await launchModelInWindow("session", { model: "openai/gpt-4o", windowName: "window" });
|
||||
expect(result.ok).toBe(true);
|
||||
expect(executedCommands).toContain("tmux send-keys -t session:window opencode --model 'openai/gpt-4o' C-m");
|
||||
});
|
||||
|
||||
test("uses custom binary name", async () => {
|
||||
mockCommandResponses["tmux send-keys -t session:window kilo --model 'openai/gpt-4o' C-m"] = { ok: true, stdout: "", stderr: "" };
|
||||
|
||||
const result = await launchModelInWindow("session", { model: "openai/gpt-4o", windowName: "window" }, "kilo");
|
||||
expect(result.ok).toBe(true);
|
||||
expect(executedCommands).toContain("tmux send-keys -t session:window kilo --model 'openai/gpt-4o' C-m");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getWorktreesForSession", () => {
|
||||
test("returns session-specific worktrees", async () => {
|
||||
spyOn(os, "homedir").mockReturnValue("/home/user");
|
||||
mockCommandResponses["git worktree list --porcelain"] = {
|
||||
ok: true,
|
||||
stdout: "worktree /home/user/.local/share/opencode/multi-model/my-session/gpt-4o\nbranch refs/heads/opencode/my-session/gpt-4o\n\nworktree /home/user/other-repo\nbranch refs/heads/main",
|
||||
stderr: "",
|
||||
};
|
||||
|
||||
const worktrees = await getWorktreesForSession("my-session");
|
||||
expect(worktrees.length).toBe(1);
|
||||
expect(worktrees[0]?.path).toBe("/home/user/.local/share/opencode/multi-model/my-session/gpt-4o");
|
||||
expect(worktrees[0]?.branch).toBe("opencode/my-session/gpt-4o");
|
||||
});
|
||||
|
||||
test("returns empty array when no matching worktrees", async () => {
|
||||
spyOn(os, "homedir").mockReturnValue("/home/user");
|
||||
mockCommandResponses["git worktree list --porcelain"] = {
|
||||
ok: true,
|
||||
stdout: "worktree /home/user/other-repo\nbranch refs/heads/main",
|
||||
stderr: "",
|
||||
};
|
||||
|
||||
const worktrees = await getWorktreesForSession("my-session");
|
||||
expect(worktrees).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getBinaryName", () => {
|
||||
test("returns default 'opencode' when env var not set", () => {
|
||||
delete process.env.OPENCODE_MULTI_MODEL_BINARY;
|
||||
expect(getBinaryName()).toBe("opencode");
|
||||
});
|
||||
|
||||
test("returns env var value when set", () => {
|
||||
process.env.OPENCODE_MULTI_MODEL_BINARY = "kilo";
|
||||
expect(getBinaryName()).toBe("kilo");
|
||||
delete process.env.OPENCODE_MULTI_MODEL_BINARY;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user