Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge branch 'worktree-agent-a432c4ed9deb834b1' | 1 | import assert from "node:assert/strict"; |
| 2 | import { afterEach, test } from "node:test"; | |
| 3 | ||
| 4 | import type { FileDiff } from "@g1t/contracts"; | |
| 5 | ||
| 6 | import { forgetFiles, loadFile, peekFile } from "./diff-files.ts"; | |
| 7 | ||
| 8 | const SOURCE = "/acme/web/diff-files.json?base=&head=" + "b".repeat(40); | |
| 9 | ||
| 10 | const file = (path: string): FileDiff => ({ path, status: "modified", additions: 1, deletions: 0, binary: false, hunks: [] }); | |
| 11 | ||
| 12 | /** A stand-in for fetch that answers with the paths asked for, and notes each address. */ | |
| 13 | function server(fail = false) { | |
| 14 | const asked: string[] = []; | |
| 15 | const fetcher = (async (url: string) => { | |
| 16 | asked.push(url); | |
| 17 | if (fail) return new Response("no", { status: 500 }); | |
| 18 | const paths = new URL(url, "https://g1t.test").searchParams.getAll("path").filter((path) => path !== "gone.ts"); | |
| 19 | return Response.json({ files: paths.map(file) }); | |
| 20 | }) as typeof fetch; | |
| 21 | return { asked, fetcher }; | |
| 22 | } | |
| 23 | ||
| 24 | afterEach(forgetFiles); | |
| 25 | ||
| 26 | test("files asked for together are fetched in one request, and once", async () => { | |
| 27 | const { asked, fetcher } = server(); | |
| 28 | const [a, b, gone] = await Promise.all([ | |
| 29 | loadFile(SOURCE, "src/a.ts", { fetcher }), | |
| 30 | loadFile(SOURCE, "src/b c.ts", { fetcher }), | |
| 31 | loadFile(SOURCE, "gone.ts", { fetcher }), | |
| 32 | ]); | |
| 33 | assert.equal(asked.length, 1); | |
| 34 | assert.ok(asked[0]!.startsWith(SOURCE + "&path=src%2Fa.ts&path=src%2Fb%20c.ts")); | |
| 35 | assert.equal(a?.path, "src/a.ts"); | |
| 36 | assert.equal(b?.path, "src/b c.ts"); | |
| 37 | // No longer in the change: null, not an error. | |
| 38 | assert.equal(gone, null); | |
| 39 | // Asked again, or drawn again after a refresh: from what was fetched. | |
| 40 | assert.equal(await loadFile(SOURCE, "src/a.ts", { fetcher }), a); | |
| 41 | assert.equal(peekFile(SOURCE, "src/a.ts"), a); | |
| 42 | assert.equal(peekFile(SOURCE, "never.ts"), undefined); | |
| 43 | assert.equal(asked.length, 1); | |
| 44 | }); | |
| 45 | ||
| 46 | test("many files at once go 20 to a request", async () => { | |
| 47 | const { asked, fetcher } = server(); | |
| 48 | await Promise.all(Array.from({ length: 45 }, (_, n) => loadFile(SOURCE, `f${n}`, { fetcher }))); | |
| 49 | assert.equal(asked.length, 3); | |
| 50 | }); | |
| 51 | ||
| 52 | test("the files after one come with it, and are not asked for again", async () => { | |
| 53 | const { asked, fetcher } = server(); | |
| 54 | await loadFile(SOURCE, "a", { also: ["b", "c"], fetcher }); | |
| 55 | assert.equal(asked.length, 1); | |
| 56 | assert.ok(asked[0]!.endsWith("&path=b&path=c&path=a")); | |
| 57 | assert.equal(peekFile(SOURCE, "c")?.path, "c"); | |
| 58 | // Reached later, they are there; one already fetched is not asked for again. | |
| 59 | assert.equal((await loadFile(SOURCE, "c", { also: ["a", "d"], fetcher }))?.path, "c"); | |
| 60 | await loadFile(SOURCE, "d", { fetcher }); | |
| 61 | assert.equal(asked.length, 2); | |
| 62 | assert.ok(asked[1]!.endsWith("?base=&head=" + "b".repeat(40) + "&path=d")); | |
| 63 | }); | |
| 64 | ||
| 65 | test("a failed fetch is an error, and is tried again when asked again", async () => { | |
| 66 | const failing = server(true); | |
| 67 | await assert.rejects(loadFile(SOURCE, "src/a.ts", { fetcher: failing.fetcher })); | |
| 68 | assert.equal(peekFile(SOURCE, "src/a.ts"), undefined); | |
| 69 | const working = server(); | |
| 70 | assert.equal((await loadFile(SOURCE, "src/a.ts", { fetcher: working.fetcher }))?.path, "src/a.ts"); | |
| 71 | assert.equal(working.asked.length, 1); | |
| 72 | }); |
This file's history is long; its oldest lines are credited to the oldest commit read.