Files
Rūdolfs Ošiņš 56e495ba8d Add unit tests for patch review logic and draft storage
Code review is the app's core workflow and had almost no coverage. A
mutation run checked that each test fails when the logic it covers breaks.
2026-10-01 18:20:24 +02:00

124 lines
3.0 KiB
TypeScript

import { describe, expect, test } from "vitest";
import { sliceForRange } from "@app/lib/patchSlice";
const preamble = [
"diff --git a/f.txt b/f.txt",
"index 1111111..2222222 100644",
"--- a/f.txt",
"+++ b/f.txt",
];
// Old side: l1..l10 on lines 1-10. New side: l1-l4, L5, L5b, l6-l10 on lines
// 1-11.
const hunk = [
"@@ -1,10 +1,11 @@ fn main",
" l1",
" l2",
" l3",
" l4",
"-l5",
"+L5",
"+L5b",
" l6",
" l7",
" l8",
" l9",
" l10",
];
function patch(...lines: string[]): string {
return [...preamble, ...lines, ""].join("\n");
}
describe("sliceForRange", () => {
test("cuts a new-side range down to its context and renumbers the hunk", () => {
expect(sliceForRange(patch(...hunk), "new", 5, 6, 1)).toBe(
patch("@@ -5,1 +5,2 @@", "-l5", "+L5", "+L5b"),
);
});
test("keeps three lines of context by default", () => {
expect(sliceForRange(patch(...hunk), "new", 5, 6)).toBe(
patch(
"@@ -3,5 +3,6 @@",
" l3",
" l4",
"-l5",
"+L5",
"+L5b",
" l6",
" l7",
),
);
});
test("cuts an old-side range", () => {
expect(sliceForRange(patch(...hunk), "old", 5, 6, 1)).toBe(
patch("@@ -4,2 +4,2 @@", " l4", "-l5", "+L5"),
);
});
test("covers a multi-line range with context on both ends", () => {
expect(sliceForRange(patch(...hunk), "new", 7, 9, 1)).toBe(
patch("@@ -6,3 +6,4 @@", "+L5b", " l6", " l7", " l8"),
);
});
test("keeps the hunk verbatim when the window covers all of it", () => {
expect(sliceForRange(patch(...hunk), "new", 5, 6, 20)).toBe(patch(...hunk));
});
test("writes 0 for a side the slice has no lines on", () => {
expect(sliceForRange(patch(...hunk), "new", 5, 7, 0)).toBe(
patch("@@ -0,0 +5,2 @@", "+L5", "+L5b"),
);
});
test("returns undefined when no hunk covers the range", () => {
expect(sliceForRange(patch(...hunk), "new", 50, 51)).toBeUndefined();
expect(sliceForRange(patch(...hunk), "old", 11, 12)).toBeUndefined();
});
test("uses the hunk that covers the range and keeps the preamble", () => {
const twoHunks = patch(
"@@ -1,2 +1,2 @@",
"-a",
"+A",
" b",
"@@ -20,3 +20,3 @@ fn second",
" x",
"-y",
"+Y",
" z",
);
expect(sliceForRange(twoHunks, "new", 21, 22, 0)).toBe(
patch("@@ -0,0 +21,1 @@", "+Y"),
);
expect(sliceForRange(twoHunks, "new", 21, 22, 5)).toBe(
patch("@@ -20,3 +20,3 @@ fn second", " x", "-y", "+Y", " z"),
);
});
test("reads a hunk header without counts", () => {
expect(sliceForRange(patch("@@ -3 +3 @@", "-c", "+C"), "new", 3, 4)).toBe(
patch("@@ -3 +3 @@", "-c", "+C"),
);
});
test("a no-newline marker doesn't shift the line numbers", () => {
const noNewline = patch(
"@@ -1,2 +1,2 @@",
"-a",
"\\ No newline at end of file",
"+A",
" b",
);
expect(sliceForRange(noNewline, "new", 2, 3, 0)).toBe(
patch("@@ -2,1 +2,1 @@", " b"),
);
});
});