Merge commit '36c66dd290d3ce6eb1ccd310d0c658d4a32bb8eb' as 'repos/effect'

This commit is contained in:
-Puter
2026-07-19 03:25:10 +05:30
parent dd1071cc10
commit 2daf979036
2214 changed files with 673090 additions and 0 deletions

View File

@@ -0,0 +1,239 @@
import { afterAll, assert, describe, expect, it, layer } from "@effect/vitest"
import { Clock, Context, Duration, Effect, Fiber, Layer, Schema } from "effect"
import { FastCheck, TestClock } from "effect/testing"
it.effect(
"effect",
() => Effect.acquireRelease(Effect.sync(() => expect(1).toEqual(1)), () => Effect.void)
)
it.live(
"live",
() => Effect.acquireRelease(Effect.sync(() => expect(1).toEqual(1)), () => Effect.void)
)
// each
it.effect.each([1, 2, 3])(
"effect each %s",
(n) => Effect.acquireRelease(Effect.sync(() => expect(n).toEqual(n)), () => Effect.void)
)
it.live.each([1, 2, 3])(
"live each %s",
(n) => Effect.acquireRelease(Effect.sync(() => expect(n).toEqual(n)), () => Effect.void)
)
// skip
it.live.skip(
"live skipped",
() => Effect.die("skipped anyway")
)
it.effect.skip(
"effect skipped",
() => Effect.die("skipped anyway")
)
// skipIf
it.effect.skipIf(true)("effect skipIf (true)", () => Effect.die("skipped anyway"))
it.effect.skipIf(false)("effect skipIf (false)", () => Effect.sync(() => expect(1).toEqual(1)))
// runIf
it.effect.runIf(true)("effect runIf (true)", () => Effect.sync(() => expect(1).toEqual(1)))
it.effect.runIf(false)("effect runIf (false)", () => Effect.die("not run anyway"))
// chained helpers
it.describe.each(["foo", "bar"] as const)("describe.each %s", (text) => {
it.effect("runs an Effect test", () =>
Effect.sync(() => {
assert.include(["foo", "bar"], text)
}))
})
it.skip.each([1])("skip.each %s", () => assert.fail("skipped anyway"))
// The following test is expected to fail because it simulates a test timeout.
// Be aware that eventual "failure" of the test is only logged out.
it.live.fails("interrupts on timeout", (ctx) =>
Effect.gen(function*() {
let acquired = false
ctx.onTestFailed(() => {
if (acquired) {
// oxlint-disable-next-line no-console
console.error("'effect is interrupted on timeout' @effect/vitest test failed")
}
})
yield* Effect.acquireRelease(
Effect.sync(() => acquired = true),
() => Effect.sync(() => acquired = false)
)
yield* Effect.sleep(1000)
}), 1)
class Foo extends Context.Service<Foo, "foo">()("Foo") {
static Live = Layer.succeed(Foo)("foo")
}
class Bar extends Context.Service<Bar, "bar">()("Bar") {
static Live = Layer.effect(Bar)(Effect.map(Foo, () => "bar" as const))
}
class Sleeper extends Context.Service<Sleeper, {
readonly sleep: (ms: number) => Effect.Effect<void>
}>()("Sleeper") {
static readonly layer = Layer.effect(Sleeper)(
Effect.gen(function*() {
const clock = yield* Clock.Clock
return {
sleep: (ms: number) => clock.sleep(Duration.millis(ms))
}
})
)
}
describe("layer", () => {
layer(Foo.Live)((it) => {
it.effect("adds context", () =>
Effect.gen(function*() {
const foo = yield* Foo
expect(foo).toEqual("foo")
}))
it.layer(Bar.Live)("nested", (it) => {
it.effect("adds context", () =>
Effect.gen(function*() {
const foo = yield* Foo
const bar = yield* Bar
expect(foo).toEqual("foo")
expect(bar).toEqual("bar")
}))
})
it.layer(Bar.Live)((it) => {
it.effect("without name", () =>
Effect.gen(function*() {
const foo = yield* Foo
const bar = yield* Bar
expect(foo).toEqual("foo")
expect(bar).toEqual("bar")
}))
})
describe("release", () => {
let released = false
afterAll(() => {
expect(released).toEqual(true)
})
class Scoped extends Context.Service<Scoped, "scoped">()("Scoped") {
static Live = Layer.effect(Scoped)(
Effect.acquireRelease(
Effect.succeed("scoped" as const),
() => Effect.sync(() => released = true)
)
)
}
it.layer(Scoped.Live)((it) => {
it.effect("adds context", () =>
Effect.gen(function*() {
const foo = yield* Foo
const scoped = yield* Scoped
expect(foo).toEqual("foo")
expect(scoped).toEqual("scoped")
}))
})
it.effect.prop(
"adds context",
[realNumber],
([num]) =>
Effect.gen(function*() {
const foo = yield* Foo
expect(foo).toEqual("foo")
return num === num
}),
{ fastCheck: { numRuns: 200 } }
)
})
})
layer(Sleeper.layer)("test services", (it) => {
it.effect("TestClock", () =>
Effect.gen(function*() {
const sleeper = yield* Sleeper
const fiber = yield* Effect.forkChild(sleeper.sleep(100_000))
yield* Effect.yieldNow
yield* TestClock.adjust(100_000)
yield* Fiber.join(fiber)
}))
})
layer(Foo.Live)("with a name", (it) => {
describe("with a nested describe", () => {
it.effect("adds context", () =>
Effect.gen(function*() {
const foo = yield* Foo
expect(foo).toEqual("foo")
}))
})
it.effect("adds context", () =>
Effect.gen(function*() {
const foo = yield* Foo
expect(foo).toEqual("foo")
}))
})
layer(Sleeper.layer, { excludeTestServices: true })("live services", (it) => {
it.effect("Clock", () =>
Effect.gen(function*() {
const sleeper = yield* Sleeper
yield* sleeper.sleep(1)
}))
})
})
// property testing
const realNumber = FastCheck.float({ noNaN: true, noDefaultInfinity: true })
it.prop("symmetry", [realNumber, FastCheck.integer()], ([a, b]) => a + b === b + a)
it.prop(
"symmetry with object",
{ a: realNumber, b: FastCheck.integer() },
({ a, b }) => a + b === b + a
)
it.live.prop(
"schema with object",
{ value: Schema.Int },
({ value }) => Effect.sync(() => assert.isTrue(Number.isInteger(value)))
)
it.effect.prop("symmetry", [realNumber, FastCheck.integer()], ([a, b]) =>
Effect.gen(function*() {
yield* Effect.void
assert.isTrue(a + b === b + a)
}))
it.effect.prop("symmetry with object", { a: realNumber, b: FastCheck.integer() }, ({ a, b }) =>
Effect.gen(function*() {
yield* Effect.void
assert.strictEqual(a + b, b + a)
}))
it.effect.prop(
"should detect the substring",
{ a: FastCheck.string(), b: FastCheck.string(), c: FastCheck.string() },
({ a, b, c }) =>
Effect.gen(function*() {
yield* Effect.scope
assert.include(a + b + c, b)
})
)

