Skip to content
72 linesCodeBlameRaw

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'1import assert from "node:assert/strict";
2import { afterEach, test } from "node:test";
3
4import type { FileDiff } from "@g1t/contracts";
5
6import { forgetFiles, loadFile, peekFile } from "./diff-files.ts";
7
8const SOURCE = "/acme/web/diff-files.json?base=&head=" + "b".repeat(40);
9
10const 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. */
13function 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
24afterEach(forgetFiles);
25
26test("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
46test("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
52test("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
65test("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.