|
| 1 | +import { filterDependenciesByAssignments } from "$lib/hunks/dependencies"; |
| 2 | +import { describe, expect, test } from "vitest"; |
| 3 | +import type { HunkDependencies } from "$lib/hunks/dependencies"; |
| 4 | +import type { HunkAssignment } from "$lib/hunks/hunk"; |
| 5 | + |
| 6 | +function makeDeps( |
| 7 | + entries: Array<{ path: string; newStart: number; newLines: number }>, |
| 8 | +): HunkDependencies { |
| 9 | + return { |
| 10 | + diffs: entries.map(({ path, newStart, newLines }) => [ |
| 11 | + path, |
| 12 | + { oldStart: 1, oldLines: 1, newStart, newLines, diff: "" }, |
| 13 | + [{ target: { type: "stack", subject: "stack-1" }, commitId: "abc" }], |
| 14 | + ]), |
| 15 | + errors: [], |
| 16 | + }; |
| 17 | +} |
| 18 | + |
| 19 | +function makeAssignment( |
| 20 | + path: string, |
| 21 | + stackId: string | null, |
| 22 | + newStart: number, |
| 23 | + newLines: number, |
| 24 | +): HunkAssignment { |
| 25 | + return { |
| 26 | + id: null, |
| 27 | + path, |
| 28 | + pathBytes: [], |
| 29 | + stackId, |
| 30 | + hunkHeader: { oldStart: 1, oldLines: 1, newStart, newLines }, |
| 31 | + lineNumsAdded: null, |
| 32 | + lineNumsRemoved: null, |
| 33 | + }; |
| 34 | +} |
| 35 | + |
| 36 | +describe("filterDependenciesByAssignments", () => { |
| 37 | + describe("unassigned view (stackId = undefined)", () => { |
| 38 | + test("keeps dependency overlapping an unassigned hunk", () => { |
| 39 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); |
| 40 | + const assignments = [makeAssignment("a.ts", null, 10, 5)]; |
| 41 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 42 | + expect(result.diffs).toHaveLength(1); |
| 43 | + }); |
| 44 | + |
| 45 | + test("drops dependency overlapping a stack-assigned hunk", () => { |
| 46 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); |
| 47 | + const assignments = [makeAssignment("a.ts", "stack-1", 10, 5)]; |
| 48 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 49 | + expect(result.diffs).toHaveLength(0); |
| 50 | + }); |
| 51 | + |
| 52 | + test("keeps only the entry overlapping the unassigned hunk when mixed", () => { |
| 53 | + const deps = makeDeps([ |
| 54 | + { path: "a.ts", newStart: 10, newLines: 5 }, // overlaps unassigned hunk |
| 55 | + { path: "a.ts", newStart: 50, newLines: 5 }, // overlaps stack-assigned hunk |
| 56 | + ]); |
| 57 | + const assignments = [ |
| 58 | + makeAssignment("a.ts", null, 10, 5), |
| 59 | + makeAssignment("a.ts", "stack-1", 50, 5), |
| 60 | + ]; |
| 61 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 62 | + expect(result.diffs).toHaveLength(1); |
| 63 | + expect(result.diffs[0]![1].newStart).toBe(10); |
| 64 | + }); |
| 65 | + }); |
| 66 | + |
| 67 | + describe("stack lane view (stackId = 'stack-1')", () => { |
| 68 | + test("keeps dependency overlapping a hunk assigned to this stack", () => { |
| 69 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); |
| 70 | + const assignments = [makeAssignment("a.ts", "stack-1", 10, 5)]; |
| 71 | + const result = filterDependenciesByAssignments(deps, assignments, "stack-1"); |
| 72 | + expect(result.diffs).toHaveLength(1); |
| 73 | + }); |
| 74 | + |
| 75 | + test("drops dependency overlapping an unassigned hunk", () => { |
| 76 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); |
| 77 | + const assignments = [makeAssignment("a.ts", null, 10, 5)]; |
| 78 | + const result = filterDependenciesByAssignments(deps, assignments, "stack-1"); |
| 79 | + expect(result.diffs).toHaveLength(0); |
| 80 | + }); |
| 81 | + |
| 82 | + test("drops dependency overlapping a hunk from a different stack", () => { |
| 83 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); |
| 84 | + const assignments = [makeAssignment("a.ts", "stack-2", 10, 5)]; |
| 85 | + const result = filterDependenciesByAssignments(deps, assignments, "stack-1"); |
| 86 | + expect(result.diffs).toHaveLength(0); |
| 87 | + }); |
| 88 | + }); |
| 89 | + |
| 90 | + describe("range overlap", () => { |
| 91 | + test("overlapping ranges match", () => { |
| 92 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); // [10, 15) |
| 93 | + const assignments = [makeAssignment("a.ts", null, 12, 5)]; // [12, 17) |
| 94 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 95 | + expect(result.diffs).toHaveLength(1); |
| 96 | + }); |
| 97 | + |
| 98 | + test("adjacent but non-overlapping ranges do not match", () => { |
| 99 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); // [10, 15) |
| 100 | + const assignments = [makeAssignment("a.ts", null, 15, 5)]; // [15, 20) |
| 101 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 102 | + expect(result.diffs).toHaveLength(0); |
| 103 | + }); |
| 104 | + |
| 105 | + test("0-line dependency hunk treated as single-line point", () => { |
| 106 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 0 }]); // treated as [10, 11) |
| 107 | + const assignments = [makeAssignment("a.ts", null, 10, 5)]; // [10, 15) |
| 108 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 109 | + expect(result.diffs).toHaveLength(1); |
| 110 | + }); |
| 111 | + |
| 112 | + test("0-line assignment hunk treated as single-line point", () => { |
| 113 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); // [10, 15) |
| 114 | + const assignments = [makeAssignment("a.ts", null, 10, 0)]; // treated as [10, 11) |
| 115 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 116 | + expect(result.diffs).toHaveLength(1); |
| 117 | + }); |
| 118 | + |
| 119 | + test("no match when dependency is entirely before assignment", () => { |
| 120 | + const deps = makeDeps([{ path: "a.ts", newStart: 5, newLines: 3 }]); // [5, 8) |
| 121 | + const assignments = [makeAssignment("a.ts", null, 10, 5)]; // [10, 15) |
| 122 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 123 | + expect(result.diffs).toHaveLength(0); |
| 124 | + }); |
| 125 | + }); |
| 126 | + |
| 127 | + describe("path matching", () => { |
| 128 | + test("only matches entries with the same path", () => { |
| 129 | + const deps = makeDeps([{ path: "a.ts", newStart: 10, newLines: 5 }]); |
| 130 | + const assignments = [makeAssignment("b.ts", null, 10, 5)]; |
| 131 | + const result = filterDependenciesByAssignments(deps, assignments, undefined); |
| 132 | + expect(result.diffs).toHaveLength(0); |
| 133 | + }); |
| 134 | + }); |
| 135 | + |
| 136 | + describe("preserves errors", () => { |
| 137 | + test("errors field is passed through unchanged", () => { |
| 138 | + const deps: HunkDependencies = { |
| 139 | + diffs: [], |
| 140 | + errors: [{ errorMessage: "oops", stackId: "s", commitId: "c", path: "a.ts" }], |
| 141 | + }; |
| 142 | + const result = filterDependenciesByAssignments(deps, [], undefined); |
| 143 | + expect(result.errors).toEqual(deps.errors); |
| 144 | + }); |
| 145 | + }); |
| 146 | +}); |
0 commit comments