84 lines
3.3 KiB
TypeScript
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")
|
|
}),
|
|
)
|
|
})
|