View File

@@ -0,0 +1,105 @@
import { afterAll, assert, describe, it } from "@effect/vitest"
import { Context, Effect, Layer, Ref } from "effect"
interface StateShape {
readonly id: number
readonly todos: Ref.Ref<Array<string>>
readonly migrated: Ref.Ref<boolean>
}
class State extends Context.Service<State, StateShape>()("State") {}
class TodoService extends Context.Service<TodoService, {
readonly stateId: Effect.Effect<number>
readonly migrated: Effect.Effect<boolean>
readonly add: (title: string) => Effect.Effect<void>
readonly list: Effect.Effect<Array<string>>
}>()("TodoService") {}
describe("top-level it.layer isolation", () => {
let nextId = 0
const observedStateIds: Array<number> = []
const baseLayer = Layer.effect(State)(
Effect.gen(function*() {
const id = ++nextId
const todos = yield* Ref.make<Array<string>>([])
const migrated = yield* Ref.make(false)
return { id, todos, migrated }
})
)
const migrationLayer = Layer.effectDiscard(
Effect.gen(function*() {
const state = yield* State
yield* Ref.set(state.migrated, true)
})
)
const migratedLayer = Layer.merge(
baseLayer,
migrationLayer.pipe(Layer.provide(baseLayer))
)
const inMemoryLayer = Layer.effect(TodoService)(
Effect.gen(function*() {
const state = yield* State
return {
stateId: Effect.succeed(state.id),
migrated: Ref.get(state.migrated),
add: (title: string) => Ref.update(state.todos, (todos) => [...todos, title]),
list: Ref.get(state.todos)
} as const
})
).pipe(Layer.provide(migratedLayer))
it.layer(inMemoryLayer)((it) => {
it.effect("first block mutates isolated state", () =>
Effect.gen(function*() {
const service = yield* TodoService
const stateId = yield* service.stateId
const migrated = yield* service.migrated
observedStateIds.push(stateId)
yield* service.add("write tests")
assert.isTrue(migrated)
assert.deepStrictEqual(yield* service.list, ["write tests"])
}))
})
it.layer(inMemoryLayer)((it) => {
it.effect("second block starts fresh", () =>
Effect.gen(function*() {
const service = yield* TodoService
const stateId = yield* service.stateId
const migrated = yield* service.migrated
observedStateIds.push(stateId)
assert.isTrue(migrated)
assert.deepStrictEqual(yield* service.list, [])
yield* service.add("ship feature")
assert.deepStrictEqual(yield* service.list, ["ship feature"])
}))
})
it.layer(inMemoryLayer)((it) => {
it.effect("third block also starts fresh", () =>
Effect.gen(function*() {
const service = yield* TodoService
const stateId = yield* service.stateId
const migrated = yield* service.migrated
observedStateIds.push(stateId)
assert.isTrue(migrated)
assert.deepStrictEqual(yield* service.list, [])
}))
})
afterAll(() => {
assert.deepStrictEqual(observedStateIds, [1, 2, 3])
})
})

