Files
claude-code/src/utils/__tests__/diff.test.ts
2026-04-02 14:44:56 +08:00

118 lines
3.9 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { adjustHunkLineNumbers, getPatchFromContents } from "../diff";
describe("adjustHunkLineNumbers", () => {
test("shifts hunk line numbers by offset", () => {
const hunks = [
{ oldStart: 1, oldLines: 3, newStart: 1, newLines: 4, lines: [" a", "-b", "+c", "+d", " e"] },
] as any[];
const result = adjustHunkLineNumbers(hunks, 10);
expect(result[0].oldStart).toBe(11);
expect(result[0].newStart).toBe(11);
});
test("returns original hunks for zero offset", () => {
const hunks = [
{ oldStart: 5, oldLines: 2, newStart: 5, newLines: 2, lines: [] },
] as any[];
const result = adjustHunkLineNumbers(hunks, 0);
expect(result).toBe(hunks); // same reference
});
test("handles negative offset", () => {
const hunks = [
{ oldStart: 10, oldLines: 2, newStart: 10, newLines: 2, lines: [] },
] as any[];
const result = adjustHunkLineNumbers(hunks, -5);
expect(result[0].oldStart).toBe(5);
expect(result[0].newStart).toBe(5);
});
test("handles empty hunks array", () => {
expect(adjustHunkLineNumbers([], 10)).toEqual([]);
});
});
describe("getPatchFromContents", () => {
test("returns hunks for different content", () => {
const hunks = getPatchFromContents({
filePath: "test.txt",
oldContent: "hello\nworld",
newContent: "hello\nplanet",
});
expect(hunks.length).toBe(1);
const allLines = hunks[0].lines;
expect(allLines).toContain("-world");
expect(allLines).toContain("+planet");
});
test("returns empty hunks for identical content", () => {
const hunks = getPatchFromContents({
filePath: "test.txt",
oldContent: "same content",
newContent: "same content",
});
expect(hunks).toEqual([]);
});
test("handles content with ampersands", () => {
const hunks = getPatchFromContents({
filePath: "test.txt",
oldContent: "a & b",
newContent: "a & c",
});
expect(hunks.length).toBeGreaterThan(0);
// Verify ampersands are unescaped in the output
const allLines = hunks.flatMap((h: any) => h.lines);
expect(allLines.some((l: string) => l.includes("&"))).toBe(true);
});
test("handles empty old content (new file)", () => {
const hunks = getPatchFromContents({
filePath: "test.txt",
oldContent: "",
newContent: "new content",
});
expect(hunks.length).toBeGreaterThan(0);
const allLines = hunks.flatMap((h: any) => h.lines);
expect(allLines.some((l: string) => l.startsWith("+"))).toBe(true);
});
test("handles content with dollar signs", () => {
const hunks = getPatchFromContents({
filePath: "test.txt",
oldContent: "price: $5",
newContent: "price: $10",
});
expect(hunks.length).toBeGreaterThan(0);
const allLines = hunks.flatMap((h: any) => h.lines);
expect(allLines.some((l: string) => l.includes("$"))).toBe(true);
// Verify dollar signs are unescaped (not the token)
expect(allLines.some((l: string) => l.includes("<<:DOLLAR_TOKEN:>>"))).toBe(false);
});
test("handles deleting all content", () => {
const hunks = getPatchFromContents({
filePath: "test.txt",
oldContent: "line1\nline2\nline3",
newContent: "",
});
expect(hunks.length).toBeGreaterThan(0);
const allLines = hunks.flatMap((h: any) => h.lines);
expect(allLines.some((l: string) => l.startsWith("-"))).toBe(true);
expect(allLines.every((l: string) => l.startsWith("-") || l.startsWith(" ") || l.startsWith("\\"))).toBe(true);
});
test("ignoreWhitespace treats indentation changes as identical", () => {
const old = "function foo() {\n return 42;\n}\n";
const nw = "function foo() {\n\treturn 42;\n}\n";
const hunks = getPatchFromContents({
filePath: "test.txt",
oldContent: old,
newContent: nw,
ignoreWhitespace: true,
});
expect(hunks).toEqual([]);
});
});