1import type { ApiSnapshot } from "@effect/api-diff/Model"
2import { Snapshotter } from "@effect/api-diff/Snapshot"
3import { Worktrees } from "@effect/api-diff/Worktrees"
4import { assert, it } from "@effect/vitest"
5import * as Effect from "effect/Effect"
6import * as FileSystem from "effect/FileSystem"
7import * as Layer from "effect/Layer"
8import * as Path from "effect/Path"
9import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"
10import * as Sink from "effect/Sink"
11import * as Stream from "effect/Stream"
12
13const snapshot = {
14 version: 1,
15 compiler: { name: "typescript", version: "fixture" },
16 ref: "main",
17 sha: "a".repeat(40),
18 packages: [],
19 entrypoints: [],
20 entities: [],
21 diagnostics: [],
22 toJSON() {
23 throw new RangeError("Invalid string length")
24 }
25} as ApiSnapshot
26
27const SnapshotterTest = Layer.succeed(
28 Snapshotter,
29 Snapshotter.of({ extract: () => Effect.succeed(snapshot) })
30)
31
32const ChildProcessSpawnerTest = Layer.succeed(
33 ChildProcessSpawner.ChildProcessSpawner,
34 ChildProcessSpawner.make(() =>
35 Effect.succeed(ChildProcessSpawner.makeHandle({
36 pid: ChildProcessSpawner.ProcessId(1),
37 stdin: Sink.drain,
38 stdout: Stream.empty,
39 stderr: Stream.empty,
40 all: Stream.empty,
41 exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(0)),
42 isRunning: Effect.succeed(false),
43 kill: () => Effect.void,
44 getInputFd: () => Sink.drain,
45 getOutputFd: () => Stream.empty,
46 unref: Effect.succeed(Effect.void)
47 }))
48 )
49)
50
51it.effect("skips the cache write when a snapshot is too large to serialize", () => {
52 let writes = 0
53 const FileSystemTest = FileSystem.layerNoop({
54 exists: (location) => Effect.succeed(location.endsWith("tsconfig.base.json")),
55 makeDirectory: () => Effect.void,
56 makeTempDirectoryScoped: () => Effect.succeed("/worktrees/head-1"),
57 readFileString: () => Effect.succeed(`{"compilerOptions":{"stripInternal":true}}`),
58 writeFileString: () =>
59 Effect.sync(() => {
60 writes++
61 })
62 })
63 const MainLayer = Worktrees.layerNoDependencies.pipe(
64 Layer.provide(Layer.mergeAll(
65 FileSystemTest,
66 Path.layer,
67 SnapshotterTest,
68 ChildProcessSpawnerTest
69 ))
70 )
71
72 return Effect.gen(function*() {
73 const worktrees = yield* Worktrees
74 const result = yield* worktrees.prepareSnapshot({
75 repoRoot: "/repo",
76 cacheRoot: "/cache",
77 worktreesRoot: "/worktrees",
78 name: "head",
79 ref: snapshot.ref,
80 sha: snapshot.sha
81 })
82
83 assert.strictEqual(result, snapshot)
84 assert.strictEqual(writes, 0)
85 }).pipe(Effect.provide(MainLayer))
86})