View File

@@ -0,0 +1,212 @@
import { afterAll, assert, beforeAll, describe, expect, layer } from "@effect/vitest"
import { Context, Effect, Layer, Ref } from "effect"
describe("nested sibling layers", () => {
let nextChildId = 0
let firstChildId = -1
let secondChildId = -1
const releasedChildIds: Array<number> = []
class Parent extends Context.Service<Parent, "parent">()("Parent") {
static readonly Live = Layer.succeed(Parent)("parent")
}
class Child extends Context.Service<Child, { readonly id: number }>()("Child") {
static readonly Live = Layer.effect(Child)(
Effect.flatMap(Parent, () => {
const id = ++nextChildId
return Effect.acquireRelease(
Effect.succeed({ id }),
() =>
Effect.sync(() => {
releasedChildIds.push(id)
})
)
})
)
}
layer(Parent.Live)("parent", (it) => {
it.layer(Child.Live)("first sibling", (it) => {
it.effect("allocates child", () =>
Effect.gen(function*() {
const child = yield* Child
firstChildId = child.id
assert.strictEqual(child.id, 1)
assert.deepStrictEqual(releasedChildIds, [])
}))
})
it.layer(Child.Live)("second sibling", (it) => {
beforeAll(() => {
expect(releasedChildIds).toEqual([firstChildId])
})
it.effect("allocates a fresh child", () =>
Effect.gen(function*() {
const child = yield* Child
secondChildId = child.id
assert.strictEqual(child.id, 2)
assert.isTrue(child.id !== firstChildId)
assert.deepStrictEqual(releasedChildIds, [firstChildId])
}))
})
afterAll(() => {
expect(firstChildId).toEqual(1)
expect(secondChildId).toEqual(2)
expect(releasedChildIds).toEqual([1, 2])
})
})
})
describe.concurrent("nested sibling layers in concurrent suites", () => {
let nextSharedId = 0
let firstSharedId: number | undefined
let secondSharedId: number | undefined
const releasedSharedIds: Array<number> = []
class Parent extends Context.Service<Parent, "parent">()("ConcurrentParent") {
static readonly Live = Layer.succeed(Parent)("parent")
}
class SharedChild extends Context.Service<SharedChild, { readonly id: number }>()("SharedChild") {
static readonly Live = Layer.effect(SharedChild)(
Effect.flatMap(Parent, () =>
Effect.gen(function*() {
yield* Effect.promise(() => new Promise<void>((resolve) => setTimeout(resolve, 50)))
const id = ++nextSharedId
return yield* Effect.acquireRelease(
Effect.succeed({ id }),
() =>
Effect.sync(() => {
releasedSharedIds.push(id)
})
)
}))
)
}
layer(Parent.Live)("parent", (it) => {
describe.concurrent("concurrent siblings", () => {
it.layer(SharedChild.Live)("first sibling", (it) => {
it.effect("captures shared child", () =>
Effect.gen(function*() {
const child = yield* SharedChild
firstSharedId = child.id
assert.isTrue(child.id === 1 || child.id === 2)
}))
})
it.layer(SharedChild.Live)("second sibling", (it) => {
it.effect("allocates an isolated child", () =>
Effect.gen(function*() {
const child = yield* SharedChild
secondSharedId = child.id
assert.isTrue(child.id === 1 || child.id === 2)
}))
})
})
afterAll(() => {
expect(firstSharedId).not.toEqual(secondSharedId)
expect(nextSharedId).toEqual(2)
expect([...releasedSharedIds].sort((a, b) => a - b)).toEqual([1, 2])
})
})
})
describe("nested sibling isolation with provided state graph", () => {
interface StateShape {
readonly id: number
readonly todos: Ref.Ref<Array<string>>
readonly migrated: Ref.Ref<boolean>
}
class Parent extends Context.Service<Parent, "parent">()("ProvidedParent") {
static readonly Live = Layer.succeed(Parent)("parent")
}
class State extends Context.Service<State, StateShape>()("ProvidedState") {}
class TodoService extends Context.Service<TodoService, {
readonly stateId: Effect.Effect<number>
readonly migrated: Effect.Effect<boolean>
readonly add: (title: string) => Effect.Effect<void>
readonly list: Effect.Effect<Array<string>>
}>()("ProvidedTodoService") {}
let nextId = 0
let firstStateId = -1
let secondStateId = -1
const baseLayer = Layer.effect(State)(
Effect.gen(function*() {
const id = ++nextId
const todos = yield* Ref.make<Array<string>>([])
const migrated = yield* Ref.make(false)
return { id, todos, migrated }
})
)
const migrationLayer = Layer.effectDiscard(
Effect.gen(function*() {
const state = yield* State
yield* Ref.set(state.migrated, true)
})
)
const migratedLayer = Layer.merge(
baseLayer,
migrationLayer.pipe(Layer.provide(baseLayer))
)
const inMemoryLayer = Layer.effect(TodoService)(
Effect.gen(function*() {
const state = yield* State
return {
stateId: Effect.succeed(state.id),
migrated: Ref.get(state.migrated),
add: (title: string) => Ref.update(state.todos, (todos) => [...todos, title]),
list: Ref.get(state.todos)
} as const
})
).pipe(Layer.provide(migratedLayer))
layer(Parent.Live)("parent", (it) => {
it.layer(inMemoryLayer)("first sibling", (it) => {
it.effect("mutates isolated provided state", () =>
Effect.gen(function*() {
const service = yield* TodoService
firstStateId = yield* service.stateId
assert.isTrue(yield* service.migrated)
yield* service.add("write tests")
assert.deepStrictEqual(yield* service.list, ["write tests"])
}))
})
it.layer(inMemoryLayer)("second sibling", (it) => {
it.effect("starts fresh with a new provided state", () =>
Effect.gen(function*() {
const service = yield* TodoService
secondStateId = yield* service.stateId
assert.isTrue(yield* service.migrated)
assert.deepStrictEqual(yield* service.list, [])
yield* service.add("ship feature")
assert.deepStrictEqual(yield* service.list, ["ship feature"])
}))
})
afterAll(() => {
expect(firstStateId).toEqual(1)
expect(secondStateId).toEqual(2)
expect(nextId).toEqual(2)
})
})
})