Public: anyone can read this; the crew can change it.

A test pins a limb's seat: `parseSeat` takes only `top:N` or `<issue>:N`, and moving a limb then restoring its old seat puts the group back #6635

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/6624-a-test-pins-a-limb-s-seat-parseseat-take → main 1 commit fork

  • Merged. scout/6624-a-test-pins-a-limb-s-seat-parseseat-take was merged into main as 3bf0d17.

Review

Sign in to review this change.
1 file changed +112 −0
test/limb-seats.test.ts added +112
@@ -0,0 +1,112 @@
1 /**
2 * A limb's seat (#6624): `parseSeat` takes only `top:N` or `<issue>:N`, and
3 * moving a limb then restoring the seat it had puts the group back.
4 */
5 import { afterAll, beforeAll, describe, expect, test } from "bun:test";
6 import { mkdtemp, rm } from "node:fs/promises";
7 import { tmpdir } from "node:os";
8 import { join } from "node:path";
9 import { createApp, type App } from "../src/app.ts";
10 import { linkIssue } from "../src/actions/dependencies.ts";
11 import { openIssue } from "../src/actions/issues.ts";
12 import { createRepo } from "../src/actions/repos.ts";
13 import { moveLimb, parseSeat, seating } from "../src/core/limb_seats.ts";
14 import { getIssueById, type Issue } from "../src/core/issues.ts";
15 import { getRepoById, type Repo } from "../src/core/repos.ts";
16 import { createUser, getUserByName } from "../src/core/users.ts";
17
18 describe("parseSeat", () => {
19 test("takes a group and a place", () => {
20 expect(parseSeat("top:1")).toEqual({ group: "top", place: 1 });
21 expect(parseSeat("42:3")).toEqual({ group: "42", place: 3 });
22 });
23
24 test("refuses everything else", () => {
25 for (const bad of ["top:0", "0:1", "01:1", "top:", ":1", "top:1x", "top:1234567"])
26 expect(parseSeat(bad)).toBeUndefined();
27 expect(parseSeat(3)).toBeUndefined();
28 expect(parseSeat(undefined)).toBeUndefined();
29 });
30 });
31
32 describe("moving a limb", () => {
33 let dataDir: string;
34 let app: App;
35 let repo: Repo;
36 let parent: Issue;
37 let limbs: Issue[];
38
39 const fresh = () => getRepoById(app.db, repo.id)!;
40 const current = (i: Issue) => getIssueById(app.db, i.id)!;
41 const open = (title: string): Issue => {
42 const o = openIssue(app, getUserByName(app.db, "alice")!, fresh(), { title });
43 if (!o.ok) throw new Error(String(o.error));
44 return o.value;
45 };
46 const link = (waiter: Issue, on: Issue): void => {
47 const l = linkIssue(
48 app,
49 getUserByName(app.db, "alice")!,
50 fresh(),
51 current(waiter),
52 current(on),
53 );
54 if (!l.ok) throw new Error(String(l.error));
55 };
56 const order = (): number[] => {
57 const seats = seating(app.db, fresh());
58 const byId = new Map(seats.graph.issues.map((i) => [i.id, i.number]));
59 return seats.order(String(parent.number)).map((id) => byId.get(id)!);
60 };
61
62 beforeAll(async () => {
63 dataDir = await mkdtemp(join(tmpdir(), "forge-limb-seats-"));
64 app = createApp({ dataDir, port: 0 });
65 const made = await createUser(app.db, {
66 origin: "seed",
67 trusted: true,
68 username: "alice",
69 email: "[email protected]",
70 password: "a-good-passphrase",
71 adminIfFirst: true,
72 });
73 if (!made.ok) throw new Error(made.error);
74 const r = await createRepo(app, getUserByName(app.db, "alice")!, {
75 name: "seats",
76 visibility: "public",
77 });
78 if (!r.ok) throw new Error(String(r.error));
79 repo = r.value;
80 parent = open("The issue whose limbs these are");
81 limbs = [open("One"), open("Two"), open("Three")];
82 for (const limb of limbs) {
83 link(parent, limb);
84 link(limb, open(`A leaf under ${limb.title}`));
85 }
86 }, 60_000);
87
88 afterAll(async () => {
89 app.close();
90 await rm(dataDir, { recursive: true, force: true });
91 });
92
93 test("the third to place 1 reads 3, 1, 2; its old seat restores 1, 2, 3", () => {
94 const [one, two, three] = limbs.map((l) => l.number);
95 expect(order()).toEqual([one!, two!, three!]);
96 const group = String(parent.number);
97 const before = seating(app.db, fresh()).of(limbs[2]!.id);
98 expect(before).toContain(`${group}:3`);
99 expect(moveLimb(app.db, fresh(), limbs[2]!.id, { group, place: 1 })).toBeUndefined();
100 expect(order()).toEqual([three!, one!, two!]);
101 const back = parseSeat(`${group}:3`)!;
102 expect(moveLimb(app.db, fresh(), limbs[2]!.id, back)).toBeUndefined();
103 expect(order()).toEqual([one!, two!, three!]);
104 expect(app.db.query("SELECT * FROM limb_place").all()).toEqual([]);
105 });
106
107 test("refuses a place past the end and a stranger", () => {
108 const group = String(parent.number);
109 expect(moveLimb(app.db, fresh(), limbs[0]!.id, { group, place: 4 })).toContain("only 3");
110 expect(moveLimb(app.db, fresh(), parent.id, { group, place: 1 })).toContain("not one");
111 });
112 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs