mirror of
https://github.com/anomalyco/opencode.git
synced 2026-10-23 22:50:30 +00:00
138 lines
4.8 KiB
TypeScript
138 lines
4.8 KiB
TypeScript
import { expect } from "bun:test"
|
|
import { Effect } from "effect"
|
|
import { State } from "@opencode/core/state"
|
|
import { it } from "./lib/effect"
|
|
|
|
it.effect("detaches every registration of a failed group and refreshes every affected domain", () =>
|
|
Effect.gen(function* () {
|
|
const notices: string[] = []
|
|
const failures: State.Failure[] = []
|
|
let refresh = Effect.void
|
|
let fail = false
|
|
let calls = 0
|
|
const grouped = State.group((failure, changed) => {
|
|
failures.push(failure)
|
|
refresh = changed
|
|
})
|
|
const first = State.create({
|
|
name: "first",
|
|
initial: () => ({ values: [] as string[] }),
|
|
editor: (value) => value,
|
|
notify: () => Effect.sync(() => void notices.push("first")),
|
|
})
|
|
const second = State.create({
|
|
name: "second",
|
|
initial: () => ({ values: [] as string[] }),
|
|
editor: (value) => value,
|
|
notify: () => Effect.sync(() => void notices.push("second")),
|
|
})
|
|
yield* first.transform((editor) => editor.values.push("healthy"))
|
|
const registration = yield* first.transform((editor) => editor.values.push("grouped")).pipe(grouped)
|
|
yield* first.transform((editor) => editor.values.push("also grouped")).pipe(grouped)
|
|
yield* second
|
|
.transform((editor) => {
|
|
calls++
|
|
editor.values.push("partial")
|
|
if (fail) throw new Error("broken")
|
|
})
|
|
.pipe(grouped)
|
|
const before = first.get()
|
|
notices.length = 0
|
|
fail = true
|
|
yield* second.reload()
|
|
|
|
expect(first.get().values).toEqual(["healthy"])
|
|
expect(second.get().values).toEqual([])
|
|
expect(before.values).toEqual(["healthy", "grouped", "also grouped"])
|
|
expect(failures).toHaveLength(1)
|
|
expect(failures[0]?.state).toBe("second")
|
|
expect(calls).toBe(2)
|
|
|
|
notices.length = 0
|
|
// The group deduplicates its domain notifications without relying on an outer batch.
|
|
yield* refresh
|
|
expect(notices.toSorted()).toEqual(["first", "second"])
|
|
yield* registration.dispose
|
|
expect(notices).toHaveLength(2)
|
|
yield* first.transform((editor) => editor.values.push("resurrected")).pipe(grouped)
|
|
expect(first.get().values).toEqual(["healthy"])
|
|
expect(failures).toHaveLength(1)
|
|
}),
|
|
)
|
|
|
|
it.effect("restarts an outer candidate when a nested read disables one of its contributors", () =>
|
|
Effect.gen(function* () {
|
|
let fail = false
|
|
const grouped = State.group(() => {})
|
|
const inner = State.create({ initial: () => ({ value: 0 }), editor: (value) => value })
|
|
const outer = State.create({ initial: () => ({ value: 0 }), editor: (value) => value })
|
|
yield* outer.transform((editor) => (editor.value += 10)).pipe(grouped)
|
|
yield* inner
|
|
.transform((editor) => {
|
|
editor.value = 5
|
|
if (fail) throw new Error("inner failed")
|
|
})
|
|
.pipe(grouped)
|
|
yield* outer.transform((editor) => (editor.value += inner.get().value + 1))
|
|
expect(outer.get().value).toBe(16)
|
|
|
|
fail = true
|
|
yield* State.batch(
|
|
Effect.gen(function* () {
|
|
yield* inner.reload()
|
|
yield* outer.reload()
|
|
expect(outer.get().value).toBe(1)
|
|
expect(inner.get().value).toBe(0)
|
|
}),
|
|
)
|
|
}),
|
|
)
|
|
|
|
it.effect("disables multiple failing groups once each before publishing a complete fold", () =>
|
|
Effect.gen(function* () {
|
|
const reported: string[] = []
|
|
const first = State.group(() => reported.push("first"))
|
|
const second = State.group(() => reported.push("second"))
|
|
const state = State.create({ initial: () => ({ values: [] as string[] }), editor: (value) => value })
|
|
yield* State.batch(
|
|
Effect.gen(function* () {
|
|
yield* state
|
|
.transform((editor) => {
|
|
editor.values.push("first")
|
|
throw "first failed"
|
|
})
|
|
.pipe(first)
|
|
yield* state
|
|
.transform((editor) => {
|
|
editor.values.push("second")
|
|
throw { message: "second failed" }
|
|
})
|
|
.pipe(second)
|
|
yield* state.transform((editor) => editor.values.push("healthy"))
|
|
}),
|
|
)
|
|
expect(state.get().values).toEqual(["healthy"])
|
|
expect(reported).toEqual(["first", "second"])
|
|
yield* state.reload()
|
|
expect(reported).toEqual(["first", "second"])
|
|
}),
|
|
)
|
|
|
|
it.effect("does not disable a group for a notification failure after successful replay", () =>
|
|
Effect.gen(function* () {
|
|
let reported = 0
|
|
let fail = true
|
|
const grouped = State.group(() => reported++)
|
|
const state = State.create({
|
|
initial: () => ({ value: 0 }),
|
|
editor: (value) => value,
|
|
notify: () => (fail ? Effect.die("observer failed") : Effect.void),
|
|
})
|
|
yield* state.transform((editor) => editor.value++).pipe(grouped, Effect.exit)
|
|
expect(reported).toBe(0)
|
|
expect(state.get().value).toBe(1)
|
|
fail = false
|
|
yield* state.reload()
|
|
expect(state.get().value).toBe(1)
|
|
}),
|
|
)
|