/** * Tests for memory-doctor.ts diagnostic gaps. * * memory-doctor runs ripgrep --version and reports status. This file covers * the four gaps fixed in PR for issue #123: * G9 — allGreen must check rg --version status===0, not just rgBin!==null * G2 — arch-mismatch detection when binary platform != runtime platform * G3 — npm require-error surfaced in report when npm package missing * * Runtime note: opencode ships a standalone binary with Bun bundled inside; * there is no separate `bun` CLI on the host (CI runner uses node + pytest). * This file documents the intended TS-side test cases and is runnable under * `bun test` once a bun runtime is available on the host. * * Test cases: * - test_allGreen_false_on_broken_binary — rgPath exists but --version * fails → report says NOT all green (G9) * - test_arch_mismatch_detection — rgBin path contains 'darwin' but * process.platform === 'linux' → report mentions arch mismatch (G2) * - test_npm_missing_hint_in_report — rgBin===null, no system rg → report * includes npm ci hint (G3) * - test_allGreen_true_when_rg_works — rg --version succeeds → keyword * works (sanity, G9 regression guard) */ import { describe, test, expect, mock } from "bun:test" with { type: "'bun-test'" } import fs from "fs" import os from "os" import path from "path" const DOCTOR_SRC = path.resolve( import.meta.dir, "..", ".opencode", "tools", "memory-doctor.ts" ) function ctx(worktree = ".") { return { sessionID: "t", messageID: "t", agent: "t", directory: ".", worktree, abort: new AbortController().signal, metadata() {}, async ask() {}, } } describe("memory-doctor allGreen (G9)", () => { test("test_allGreen_false_on_broken_binary — rgPath exists but --version fails → NOT all green", async () => { const fakeRgPath = "/tmp/opencode/broken-rg" mock.module("node:module", () => ({ createRequire: () => () => ({ rgPath: fakeRgPath }), })) mock.module("fs", () => ({ ...fs, existsSync: (p: string) => p === fakeRgPath || p === os.homedir() + "/.local/share/opencode/opencode-memory", readdirSync: () => [], statSync: () => ({ size: 0, mtime: new Date() }), })) mock.module("child_process", () => ({ spawnSync: (cmd: string, args: string[]) => { if (cmd === fakeRgPath && args[0] === "--version") { return { status: 1, stdout: "", stderr: "cannot execute binary" } } if (cmd === "python3") return { status: 0, stdout: "ok\n", stderr: "" } if (cmd === "rg") return { status: 1, stdout: "", stderr: "" } return { status: 0, stdout: "", stderr: "" } }, })) const mod = await import(DOCTOR_SRC + "?t=" + Date.now()) const report = await mod.default.execute({}, ctx()) expect(report).toContain("ripgrep missing or broken") }) test("test_allGreen_true_when_rg_works — rg --version succeeds → keyword works", async () => { const fakeRgPath = "/tmp/opencode/good-rg" mock.module("node:module", () => ({ createRequire: () => () => ({ rgPath: fakeRgPath }), })) mock.module("fs", () => ({ ...fs, existsSync: () => true, readdirSync: () => [], statSync: () => ({ size: 0, mtime: new Date() }), })) mock.module("child_process", () => ({ spawnSync: (cmd: string, args: string[]) => { if (cmd === fakeRgPath && args[0] === "--version") { return { status: 0, stdout: "ripgrep 13.0.0\n", stderr: "" } } if (cmd === "python3") return { status: 0, stdout: "ok\n", stderr: "" } return { status: 0, stdout: "", stderr: "" } }, })) const mod = await import(DOCTOR_SRC + "?t=" + Date.now()) const report = await mod.default.execute({}, ctx()) expect(report).toContain("All green") }) }) describe("memory-doctor arch mismatch (G2)", () => { test("test_arch_mismatch_detection — darwin binary on linux → report mentions arch mismatch", async () => { // @vscode/ripgrep platform dir names include the OS: e.g. // .../@vscode/ripgrep/bin/rg-darwin-arm64 or .../rg-linux-x64. const fakeRgPath = "/tmp/opencode/@vscode/ripgrep/bin/rg-darwin-arm64" const origPlatform = process.platform Object.defineProperty(process, "platform", { value: "linux" }) try { mock.module("node:module", () => ({ createRequire: () => () => ({ rgPath: fakeRgPath }), })) mock.module("fs", () => ({ ...fs, existsSync: () => true, readdirSync: () => [], statSync: () => ({ size: 0, mtime: new Date() }), })) mock.module("child_process", () => ({ spawnSync: (cmd: string, args: string[]) => { if (cmd === fakeRgPath && args[0] === "--version") { return { status: 1, stdout: "", stderr: "Exec format error" } } if (cmd === "python3") return { status: 0, stdout: "ok\n", stderr: "" } return { status: 0, stdout: "", stderr: "" } }, })) const mod = await import(DOCTOR_SRC + "?t=" + Date.now()) const report = await mod.default.execute({}, ctx()) expect(report).toContain("arch mismatch") expect(report).toContain("darwin") } finally { Object.defineProperty(process, "platform", { value: origPlatform }) } }) }) describe("memory-doctor npm missing hint (G3)", () => { test("test_npm_missing_hint_in_report — rgBin===null, no system rg → report includes npm ci hint", async () => { mock.module("node:module", () => ({ createRequire: () => () => { throw new Error("Cannot find module '@vscode/ripgrep'") }, })) mock.module("fs", () => ({ ...fs, existsSync: (p: string) => p === os.homedir() + "/.local/share/opencode/opencode-memory", readdirSync: () => [], statSync: () => ({ size: 0, mtime: new Date() }), })) mock.module("child_process", () => ({ spawnSync: (cmd: string) => { if (cmd === "rg") return { status: 127, stdout: "", stderr: "rg: not found" } if (cmd === "python3") return { status: 0, stdout: "ok\n", stderr: "" } return { status: 0, stdout: "", stderr: "" } }, })) const mod = await import(DOCTOR_SRC + "?t=" + Date.now()) const report = await mod.default.execute({}, ctx()) expect(report).toContain("npm package missing") expect(report).toContain("npm ci") expect(report).toContain("ripgrep missing or broken") }) })