197 lines
6.9 KiB
TypeScript
197 lines
6.9 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { splitDiffBlocks, hasDiffBlocks } from "./diff-blocks";
|
|
|
|
// ─── hasDiffBlocks ─────────────────────────────────────────────────
|
|
|
|
describe("hasDiffBlocks", () => {
|
|
it("returns true when diff block is present", () => {
|
|
expect(hasDiffBlocks("```diff\n-old\n+new\n```")).toBe(true);
|
|
});
|
|
|
|
it("returns false for plain text", () => {
|
|
expect(hasDiffBlocks("Hello world")).toBe(false);
|
|
});
|
|
|
|
it("returns false for regular code block", () => {
|
|
expect(hasDiffBlocks("```js\nconst x = 1;\n```")).toBe(false);
|
|
});
|
|
|
|
it("returns true for partial match (streaming content)", () => {
|
|
expect(hasDiffBlocks("Some text then ```diff")).toBe(true);
|
|
});
|
|
|
|
it("returns true for multiple diff blocks", () => {
|
|
expect(hasDiffBlocks("```diff\n-a\n```\ntext\n```diff\n+b\n```")).toBe(true);
|
|
});
|
|
|
|
it("returns false for empty string", () => {
|
|
expect(hasDiffBlocks("")).toBe(false);
|
|
});
|
|
|
|
it("returns false for 'diff' without backtick fence", () => {
|
|
expect(hasDiffBlocks("This is a diff of two files")).toBe(false);
|
|
});
|
|
});
|
|
|
|
// ─── splitDiffBlocks ───────────────────────────────────────────────
|
|
|
|
describe("splitDiffBlocks", () => {
|
|
it("returns text segment for plain text with no blocks", () => {
|
|
const result = splitDiffBlocks("Hello world");
|
|
expect(result).toEqual([{ type: "text", text: "Hello world" }]);
|
|
});
|
|
|
|
it("returns empty array for whitespace-only text", () => {
|
|
expect(splitDiffBlocks(" ")).toEqual([]);
|
|
});
|
|
|
|
it("parses a single diff block", () => {
|
|
const text = "```diff\n-old line\n+new line\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].type).toBe("diff-artifact");
|
|
if (result[0].type === "diff-artifact") {
|
|
expect(result[0].diff).toBe("-old line\n+new line");
|
|
}
|
|
});
|
|
|
|
it("splits text before and after a diff block", () => {
|
|
const text = "Before text\n\n```diff\n-old\n+new\n```\n\nAfter text";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(3);
|
|
expect(result[0]).toEqual({ type: "text", text: "Before text\n\n" });
|
|
expect(result[1].type).toBe("diff-artifact");
|
|
expect(result[2]).toEqual({ type: "text", text: "\n\nAfter text" });
|
|
});
|
|
|
|
it("handles multiple diff blocks", () => {
|
|
const text = "First:\n```diff\n-a\n+b\n```\nSecond:\n```diff\n-c\n+d\n```\nDone.";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(5);
|
|
expect(result[0].type).toBe("text");
|
|
expect(result[1].type).toBe("diff-artifact");
|
|
expect(result[2].type).toBe("text");
|
|
expect(result[3].type).toBe("diff-artifact");
|
|
expect(result[4].type).toBe("text");
|
|
});
|
|
|
|
it("handles diff block at the very beginning", () => {
|
|
const text = "```diff\n-x\n+y\n```\nSome text after.";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(2);
|
|
expect(result[0].type).toBe("diff-artifact");
|
|
expect(result[1].type).toBe("text");
|
|
});
|
|
|
|
it("handles diff block at the very end", () => {
|
|
const text = "Some text before\n```diff\n-x\n+y\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(2);
|
|
expect(result[0].type).toBe("text");
|
|
expect(result[1].type).toBe("diff-artifact");
|
|
});
|
|
|
|
it("handles empty diff block (becomes text)", () => {
|
|
const text = "```diff\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].type).toBe("text");
|
|
expect(result[0]).toEqual({ type: "text", text: "```diff\n```" });
|
|
});
|
|
|
|
it("handles complex unified diff format", () => {
|
|
const diff = [
|
|
"--- a/file.ts",
|
|
"+++ b/file.ts",
|
|
"@@ -1,3 +1,3 @@",
|
|
" line 1",
|
|
"-old line 2",
|
|
"+new line 2",
|
|
" line 3",
|
|
].join("\n");
|
|
const text = `\`\`\`diff\n${diff}\n\`\`\``;
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].type).toBe("diff-artifact");
|
|
if (result[0].type === "diff-artifact") {
|
|
expect(result[0].diff).toContain("--- a/file.ts");
|
|
expect(result[0].diff).toContain("+++ b/file.ts");
|
|
}
|
|
});
|
|
|
|
it("handles diff with special characters", () => {
|
|
const text = '```diff\n-const x = "hello";\n+const x = "world";\n```';
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].type).toBe("diff-artifact");
|
|
});
|
|
|
|
it("does not match regular code blocks", () => {
|
|
const text = "```js\nconst x = 1;\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].type).toBe("text");
|
|
});
|
|
|
|
it("handles only diff block with no surrounding text", () => {
|
|
const text = "```diff\n+added\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].type).toBe("diff-artifact");
|
|
if (result[0].type === "diff-artifact") {
|
|
expect(result[0].diff).toBe("+added");
|
|
}
|
|
});
|
|
|
|
it("handles diff with whitespace-only before (trimmed away)", () => {
|
|
const text = " \n```diff\n+added\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].type).toBe("diff-artifact");
|
|
});
|
|
|
|
it("handles diff with whitespace after language tag", () => {
|
|
const text = "```diff \n-removed\n+added\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].type).toBe("diff-artifact");
|
|
});
|
|
|
|
it("handles consecutive diff blocks with no text between", () => {
|
|
const text = "```diff\n-a\n```\n```diff\n+b\n```";
|
|
const result = splitDiffBlocks(text);
|
|
// The \n between blocks isn't trimmed, so we get 2 diff artifacts
|
|
const diffArtifacts = result.filter((s) => s.type === "diff-artifact");
|
|
expect(diffArtifacts.length).toBe(2);
|
|
});
|
|
|
|
it("handles diff block with deletion-only content", () => {
|
|
const text = "```diff\n-line1\n-line2\n-line3\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
if (result[0].type === "diff-artifact") {
|
|
expect(result[0].diff).toContain("-line1");
|
|
expect(result[0].diff).toContain("-line3");
|
|
}
|
|
});
|
|
|
|
it("handles diff block with addition-only content", () => {
|
|
const text = "```diff\n+new1\n+new2\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
if (result[0].type === "diff-artifact") {
|
|
expect(result[0].diff).toContain("+new1");
|
|
}
|
|
});
|
|
|
|
it("preserves context lines in diff", () => {
|
|
const text = "```diff\n context\n-removed\n+added\n context2\n```";
|
|
const result = splitDiffBlocks(text);
|
|
expect(result).toHaveLength(1);
|
|
if (result[0].type === "diff-artifact") {
|
|
expect(result[0].diff).toContain(" context");
|
|
expect(result[0].diff).toContain(" context2");
|
|
}
|
|
});
|
|
});
|