Files
oh-my-opencode/src/features/boulder-state/storage.test.ts
T

251 lines
6.9 KiB
TypeScript
Raw Normal View History

2026-01-09 02:24:43 +09:00
import { describe, expect, test, beforeEach, afterEach } from "bun:test"
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
import { join } from "node:path"
import { tmpdir } from "node:os"
import {
readBoulderState,
writeBoulderState,
appendSessionId,
clearBoulderState,
getPlanProgress,
getPlanName,
createBoulderState,
findPrometheusPlans,
} from "./storage"
import type { BoulderState } from "./types"
describe("boulder-state", () => {
const TEST_DIR = join(tmpdir(), "boulder-state-test-" + Date.now())
const SISYPHUS_DIR = join(TEST_DIR, ".sisyphus")
beforeEach(() => {
if (!existsSync(TEST_DIR)) {
mkdirSync(TEST_DIR, { recursive: true })
}
if (!existsSync(SISYPHUS_DIR)) {
mkdirSync(SISYPHUS_DIR, { recursive: true })
}
clearBoulderState(TEST_DIR)
})
afterEach(() => {
if (existsSync(TEST_DIR)) {
rmSync(TEST_DIR, { recursive: true, force: true })
}
})
describe("readBoulderState", () => {
test("should return null when no boulder.json exists", () => {
// #given - no boulder.json file
// #when
const result = readBoulderState(TEST_DIR)
// #then
expect(result).toBeNull()
})
test("should read valid boulder state", () => {
// #given - valid boulder.json
const state: BoulderState = {
active_plan: "/path/to/plan.md",
started_at: "2026-01-02T10:00:00Z",
session_ids: ["session-1", "session-2"],
plan_name: "my-plan",
}
writeBoulderState(TEST_DIR, state)
// #when
const result = readBoulderState(TEST_DIR)
// #then
expect(result).not.toBeNull()
expect(result?.active_plan).toBe("/path/to/plan.md")
expect(result?.session_ids).toEqual(["session-1", "session-2"])
expect(result?.plan_name).toBe("my-plan")
})
})
describe("writeBoulderState", () => {
test("should write state and create .sisyphus directory if needed", () => {
// #given - state to write
const state: BoulderState = {
active_plan: "/test/plan.md",
started_at: "2026-01-02T12:00:00Z",
session_ids: ["ses-123"],
plan_name: "test-plan",
}
// #when
const success = writeBoulderState(TEST_DIR, state)
const readBack = readBoulderState(TEST_DIR)
// #then
expect(success).toBe(true)
expect(readBack).not.toBeNull()
expect(readBack?.active_plan).toBe("/test/plan.md")
})
})
describe("appendSessionId", () => {
test("should append new session id to existing state", () => {
// #given - existing state with one session
const state: BoulderState = {
active_plan: "/plan.md",
started_at: "2026-01-02T10:00:00Z",
session_ids: ["session-1"],
plan_name: "plan",
}
writeBoulderState(TEST_DIR, state)
// #when
const result = appendSessionId(TEST_DIR, "session-2")
// #then
expect(result).not.toBeNull()
expect(result?.session_ids).toEqual(["session-1", "session-2"])
})
test("should not duplicate existing session id", () => {
// #given - state with session-1 already
const state: BoulderState = {
active_plan: "/plan.md",
started_at: "2026-01-02T10:00:00Z",
session_ids: ["session-1"],
plan_name: "plan",
}
writeBoulderState(TEST_DIR, state)
// #when
appendSessionId(TEST_DIR, "session-1")
const result = readBoulderState(TEST_DIR)
// #then
expect(result?.session_ids).toEqual(["session-1"])
})
test("should return null when no state exists", () => {
// #given - no boulder.json
// #when
const result = appendSessionId(TEST_DIR, "new-session")
// #then
expect(result).toBeNull()
})
})
describe("clearBoulderState", () => {
test("should remove boulder.json", () => {
// #given - existing state
const state: BoulderState = {
active_plan: "/plan.md",
started_at: "2026-01-02T10:00:00Z",
session_ids: ["session-1"],
plan_name: "plan",
}
writeBoulderState(TEST_DIR, state)
// #when
const success = clearBoulderState(TEST_DIR)
const result = readBoulderState(TEST_DIR)
// #then
expect(success).toBe(true)
expect(result).toBeNull()
})
test("should succeed even when no file exists", () => {
// #given - no boulder.json
// #when
const success = clearBoulderState(TEST_DIR)
// #then
expect(success).toBe(true)
})
})
describe("getPlanProgress", () => {
test("should count completed and uncompleted checkboxes", () => {
// #given - plan file with checkboxes
const planPath = join(TEST_DIR, "test-plan.md")
writeFileSync(planPath, `# Plan
- [ ] Task 1
- [x] Task 2
- [ ] Task 3
- [X] Task 4
`)
// #when
const progress = getPlanProgress(planPath)
// #then
expect(progress.total).toBe(4)
expect(progress.completed).toBe(2)
expect(progress.isComplete).toBe(false)
})
test("should return isComplete true when all checked", () => {
// #given - all tasks completed
const planPath = join(TEST_DIR, "complete-plan.md")
writeFileSync(planPath, `# Plan
- [x] Task 1
- [X] Task 2
`)
// #when
const progress = getPlanProgress(planPath)
// #then
expect(progress.total).toBe(2)
expect(progress.completed).toBe(2)
expect(progress.isComplete).toBe(true)
})
test("should return isComplete true for empty plan", () => {
// #given - plan with no checkboxes
const planPath = join(TEST_DIR, "empty-plan.md")
writeFileSync(planPath, "# Plan\nNo tasks here")
// #when
const progress = getPlanProgress(planPath)
// #then
expect(progress.total).toBe(0)
expect(progress.isComplete).toBe(true)
})
test("should handle non-existent file", () => {
// #given - non-existent file
// #when
const progress = getPlanProgress("/non/existent/file.md")
// #then
expect(progress.total).toBe(0)
expect(progress.isComplete).toBe(true)
})
})
describe("getPlanName", () => {
test("should extract plan name from path", () => {
// #given
const path = "/home/user/.sisyphus/plans/project/my-feature.md"
// #when
const name = getPlanName(path)
// #then
expect(name).toBe("my-feature")
})
})
describe("createBoulderState", () => {
test("should create state with correct fields", () => {
// #given
const planPath = "/path/to/auth-refactor.md"
const sessionId = "ses-abc123"
// #when
const state = createBoulderState(planPath, sessionId)
// #then
expect(state.active_plan).toBe(planPath)
expect(state.session_ids).toEqual([sessionId])
expect(state.plan_name).toBe("auth-refactor")
expect(state.started_at).toBeDefined()
})
})
})