Showing the changes to apps/server/src/workspace/WorkspaceFileSystem.test.ts (1 of 2 files). Show all
Unified · Split
| @@ -1,9 +1,11 @@ | ||
| 1 | 1 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 2 | −import { it, describe, expect } from "@effect/vitest"; | |
| 2 | +import { assert, describe, it } from "@effect/vitest"; | |
| 3 | 3 | import * as Effect from "effect/Effect"; |
| 4 | 4 | import * as FileSystem from "effect/FileSystem"; |
| 5 | 5 | import * as Layer from "effect/Layer"; |
| 6 | +import * as Option from "effect/Option"; | |
| 6 | 7 | import * as Path from "effect/Path"; |
| 8 | +import * as PlatformError from "effect/PlatformError"; | |
| 7 | 9 | |
| 8 | 10 | import * as ServerConfig from "../config.ts"; |
| 9 | 11 | import * as VcsDriverRegistry from "../vcs/VcsDriverRegistry.ts"; |
| @@ -64,7 +66,7 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 54 unmodified lines | ||
| 64 | 66 | relativePath: "src/index.ts", |
| 65 | 67 | }); |
| 66 | 68 | |
| 67 | − expect(result).toEqual({ | |
| 69 | + assert.deepStrictEqual(result, { | |
| 68 | 70 | relativePath: "src/index.ts", |
| 69 | 71 | contents: "export const answer = 42;\n", |
| 70 | 72 | byteLength: 26, |
| @@ -82,7 +84,8 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 11 unmodified lines | ||
| 82 | 84 | .readFile({ cwd, relativePath: "../escape.md" }) |
| 83 | 85 | .pipe(Effect.flip); |
| 84 | 86 | |
| 85 | − expect(error.message).toContain( | |
| 87 | + assert.include( | |
| 88 | + error.message, | |
| 86 | 89 | "Workspace file path must be relative to the project root: ../escape.md", |
| 87 | 90 | ); |
| 88 | 91 | }), |
| @@ -107,14 +110,14 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 18 unmodified lines | ||
| 107 | 110 | const resolvedWorkspaceRoot = yield* fileSystem.realPath(cwd); |
| 108 | 111 | const resolvedPath = yield* fileSystem.realPath(path.join(outsideDir, "secret.txt")); |
| 109 | 112 | |
| 110 | − expect(error).toBeInstanceOf(WorkspaceFileSystem.WorkspaceFilePathEscapeError); | |
| 111 | − expect(error).toMatchObject({ | |
| 113 | + assert.strictEqual(error._tag, "WorkspaceFilePathEscapeError"); | |
| 114 | + assert.deepInclude(error, { | |
| 112 | 115 | workspaceRoot: cwd, |
| 113 | 116 | relativePath: "linked-secret.txt", |
| 114 | 117 | resolvedWorkspaceRoot, |
| 115 | 118 | resolvedPath, |
| 116 | 119 | }); |
| 117 | − expect("cause" in error).toBe(false); | |
| 120 | + assert.notProperty(error, "cause"); | |
| 118 | 121 | }), |
| 119 | 122 | ); |
| 120 | 123 | |
| @@ -131,13 +134,13 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 10 unmodified lines | ||
| 131 | 134 | .pipe(Effect.flip); |
| 132 | 135 | const resolvedPath = yield* fileSystem.realPath(path.join(cwd, "src")); |
| 133 | 136 | |
| 134 | − expect(error).toBeInstanceOf(WorkspaceFileSystem.WorkspacePathNotFileError); | |
| 135 | − expect(error).toMatchObject({ | |
| 137 | + assert.strictEqual(error._tag, "WorkspacePathNotFileError"); | |
| 138 | + assert.deepInclude(error, { | |
| 136 | 139 | workspaceRoot: cwd, |
| 137 | 140 | relativePath: "src", |
| 138 | 141 | resolvedPath, |
| 139 | 142 | }); |
| 140 | − expect("cause" in error).toBe(false); | |
| 143 | + assert.notProperty(error, "cause"); | |
| 141 | 144 | }), |
| 142 | 145 | ); |
| 143 | 146 | |
| @@ -155,14 +158,31 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 11 unmodified lines | ||
| 155 | 158 | .pipe(Effect.flip); |
| 156 | 159 | const resolvedPath = yield* fileSystem.realPath(absolutePath); |
| 157 | 160 | |
| 158 | − expect(error).toBeInstanceOf(WorkspaceFileSystem.WorkspaceBinaryFileError); | |
| 159 | − expect(error).toMatchObject({ | |
| 161 | + assert.strictEqual(error._tag, "WorkspaceBinaryFileError"); | |
| 162 | + assert.deepInclude(error, { | |
| 160 | 163 | workspaceRoot: cwd, |
| 161 | 164 | relativePath: "asset.bin", |
| 162 | 165 | resolvedPath, |
| 163 | 166 | }); |
| 164 | − expect("cause" in error).toBe(false); | |
| 165 | − expect("contents" in error).toBe(false); | |
| 167 | + assert.notProperty(error, "cause"); | |
| 168 | + assert.notProperty(error, "contents"); | |
| 169 | + }), | |
| 170 | + ); | |
| 171 | + | |
| 172 | + it.effect("reads at most the preview limit", () => | |
| 173 | + Effect.gen(function* () { | |
| 174 | + const workspaceFileSystem = yield* WorkspaceFileSystem.WorkspaceFileSystem; | |
| 175 | + const cwd = yield* makeTempDir; | |
| 176 | + yield* writeTextFile(cwd, "large.txt", "a".repeat(1024 * 1024 + 1)); | |
| 177 | + | |
| 178 | + const result = yield* workspaceFileSystem.readFile({ | |
| 179 | + cwd, | |
| 180 | + relativePath: "large.txt", | |
| 181 | + }); | |
| 182 | + | |
| 183 | + assert.strictEqual(result.contents.length, 1024 * 1024); | |
| 184 | + assert.strictEqual(result.byteLength, 1024 * 1024 + 1); | |
| 185 | + assert.isTrue(result.truncated); | |
| 166 | 186 | }), |
| 167 | 187 | ); |
| 168 | 188 | |
| @@ -177,16 +197,16 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 8 unmodified lines | ||
| 177 | 197 | .readFile({ cwd, relativePath: "missing.txt" }) |
| 178 | 198 | .pipe(Effect.flip); |
| 179 | 199 | |
| 180 | − expect(error).toBeInstanceOf(WorkspaceFileSystem.WorkspaceFileSystemOperationError); | |
| 181 | − expect(error).toMatchObject({ | |
| 200 | + assert.strictEqual(error._tag, "WorkspaceFileSystemOperationError"); | |
| 201 | + assert.deepInclude(error, { | |
| 182 | 202 | workspaceRoot: cwd, |
| 183 | 203 | relativePath: "missing.txt", |
| 184 | 204 | resolvedPath, |
| 185 | 205 | operationPath: resolvedPath, |
| 186 | 206 | operation: "realpath-target", |
| 187 | 207 | }); |
| 188 | − expect(error.cause).toBeInstanceOf(Error); | |
| 189 | − expect((error.cause as NodeJS.ErrnoException).code).toBe("ENOENT"); | |
| 208 | + assert.instanceOf(error.cause, PlatformError.PlatformError); | |
| 209 | + assert.strictEqual((error.cause as PlatformError.PlatformError).reason._tag, "NotFound"); | |
| 190 | 210 | }), |
| 191 | 211 | ); |
| 192 | 212 | }); |
| @@ -207,8 +227,8 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 14 unmodified lines | ||
| 207 | 227 | .readFileString(path.join(cwd, "plans/effect-rpc.md")) |
| 208 | 228 | .pipe(Effect.orDie); |
| 209 | 229 | |
| 210 | − expect(result).toEqual({ relativePath: "plans/effect-rpc.md" }); | |
| 211 | − expect(saved).toBe("# Plan\n"); | |
| 230 | + assert.deepStrictEqual(result, { relativePath: "plans/effect-rpc.md" }); | |
| 231 | + assert.strictEqual(saved, "# Plan\n"); | |
| 212 | 232 | }), |
| 213 | 233 | ); |
| 214 | 234 | |
| @@ -220,8 +240,8 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 5 unmodified lines | ||
| 220 | 240 | yield* writeTextFile(cwd, "src/existing.ts", "export {};\n"); |
| 221 | 241 | |
| 222 | 242 | const beforeWrite = yield* workspaceEntries.list({ cwd }); |
| 223 | − expect(beforeWrite.entries.some((entry) => entry.path === "plans/effect-rpc.md")).toBe( | |
| 224 | − false, | |
| 243 | + assert.isFalse( | |
| 244 | + beforeWrite.entries.some((entry) => entry.path === "plans/effect-rpc.md"), | |
| 225 | 245 | ); |
| 226 | 246 | |
| 227 | 247 | yield* workspaceFileSystem.writeFile({ |
| @@ -231,10 +251,10 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 3 unmodified lines | ||
| 231 | 251 | }); |
| 232 | 252 | |
| 233 | 253 | const afterWrite = yield* workspaceEntries.list({ cwd }); |
| 234 | − expect(afterWrite.entries).toEqual( | |
| 235 | − expect.arrayContaining([expect.objectContaining({ path: "plans/effect-rpc.md" })]), | |
| 254 | + assert.isTrue( | |
| 255 | + afterWrite.entries.some((entry) => entry.path === "plans/effect-rpc.md"), | |
| 236 | 256 | ); |
| 237 | − expect(afterWrite.truncated).toBe(false); | |
| 257 | + assert.isFalse(afterWrite.truncated); | |
| 238 | 258 | }), |
| 239 | 259 | ); |
| 240 | 260 | |
| @@ -253,15 +273,14 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 12 unmodified lines | ||
| 253 | 273 | }) |
| 254 | 274 | .pipe(Effect.flip); |
| 255 | 275 | |
| 256 | − expect(error.message).toContain( | |
| 276 | + assert.include( | |
| 277 | + error.message, | |
| 257 | 278 | "Workspace file path must be relative to the project root: ../escape.md", |
| 258 | 279 | ); |
| 259 | 280 | |
| 260 | 281 | const escapedPath = path.resolve(cwd, "..", "escape.md"); |
| 261 | − const escapedStat = yield* fileSystem | |
| 262 | − .stat(escapedPath) | |
| 263 | − .pipe(Effect.orElseSucceed(() => null)); | |
| 264 | − expect(escapedStat).toBeNull(); | |
| 282 | + const escapedStat = yield* fileSystem.stat(escapedPath).pipe(Effect.option); | |
| 283 | + assert.isTrue(Option.isNone(escapedStat)); | |
| 265 | 284 | }), |
| 266 | 285 | ); |
| 267 | 286 | }); |