cloudaxe-opencode/packages/opencode/test/testing/simulation/filesystem.test.ts
James Long 27de1ee982 wip
2026-05-17 14:57:41 -04:00

84 lines
3.3 KiB
TypeScript

import { describe, expect } from "bun:test"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Effect, Exit } from "effect"
import { Bash, InMemoryFs } from "just-bash"
import path from "path"
import { SimulationFileSystem } from "../../../src/testing/simulation/filesystem"
import { testEffect } from "../../lib/effect"
const root = "/simulation"
const it = testEffect(
SimulationFileSystem.layer({
root,
files: {
"opencode.json": JSON.stringify({ model: "test/model" }),
"README.md": "hello",
"src/index.ts": "export const value = 1\n",
"src/data.json": JSON.stringify({ ok: true }),
},
}),
)
describe("SimulationFileSystem", () => {
it.effect("reads seeded files and writes nested files", () =>
Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
expect(yield* fs.readFileString(path.join(root, "README.md"))).toBe("hello")
expect(yield* fs.readFileString(path.join(root, "src/index.ts"))).toBe("export const value = 1\n")
expect(yield* fs.isDir(path.join(root, "src"))).toBe(true)
yield* fs.writeWithDirs(path.join(root, "tmp", "result.txt"), "done")
expect(yield* fs.readFileString(path.join(root, "tmp", "result.txt"))).toBe("done")
expect(yield* fs.isDir(path.join(root, "tmp"))).toBe(true)
expect(yield* fs.isFile(path.join(root, "tmp", "result.txt"))).toBe(true)
}),
)
it.effect("lists directory entries and globs in memory", () =>
Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
expect(yield* fs.readDirectoryEntries(path.join(root, "src"))).toEqual([
{ name: "data.json", type: "file" },
{ name: "index.ts", type: "file" },
])
expect(yield* fs.glob("**/*.ts", { cwd: root })).toEqual(["src/index.ts"])
expect(yield* fs.globUp("*.md", path.join(root, "src"), root)).toEqual([path.join(root, "README.md")])
}),
)
it.effect("denies paths outside the simulated root", () =>
Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const exit = yield* fs.readFileString("/etc/passwd").pipe(Effect.exit)
expect(Exit.isFailure(exit)).toBe(true)
}),
)
it.effect("returns no upward matches when search starts outside the simulated root", () =>
Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
expect(yield* fs.up({ targets: [".opencode"], start: "/Users/james", stop: "/Users/james" })).toEqual([])
expect(yield* fs.globUp("*.json", "/Users/james", "/Users/james")).toEqual([])
}),
)
const shared = new InMemoryFs()
const sharedIt = testEffect(SimulationFileSystem.layer({ root, fs: shared }))
sharedIt.effect("shares the just-bash filesystem with Bash", () =>
Effect.gen(function* () {
const appFs = yield* AppFileSystem.Service
const bash = new Bash({ fs: shared, cwd: root })
yield* appFs.writeWithDirs(path.join(root, "from-app.txt"), "hello from app")
expect((yield* Effect.promise(() => bash.exec("cat from-app.txt"))).stdout).toBe("hello from app")
expect((yield* Effect.promise(() => bash.exec("printf 'hello from bash' > from-bash.txt"))).exitCode).toBe(0)
expect(yield* appFs.readFileString(path.join(root, "from-bash.txt"))).toBe("hello from bash")
}),
)
})