History

Refactor filesystem and VCS config Effect usage

Cursor Agent committed 4 months ago

Commit cb1e1691 parent 3bdaa6e4 files · +230 −83Browse files

Showing the changes to apps/server/src/workspace/Layers/WorkspaceFileSystem.test.ts (1 of 4 files). Show all

Unified · Split

apps/server/src/workspace/Layers/WorkspaceFileSystem.test.ts+79−14
@@ -1,5 +1,5 @@
11 import * as NodeServices from "@effect/platform-node/NodeServices";
2−import { it, describe, expect } from "@effect/vitest";
2+import { assert, it, describe } from "@effect/vitest";
33 import * as Effect from "effect/Effect";
44 import * as FileSystem from "effect/FileSystem";
55 import * as Layer from "effect/Layer";
@@ -18,6 +18,8 @@ const ProjectLayer = WorkspaceFileSystemLive.pipe( · 12 unmodified lines
1818 Layer.provide(WorkspaceEntries.layer.pipe(Layer.provide(WorkspacePathsLive))),
1919 );
2020
21+const PROJECT_READ_FILE_MAX_BYTES = 1024 * 1024;
22+
2123 const TestLayer = Layer.empty.pipe(
2224 Layer.provideMerge(ProjectLayer),
2325 Layer.provideMerge(WorkspaceEntries.layer.pipe(Layer.provide(WorkspacePathsLive))),
@@ -52,6 +54,20 @@ const writeTextFile = Effect.fn("writeTextFile")(function* ( · 28 unmodified lines
5254 yield* fileSystem.writeFileString(absolutePath, contents).pipe(Effect.orDie);
5355 });
5456
57+const writeBinaryFile = Effect.fn("writeBinaryFile")(function* (
58+ cwd: string,
59+ relativePath: string,
60+ contents: Uint8Array,
61+) {
62+ const fileSystem = yield* FileSystem.FileSystem;
63+ const path = yield* Path.Path;
64+ const absolutePath = path.join(cwd, relativePath);
65+ yield* fileSystem
66+ .makeDirectory(path.dirname(absolutePath), { recursive: true })
67+ .pipe(Effect.orDie);
68+ yield* fileSystem.writeFile(absolutePath, contents).pipe(Effect.orDie);
69+});
70+
5571 it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (it) => {
5672 describe("readFile", () => {
5773 it.effect("reads UTF-8 files relative to the workspace root", () =>
@@ -65,7 +81,7 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 7 unmodified lines
6581 relativePath: "src/index.ts",
6682 });
6783
68− expect(result).toEqual({
84+ assert.deepStrictEqual(result, {
6985 relativePath: "src/index.ts",
7086 contents: "export const answer = 42;\n",
7187 byteLength: 26,
@@ -83,7 +99,8 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 11 unmodified lines
8399 .readFile({ cwd, relativePath: "../escape.md" })
84100 .pipe(Effect.flip);
85101
86− expect(error.message).toContain(
102+ assert.include(
103+ error.message,
87104 "Workspace file path must be relative to the project root: ../escape.md",
88105 );
89106 }),
@@ -106,7 +123,56 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 16 unmodified lines
106123 .readFile({ cwd, relativePath: "linked-secret.txt" })
107124 .pipe(Effect.flip);
108125
109− expect(error.message).toContain("resolves outside the project root");
126+ assert.include(error.message, "resolves outside the project root");
127+ }),
128+ );
129+
130+ it.effect("truncates files larger than the preview byte limit", () =>
131+ Effect.gen(function* () {
132+ const workspaceFileSystem = yield* WorkspaceFileSystem;
133+ const cwd = yield* makeTempDir;
134+ const contents = `${"a".repeat(PROJECT_READ_FILE_MAX_BYTES)}tail`;
135+ yield* writeTextFile(cwd, "large.txt", contents);
136+
137+ const result = yield* workspaceFileSystem.readFile({
138+ cwd,
139+ relativePath: "large.txt",
140+ });
141+
142+ assert.equal(result.contents.length, PROJECT_READ_FILE_MAX_BYTES);
143+ assert.equal(result.contents, "a".repeat(PROJECT_READ_FILE_MAX_BYTES));
144+ assert.equal(result.byteLength, PROJECT_READ_FILE_MAX_BYTES + 4);
145+ assert.isTrue(result.truncated);
146+ }),
147+ );
148+
149+ it.effect("rejects binary files", () =>
150+ Effect.gen(function* () {
151+ const workspaceFileSystem = yield* WorkspaceFileSystem;
152+ const cwd = yield* makeTempDir;
153+ yield* writeBinaryFile(cwd, "binary.bin", new Uint8Array([65, 0, 66]));
154+
155+ const error = yield* workspaceFileSystem
156+ .readFile({ cwd, relativePath: "binary.bin" })
157+ .pipe(Effect.flip);
158+
159+ assert.include(error.message, "Binary files cannot be previewed as text.");
160+ }),
161+ );
162+
163+ it.effect("rejects directories", () =>
164+ Effect.gen(function* () {
165+ const workspaceFileSystem = yield* WorkspaceFileSystem;
166+ const fileSystem = yield* FileSystem.FileSystem;
167+ const path = yield* Path.Path;
168+ const cwd = yield* makeTempDir;
169+ yield* fileSystem.makeDirectory(path.join(cwd, "src"), { recursive: true });
170+
171+ const error = yield* workspaceFileSystem
172+ .readFile({ cwd, relativePath: "src" })
173+ .pipe(Effect.flip);
174+
175+ assert.include(error.message, "Workspace path is not a file.");
110176 }),
111177 );
112178 });
@@ -127,8 +193,8 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 14 unmodified lines
127193 .readFileString(path.join(cwd, "plans/effect-rpc.md"))
128194 .pipe(Effect.orDie);
129195
130− expect(result).toEqual({ relativePath: "plans/effect-rpc.md" });
131− expect(saved).toBe("# Plan\n");
196+ assert.deepStrictEqual(result, { relativePath: "plans/effect-rpc.md" });
197+ assert.equal(saved, "# Plan\n");
132198 }),
133199 );
134200
@@ -140,9 +206,7 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 5 unmodified lines
140206 yield* writeTextFile(cwd, "src/existing.ts", "export {};\n");
141207
142208 const beforeWrite = yield* workspaceEntries.list({ cwd });
143− expect(beforeWrite.entries.some((entry) => entry.path === "plans/effect-rpc.md")).toBe(
144− false,
145− );
209+ assert.isFalse(beforeWrite.entries.some((entry) => entry.path === "plans/effect-rpc.md"));
146210
147211 yield* workspaceFileSystem.writeFile({
148212 cwd,
@@ -151,10 +215,10 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 2 unmodified lines
151215 });
152216
153217 const afterWrite = yield* workspaceEntries.list({ cwd });
154− expect(afterWrite.entries).toEqual(
155− expect.arrayContaining([expect.objectContaining({ path: "plans/effect-rpc.md" })]),
218+ assert.isTrue(
219+ afterWrite.entries.some((entry) => entry.path === "plans/effect-rpc.md"),
156220 );
157− expect(afterWrite.truncated).toBe(false);
221+ assert.isFalse(afterWrite.truncated);
158222 }),
159223 );
160224
@@ -173,7 +237,8 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 12 unmodified lines
173237 })
174238 .pipe(Effect.flip);
175239
176− expect(error.message).toContain(
240+ assert.include(
241+ error.message,
177242 "Workspace file path must be relative to the project root: ../escape.md",
178243 );
179244
@@ -181,7 +246,7 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 1 unmodified line
181246 const escapedStat = yield* fileSystem
182247 .stat(escapedPath)
183248 .pipe(Effect.orElseSucceed(() => null));
184− expect(escapedStat).toBeNull();
249+ assert.isNull(escapedStat);
185250 }),
186251 );
187252 });