|
@@ -1,738 +0,0 @@
|
|
|
-import { NewUnifiedDiffStrategy } from "../new-unified"
|
|
|
|
|
-
|
|
|
|
|
-describe("main", () => {
|
|
|
|
|
- let strategy: NewUnifiedDiffStrategy
|
|
|
|
|
-
|
|
|
|
|
- beforeEach(() => {
|
|
|
|
|
- strategy = new NewUnifiedDiffStrategy(0.97)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- describe("constructor", () => {
|
|
|
|
|
- it("should use default confidence threshold when not provided", () => {
|
|
|
|
|
- const defaultStrategy = new NewUnifiedDiffStrategy()
|
|
|
|
|
- expect(defaultStrategy["confidenceThreshold"]).toBe(1)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should use provided confidence threshold", () => {
|
|
|
|
|
- const customStrategy = new NewUnifiedDiffStrategy(0.85)
|
|
|
|
|
- expect(customStrategy["confidenceThreshold"]).toBe(0.85)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should enforce minimum confidence threshold", () => {
|
|
|
|
|
- const lowStrategy = new NewUnifiedDiffStrategy(0.7) // Below minimum of 0.8
|
|
|
|
|
- expect(lowStrategy["confidenceThreshold"]).toBe(0.8)
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- describe("getToolDescription", () => {
|
|
|
|
|
- it("should return tool description with correct cwd", () => {
|
|
|
|
|
- const cwd = "/test/path"
|
|
|
|
|
- const description = strategy.getToolDescription({ cwd })
|
|
|
|
|
-
|
|
|
|
|
- expect(description).toContain("apply_diff Tool - Generate Precise Code Changes")
|
|
|
|
|
- expect(description).toContain(cwd)
|
|
|
|
|
- expect(description).toContain("Step-by-Step Instructions")
|
|
|
|
|
- expect(description).toContain("Requirements")
|
|
|
|
|
- expect(description).toContain("Examples")
|
|
|
|
|
- expect(description).toContain("Parameters:")
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should apply simple diff correctly", async () => {
|
|
|
|
|
- const original = `line1
|
|
|
|
|
-line2
|
|
|
|
|
-line3`
|
|
|
|
|
-
|
|
|
|
|
- const diff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line1
|
|
|
|
|
-+new line
|
|
|
|
|
- line2
|
|
|
|
|
--line3
|
|
|
|
|
-+modified line3`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(`line1
|
|
|
|
|
-new line
|
|
|
|
|
-line2
|
|
|
|
|
-modified line3`)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle multiple hunks", async () => {
|
|
|
|
|
- const original = `line1
|
|
|
|
|
-line2
|
|
|
|
|
-line3
|
|
|
|
|
-line4
|
|
|
|
|
-line5`
|
|
|
|
|
-
|
|
|
|
|
- const diff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line1
|
|
|
|
|
-+new line
|
|
|
|
|
- line2
|
|
|
|
|
--line3
|
|
|
|
|
-+modified line3
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line4
|
|
|
|
|
--line5
|
|
|
|
|
-+modified line5
|
|
|
|
|
-+new line at end`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(`line1
|
|
|
|
|
-new line
|
|
|
|
|
-line2
|
|
|
|
|
-modified line3
|
|
|
|
|
-line4
|
|
|
|
|
-modified line5
|
|
|
|
|
-new line at end`)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle complex large", async () => {
|
|
|
|
|
- const original = `line1
|
|
|
|
|
-line2
|
|
|
|
|
-line3
|
|
|
|
|
-line4
|
|
|
|
|
-line5
|
|
|
|
|
-line6
|
|
|
|
|
-line7
|
|
|
|
|
-line8
|
|
|
|
|
-line9
|
|
|
|
|
-line10`
|
|
|
|
|
-
|
|
|
|
|
- const diff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line1
|
|
|
|
|
-+header line
|
|
|
|
|
-+another header
|
|
|
|
|
- line2
|
|
|
|
|
--line3
|
|
|
|
|
--line4
|
|
|
|
|
-+modified line3
|
|
|
|
|
-+modified line4
|
|
|
|
|
-+extra line
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line6
|
|
|
|
|
-+middle section
|
|
|
|
|
- line7
|
|
|
|
|
--line8
|
|
|
|
|
-+changed line8
|
|
|
|
|
-+bonus line
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line9
|
|
|
|
|
--line10
|
|
|
|
|
-+final line
|
|
|
|
|
-+very last line`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(`line1
|
|
|
|
|
-header line
|
|
|
|
|
-another header
|
|
|
|
|
-line2
|
|
|
|
|
-modified line3
|
|
|
|
|
-modified line4
|
|
|
|
|
-extra line
|
|
|
|
|
-line5
|
|
|
|
|
-line6
|
|
|
|
|
-middle section
|
|
|
|
|
-line7
|
|
|
|
|
-changed line8
|
|
|
|
|
-bonus line
|
|
|
|
|
-line9
|
|
|
|
|
-final line
|
|
|
|
|
-very last line`)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle indentation changes", async () => {
|
|
|
|
|
- const original = `first line
|
|
|
|
|
- indented line
|
|
|
|
|
- double indented line
|
|
|
|
|
- back to single indent
|
|
|
|
|
-no indent
|
|
|
|
|
- indented again
|
|
|
|
|
- double indent again
|
|
|
|
|
- triple indent
|
|
|
|
|
- back to single
|
|
|
|
|
-last line`
|
|
|
|
|
-
|
|
|
|
|
- const diff = `--- original
|
|
|
|
|
-+++ modified
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- first line
|
|
|
|
|
- indented line
|
|
|
|
|
-+ tab indented line
|
|
|
|
|
-+ new indented line
|
|
|
|
|
- double indented line
|
|
|
|
|
- back to single indent
|
|
|
|
|
- no indent
|
|
|
|
|
- indented again
|
|
|
|
|
- double indent again
|
|
|
|
|
-- triple indent
|
|
|
|
|
-+ hi there mate
|
|
|
|
|
- back to single
|
|
|
|
|
- last line`
|
|
|
|
|
-
|
|
|
|
|
- const expected = `first line
|
|
|
|
|
- indented line
|
|
|
|
|
- tab indented line
|
|
|
|
|
- new indented line
|
|
|
|
|
- double indented line
|
|
|
|
|
- back to single indent
|
|
|
|
|
-no indent
|
|
|
|
|
- indented again
|
|
|
|
|
- double indent again
|
|
|
|
|
- hi there mate
|
|
|
|
|
- back to single
|
|
|
|
|
-last line`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(expected)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle high level edits", async () => {
|
|
|
|
|
- const original = `def factorial(n):
|
|
|
|
|
- if n == 0:
|
|
|
|
|
- return 1
|
|
|
|
|
- else:
|
|
|
|
|
- return n * factorial(n-1)`
|
|
|
|
|
- const diff = `@@ ... @@
|
|
|
|
|
--def factorial(n):
|
|
|
|
|
-- if n == 0:
|
|
|
|
|
-- return 1
|
|
|
|
|
-- else:
|
|
|
|
|
-- return n * factorial(n-1)
|
|
|
|
|
-+def factorial(number):
|
|
|
|
|
-+ if number == 0:
|
|
|
|
|
-+ return 1
|
|
|
|
|
-+ else:
|
|
|
|
|
-+ return number * factorial(number-1)`
|
|
|
|
|
-
|
|
|
|
|
- const expected = `def factorial(number):
|
|
|
|
|
- if number == 0:
|
|
|
|
|
- return 1
|
|
|
|
|
- else:
|
|
|
|
|
- return number * factorial(number-1)`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(expected)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("it should handle very complex edits", async () => {
|
|
|
|
|
- const original = `//Initialize the array that will hold the primes
|
|
|
|
|
-var primeArray = [];
|
|
|
|
|
-/*Write a function that checks for primeness and
|
|
|
|
|
- pushes those values to t*he array*/
|
|
|
|
|
-function PrimeCheck(candidate){
|
|
|
|
|
- isPrime = true;
|
|
|
|
|
- for(var i = 2; i < candidate && isPrime; i++){
|
|
|
|
|
- if(candidate%i === 0){
|
|
|
|
|
- isPrime = false;
|
|
|
|
|
- } else {
|
|
|
|
|
- isPrime = true;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if(isPrime){
|
|
|
|
|
- primeArray.push(candidate);
|
|
|
|
|
- }
|
|
|
|
|
- return primeArray;
|
|
|
|
|
-}
|
|
|
|
|
-/*Write the code that runs the above until the
|
|
|
|
|
- l ength of the array equa*ls the number of primes
|
|
|
|
|
- desired*/
|
|
|
|
|
-
|
|
|
|
|
-var numPrimes = prompt("How many primes?");
|
|
|
|
|
-
|
|
|
|
|
-//Display the finished array of primes
|
|
|
|
|
-
|
|
|
|
|
-//for loop starting at 2 as that is the lowest prime number keep going until the array is as long as we requested
|
|
|
|
|
-for (var i = 2; primeArray.length < numPrimes; i++) {
|
|
|
|
|
- PrimeCheck(i); //
|
|
|
|
|
-}
|
|
|
|
|
-console.log(primeArray);
|
|
|
|
|
-`
|
|
|
|
|
-
|
|
|
|
|
- const diff = `--- test_diff.js
|
|
|
|
|
-+++ test_diff.js
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
--//Initialize the array that will hold the primes
|
|
|
|
|
- var primeArray = [];
|
|
|
|
|
--/*Write a function that checks for primeness and
|
|
|
|
|
-- pushes those values to t*he array*/
|
|
|
|
|
- function PrimeCheck(candidate){
|
|
|
|
|
- isPrime = true;
|
|
|
|
|
- for(var i = 2; i < candidate && isPrime; i++){
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- return primeArray;
|
|
|
|
|
- }
|
|
|
|
|
--/*Write the code that runs the above until the
|
|
|
|
|
-- l ength of the array equa*ls the number of primes
|
|
|
|
|
-- desired*/
|
|
|
|
|
-
|
|
|
|
|
- var numPrimes = prompt("How many primes?");
|
|
|
|
|
-
|
|
|
|
|
--//Display the finished array of primes
|
|
|
|
|
--
|
|
|
|
|
--//for loop starting at 2 as that is the lowest prime number keep going until the array is as long as we requested
|
|
|
|
|
- for (var i = 2; primeArray.length < numPrimes; i++) {
|
|
|
|
|
-- PrimeCheck(i); //
|
|
|
|
|
-+ PrimeCheck(i);
|
|
|
|
|
- }
|
|
|
|
|
- console.log(primeArray);`
|
|
|
|
|
-
|
|
|
|
|
- const expected = `var primeArray = [];
|
|
|
|
|
-function PrimeCheck(candidate){
|
|
|
|
|
- isPrime = true;
|
|
|
|
|
- for(var i = 2; i < candidate && isPrime; i++){
|
|
|
|
|
- if(candidate%i === 0){
|
|
|
|
|
- isPrime = false;
|
|
|
|
|
- } else {
|
|
|
|
|
- isPrime = true;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if(isPrime){
|
|
|
|
|
- primeArray.push(candidate);
|
|
|
|
|
- }
|
|
|
|
|
- return primeArray;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-var numPrimes = prompt("How many primes?");
|
|
|
|
|
-
|
|
|
|
|
-for (var i = 2; primeArray.length < numPrimes; i++) {
|
|
|
|
|
- PrimeCheck(i);
|
|
|
|
|
-}
|
|
|
|
|
-console.log(primeArray);
|
|
|
|
|
-`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(expected)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- describe("error handling and edge cases", () => {
|
|
|
|
|
- it("should reject completely invalid diff format", async () => {
|
|
|
|
|
- const original = "line1\nline2\nline3"
|
|
|
|
|
- const invalidDiff = "this is not a diff at all"
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, invalidDiff)
|
|
|
|
|
- expect(result.success).toBe(false)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should reject diff with invalid hunk format", async () => {
|
|
|
|
|
- const original = "line1\nline2\nline3"
|
|
|
|
|
- const invalidHunkDiff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-invalid hunk header
|
|
|
|
|
- line1
|
|
|
|
|
--line2
|
|
|
|
|
-+new line`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, invalidHunkDiff)
|
|
|
|
|
- expect(result.success).toBe(false)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should fail when diff tries to modify non-existent content", async () => {
|
|
|
|
|
- const original = "line1\nline2\nline3"
|
|
|
|
|
- const nonMatchingDiff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line1
|
|
|
|
|
--nonexistent line
|
|
|
|
|
-+new line
|
|
|
|
|
- line3`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, nonMatchingDiff)
|
|
|
|
|
- expect(result.success).toBe(false)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle overlapping hunks", async () => {
|
|
|
|
|
- const original = `line1
|
|
|
|
|
-line2
|
|
|
|
|
-line3
|
|
|
|
|
-line4
|
|
|
|
|
-line5`
|
|
|
|
|
- const overlappingDiff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line1
|
|
|
|
|
- line2
|
|
|
|
|
--line3
|
|
|
|
|
-+modified3
|
|
|
|
|
- line4
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line2
|
|
|
|
|
--line3
|
|
|
|
|
--line4
|
|
|
|
|
-+modified3and4
|
|
|
|
|
- line5`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, overlappingDiff)
|
|
|
|
|
- expect(result.success).toBe(false)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle empty lines modifications", async () => {
|
|
|
|
|
- const original = `line1
|
|
|
|
|
-
|
|
|
|
|
-line3
|
|
|
|
|
-
|
|
|
|
|
-line5`
|
|
|
|
|
- const emptyLinesDiff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line1
|
|
|
|
|
-
|
|
|
|
|
--line3
|
|
|
|
|
-+line3modified
|
|
|
|
|
-
|
|
|
|
|
- line5`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, emptyLinesDiff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(`line1
|
|
|
|
|
-
|
|
|
|
|
-line3modified
|
|
|
|
|
-
|
|
|
|
|
-line5`)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle mixed line endings in diff", async () => {
|
|
|
|
|
- const original = "line1\r\nline2\nline3\r\n"
|
|
|
|
|
- const mixedEndingsDiff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line1\r
|
|
|
|
|
--line2
|
|
|
|
|
-+modified2\r
|
|
|
|
|
- line3`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, mixedEndingsDiff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe("line1\r\nmodified2\r\nline3\r\n")
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle partial line modifications", async () => {
|
|
|
|
|
- const original = "const value = oldValue + 123;"
|
|
|
|
|
- const partialDiff = `--- a/file.txt
|
|
|
|
|
-+++ b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
--const value = oldValue + 123;
|
|
|
|
|
-+const value = newValue + 123;`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, partialDiff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe("const value = newValue + 123;")
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle slightly malformed but recoverable diff", async () => {
|
|
|
|
|
- const original = "line1\nline2\nline3"
|
|
|
|
|
- // Missing space after --- and +++
|
|
|
|
|
- const slightlyBadDiff = `---a/file.txt
|
|
|
|
|
-+++b/file.txt
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- line1
|
|
|
|
|
--line2
|
|
|
|
|
-+new line
|
|
|
|
|
- line3`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, slightlyBadDiff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe("line1\nnew line\nline3")
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- describe("similar code sections", () => {
|
|
|
|
|
- it("should correctly modify the right section when similar code exists", async () => {
|
|
|
|
|
- const original = `function add(a, b) {
|
|
|
|
|
- return a + b;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function subtract(a, b) {
|
|
|
|
|
- return a - b;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function multiply(a, b) {
|
|
|
|
|
- return a + b; // Bug here
|
|
|
|
|
-}`
|
|
|
|
|
-
|
|
|
|
|
- const diff = `--- a/math.js
|
|
|
|
|
-+++ b/math.js
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- function multiply(a, b) {
|
|
|
|
|
-- return a + b; // Bug here
|
|
|
|
|
-+ return a * b;
|
|
|
|
|
- }`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(`function add(a, b) {
|
|
|
|
|
- return a + b;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function subtract(a, b) {
|
|
|
|
|
- return a - b;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function multiply(a, b) {
|
|
|
|
|
- return a * b;
|
|
|
|
|
-}`)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- it("should handle multiple similar sections with correct context", async () => {
|
|
|
|
|
- const original = `if (condition) {
|
|
|
|
|
- doSomething();
|
|
|
|
|
- doSomething();
|
|
|
|
|
- doSomething();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-if (otherCondition) {
|
|
|
|
|
- doSomething();
|
|
|
|
|
- doSomething();
|
|
|
|
|
- doSomething();
|
|
|
|
|
-}`
|
|
|
|
|
-
|
|
|
|
|
- const diff = `--- a/file.js
|
|
|
|
|
-+++ b/file.js
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
- if (otherCondition) {
|
|
|
|
|
- doSomething();
|
|
|
|
|
-- doSomething();
|
|
|
|
|
-+ doSomethingElse();
|
|
|
|
|
- doSomething();
|
|
|
|
|
- }`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(`if (condition) {
|
|
|
|
|
- doSomething();
|
|
|
|
|
- doSomething();
|
|
|
|
|
- doSomething();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-if (otherCondition) {
|
|
|
|
|
- doSomething();
|
|
|
|
|
- doSomethingElse();
|
|
|
|
|
- doSomething();
|
|
|
|
|
-}`)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- describe("hunk splitting", () => {
|
|
|
|
|
- it("should handle large diffs with multiple non-contiguous changes", async () => {
|
|
|
|
|
- const original = `import { readFile } from 'fs';
|
|
|
|
|
-import { join } from 'path';
|
|
|
|
|
-import { Logger } from './logger';
|
|
|
|
|
-
|
|
|
|
|
-const logger = new Logger();
|
|
|
|
|
-
|
|
|
|
|
-async function processFile(filePath: string) {
|
|
|
|
|
- try {
|
|
|
|
|
- const data = await readFile(filePath, 'utf8');
|
|
|
|
|
- logger.info('File read successfully');
|
|
|
|
|
- return data;
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- logger.error('Failed to read file:', error);
|
|
|
|
|
- throw error;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function validateInput(input: string): boolean {
|
|
|
|
|
- if (!input) {
|
|
|
|
|
- logger.warn('Empty input received');
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- return input.length > 0;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-async function writeOutput(data: string) {
|
|
|
|
|
- logger.info('Processing output');
|
|
|
|
|
- // TODO: Implement output writing
|
|
|
|
|
- return Promise.resolve();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function parseConfig(configPath: string) {
|
|
|
|
|
- logger.debug('Reading config from:', configPath);
|
|
|
|
|
- // Basic config parsing
|
|
|
|
|
- return {
|
|
|
|
|
- enabled: true,
|
|
|
|
|
- maxRetries: 3
|
|
|
|
|
- };
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-export {
|
|
|
|
|
- processFile,
|
|
|
|
|
- validateInput,
|
|
|
|
|
- writeOutput,
|
|
|
|
|
- parseConfig
|
|
|
|
|
-};`
|
|
|
|
|
-
|
|
|
|
|
- const diff = `--- a/file.ts
|
|
|
|
|
-+++ b/file.ts
|
|
|
|
|
-@@ ... @@
|
|
|
|
|
--import { readFile } from 'fs';
|
|
|
|
|
-+import { readFile, writeFile } from 'fs';
|
|
|
|
|
- import { join } from 'path';
|
|
|
|
|
--import { Logger } from './logger';
|
|
|
|
|
-+import { Logger } from './utils/logger';
|
|
|
|
|
-+import { Config } from './types';
|
|
|
|
|
-
|
|
|
|
|
--const logger = new Logger();
|
|
|
|
|
-+const logger = new Logger('FileProcessor');
|
|
|
|
|
-
|
|
|
|
|
- async function processFile(filePath: string) {
|
|
|
|
|
- try {
|
|
|
|
|
- const data = await readFile(filePath, 'utf8');
|
|
|
|
|
-- logger.info('File read successfully');
|
|
|
|
|
-+ logger.info(\`File \${filePath} read successfully\`);
|
|
|
|
|
- return data;
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
-- logger.error('Failed to read file:', error);
|
|
|
|
|
-+ logger.error(\`Failed to read file \${filePath}:\`, error);
|
|
|
|
|
- throw error;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function validateInput(input: string): boolean {
|
|
|
|
|
- if (!input) {
|
|
|
|
|
-- logger.warn('Empty input received');
|
|
|
|
|
-+ logger.warn('Validation failed: Empty input received');
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-- return input.length > 0;
|
|
|
|
|
-+ return input.trim().length > 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
--async function writeOutput(data: string) {
|
|
|
|
|
-- logger.info('Processing output');
|
|
|
|
|
-- // TODO: Implement output writing
|
|
|
|
|
-- return Promise.resolve();
|
|
|
|
|
-+async function writeOutput(data: string, outputPath: string) {
|
|
|
|
|
-+ try {
|
|
|
|
|
-+ await writeFile(outputPath, data, 'utf8');
|
|
|
|
|
-+ logger.info(\`Output written to \${outputPath}\`);
|
|
|
|
|
-+ } catch (error) {
|
|
|
|
|
-+ logger.error(\`Failed to write output to \${outputPath}:\`, error);
|
|
|
|
|
-+ throw error;
|
|
|
|
|
-+ }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
--function parseConfig(configPath: string) {
|
|
|
|
|
-- logger.debug('Reading config from:', configPath);
|
|
|
|
|
-- // Basic config parsing
|
|
|
|
|
-- return {
|
|
|
|
|
-- enabled: true,
|
|
|
|
|
-- maxRetries: 3
|
|
|
|
|
-- };
|
|
|
|
|
-+async function parseConfig(configPath: string): Promise<Config> {
|
|
|
|
|
-+ try {
|
|
|
|
|
-+ const configData = await readFile(configPath, 'utf8');
|
|
|
|
|
-+ logger.debug(\`Reading config from \${configPath}\`);
|
|
|
|
|
-+ return JSON.parse(configData);
|
|
|
|
|
-+ } catch (error) {
|
|
|
|
|
-+ logger.error(\`Failed to parse config from \${configPath}:\`, error);
|
|
|
|
|
-+ throw error;
|
|
|
|
|
-+ }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- export {
|
|
|
|
|
- processFile,
|
|
|
|
|
- validateInput,
|
|
|
|
|
- writeOutput,
|
|
|
|
|
-- parseConfig
|
|
|
|
|
-+ parseConfig,
|
|
|
|
|
-+ type Config
|
|
|
|
|
- };`
|
|
|
|
|
-
|
|
|
|
|
- const expected = `import { readFile, writeFile } from 'fs';
|
|
|
|
|
-import { join } from 'path';
|
|
|
|
|
-import { Logger } from './utils/logger';
|
|
|
|
|
-import { Config } from './types';
|
|
|
|
|
-
|
|
|
|
|
-const logger = new Logger('FileProcessor');
|
|
|
|
|
-
|
|
|
|
|
-async function processFile(filePath: string) {
|
|
|
|
|
- try {
|
|
|
|
|
- const data = await readFile(filePath, 'utf8');
|
|
|
|
|
- logger.info(\`File \${filePath} read successfully\`);
|
|
|
|
|
- return data;
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- logger.error(\`Failed to read file \${filePath}:\`, error);
|
|
|
|
|
- throw error;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function validateInput(input: string): boolean {
|
|
|
|
|
- if (!input) {
|
|
|
|
|
- logger.warn('Validation failed: Empty input received');
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- return input.trim().length > 0;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-async function writeOutput(data: string, outputPath: string) {
|
|
|
|
|
- try {
|
|
|
|
|
- await writeFile(outputPath, data, 'utf8');
|
|
|
|
|
- logger.info(\`Output written to \${outputPath}\`);
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- logger.error(\`Failed to write output to \${outputPath}:\`, error);
|
|
|
|
|
- throw error;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-async function parseConfig(configPath: string): Promise<Config> {
|
|
|
|
|
- try {
|
|
|
|
|
- const configData = await readFile(configPath, 'utf8');
|
|
|
|
|
- logger.debug(\`Reading config from \${configPath}\`);
|
|
|
|
|
- return JSON.parse(configData);
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- logger.error(\`Failed to parse config from \${configPath}:\`, error);
|
|
|
|
|
- throw error;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-export {
|
|
|
|
|
- processFile,
|
|
|
|
|
- validateInput,
|
|
|
|
|
- writeOutput,
|
|
|
|
|
- parseConfig,
|
|
|
|
|
- type Config
|
|
|
|
|
-};`
|
|
|
|
|
-
|
|
|
|
|
- const result = await strategy.applyDiff(original, diff)
|
|
|
|
|
- expect(result.success).toBe(true)
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.content).toBe(expected)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
-})
|
|
|