mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
test: add validateMarkerSequencing test cases
Tests valid and invalid marker sequences: - validates single and multiple complete sequences - detects out-of-order markers (separator/replace before search) - detects incorrect sequence termination - validates state transitions between SEARCH/SEP/REPLACE markers Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org>
This commit is contained in:
parent
4b3f711746
commit
2032c9e45f
1 changed files with 329 additions and 266 deletions
|
|
@ -1,16 +1,64 @@
|
|||
import { MultiSearchReplaceDiffStrategy } from "../multi-search-replace"
|
||||
|
||||
describe("MultiSearchReplaceDiffStrategy", () => {
|
||||
describe("exact matching", () => {
|
||||
describe("validateMarkerSequencing", () => {
|
||||
let strategy: MultiSearchReplaceDiffStrategy
|
||||
|
||||
beforeEach(() => {
|
||||
strategy = new MultiSearchReplaceDiffStrategy(1.0, 5) // Default 1.0 threshold for exact matching, 5 line buffer for tests
|
||||
strategy = new MultiSearchReplaceDiffStrategy()
|
||||
})
|
||||
|
||||
it("should replace matching content", async () => {
|
||||
const originalContent = 'function hello() {\n console.log("hello")\n}\n'
|
||||
const diffContent = `test.ts
|
||||
it("validates correct marker sequence", () => {
|
||||
const diff = "<<<<<<< SEARCH\n" + "some content\n" + "=======\n" + "new content\n" + ">>>>>>> REPLACE"
|
||||
expect(strategy["validateMarkerSequencing"](diff).success).toBe(true)
|
||||
})
|
||||
|
||||
it("validates multiple correct marker sequences", () => {
|
||||
const diff =
|
||||
"<<<<<<< SEARCH\n" +
|
||||
"content1\n" +
|
||||
"=======\n" +
|
||||
"new1\n" +
|
||||
">>>>>>> REPLACE\n\n" +
|
||||
"<<<<<<< SEARCH\n" +
|
||||
"content2\n" +
|
||||
"=======\n" +
|
||||
"new2\n" +
|
||||
">>>>>>> REPLACE"
|
||||
expect(strategy["validateMarkerSequencing"](diff).success).toBe(true)
|
||||
})
|
||||
|
||||
it("detects separator before search", () => {
|
||||
const diff = "=======\n" + "content\n" + ">>>>>>> REPLACE"
|
||||
const result = strategy["validateMarkerSequencing"](diff)
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toContain("'=======' found in your diff content")
|
||||
})
|
||||
|
||||
it("detects replace before separator", () => {
|
||||
const diff = "<<<<<<< SEARCH\n" + "content\n" + ">>>>>>> REPLACE"
|
||||
const result = strategy["validateMarkerSequencing"](diff)
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toContain("'>>>>>>> REPLACE' found in your diff content")
|
||||
})
|
||||
|
||||
it("detects incomplete sequence", () => {
|
||||
const diff = "<<<<<<< SEARCH\n" + "content\n" + "=======\n" + "new content"
|
||||
const result = strategy["validateMarkerSequencing"](diff)
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toContain("Expected '>>>>>>> REPLACE' was not found")
|
||||
})
|
||||
|
||||
describe("exact matching", () => {
|
||||
let strategy: MultiSearchReplaceDiffStrategy
|
||||
|
||||
beforeEach(() => {
|
||||
strategy = new MultiSearchReplaceDiffStrategy(1.0, 5) // Default 1.0 threshold for exact matching, 5 line buffer for tests
|
||||
})
|
||||
|
||||
it("should replace matching content", async () => {
|
||||
const originalContent = 'function hello() {\n console.log("hello")\n}\n'
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
function hello() {
|
||||
console.log("hello")
|
||||
|
|
@ -21,16 +69,16 @@ function hello() {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe('function hello() {\n console.log("hello world")\n}\n')
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe('function hello() {\n console.log("hello world")\n}\n')
|
||||
}
|
||||
})
|
||||
|
||||
it("should match content with different surrounding whitespace", async () => {
|
||||
const originalContent = "\nfunction example() {\n return 42;\n}\n\n"
|
||||
const diffContent = `test.ts
|
||||
it("should match content with different surrounding whitespace", async () => {
|
||||
const originalContent = "\nfunction example() {\n return 42;\n}\n\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
function example() {
|
||||
return 42;
|
||||
|
|
@ -41,16 +89,16 @@ function example() {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("\nfunction example() {\n return 43;\n}\n\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("\nfunction example() {\n return 43;\n}\n\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should match content with different indentation in search block", async () => {
|
||||
const originalContent = " function test() {\n return true;\n }\n"
|
||||
const diffContent = `test.ts
|
||||
it("should match content with different indentation in search block", async () => {
|
||||
const originalContent = " function test() {\n return true;\n }\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
function test() {
|
||||
return true;
|
||||
|
|
@ -61,16 +109,16 @@ function test() {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(" function test() {\n return false;\n }\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(" function test() {\n return false;\n }\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle tab-based indentation", async () => {
|
||||
const originalContent = "function test() {\n\treturn true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
it("should handle tab-based indentation", async () => {
|
||||
const originalContent = "function test() {\n\treturn true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
function test() {
|
||||
\treturn true;
|
||||
|
|
@ -81,16 +129,16 @@ function test() {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\n\treturn false;\n}\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\n\treturn false;\n}\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should preserve mixed tabs and spaces", async () => {
|
||||
const originalContent = "\tclass Example {\n\t constructor() {\n\t\tthis.value = 0;\n\t }\n\t}"
|
||||
const diffContent = `test.ts
|
||||
it("should preserve mixed tabs and spaces", async () => {
|
||||
const originalContent = "\tclass Example {\n\t constructor() {\n\t\tthis.value = 0;\n\t }\n\t}"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
\tclass Example {
|
||||
\t constructor() {
|
||||
|
|
@ -105,18 +153,18 @@ function test() {
|
|||
\t}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
"\tclass Example {\n\t constructor() {\n\t\tthis.value = 1;\n\t }\n\t}",
|
||||
)
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
"\tclass Example {\n\t constructor() {\n\t\tthis.value = 1;\n\t }\n\t}",
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle additional indentation with tabs", async () => {
|
||||
const originalContent = "\tfunction test() {\n\t\treturn true;\n\t}"
|
||||
const diffContent = `test.ts
|
||||
it("should handle additional indentation with tabs", async () => {
|
||||
const originalContent = "\tfunction test() {\n\t\treturn true;\n\t}"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
function test() {
|
||||
\treturn true;
|
||||
|
|
@ -128,16 +176,16 @@ function test() {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("\tfunction test() {\n\t\t// Add comment\n\t\treturn false;\n\t}")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("\tfunction test() {\n\t\t// Add comment\n\t\treturn false;\n\t}")
|
||||
}
|
||||
})
|
||||
|
||||
it("should preserve exact indentation characters when adding lines", async () => {
|
||||
const originalContent = "\tfunction test() {\n\t\treturn true;\n\t}"
|
||||
const diffContent = `test.ts
|
||||
it("should preserve exact indentation characters when adding lines", async () => {
|
||||
const originalContent = "\tfunction test() {\n\t\treturn true;\n\t}"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
\tfunction test() {
|
||||
\t\treturn true;
|
||||
|
|
@ -150,18 +198,18 @@ function test() {
|
|||
\t}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
"\tfunction test() {\n\t\t// First comment\n\t\t// Second comment\n\t\treturn true;\n\t}",
|
||||
)
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
"\tfunction test() {\n\t\t// First comment\n\t\t// Second comment\n\t\treturn true;\n\t}",
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle Windows-style CRLF line endings", async () => {
|
||||
const originalContent = "function test() {\r\n return true;\r\n}\r\n"
|
||||
const diffContent = `test.ts
|
||||
it("should handle Windows-style CRLF line endings", async () => {
|
||||
const originalContent = "function test() {\r\n return true;\r\n}\r\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
function test() {
|
||||
return true;
|
||||
|
|
@ -172,16 +220,16 @@ function test() {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\r\n return false;\r\n}\r\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\r\n return false;\r\n}\r\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should return false if search content does not match", async () => {
|
||||
const originalContent = 'function hello() {\n console.log("hello")\n}\n'
|
||||
const diffContent = `test.ts
|
||||
it("should return false if search content does not match", async () => {
|
||||
const originalContent = 'function hello() {\n console.log("hello")\n}\n'
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
function hello() {
|
||||
console.log("wrong")
|
||||
|
|
@ -192,22 +240,22 @@ function hello() {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false if diff format is invalid", async () => {
|
||||
const originalContent = 'function hello() {\n console.log("hello")\n}\n'
|
||||
const diffContent = `test.ts\nInvalid diff format`
|
||||
it("should return false if diff format is invalid", async () => {
|
||||
const originalContent = 'function hello() {\n console.log("hello")\n}\n'
|
||||
const diffContent = `test.ts\nInvalid diff format`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it("should handle multiple lines with proper indentation", async () => {
|
||||
const originalContent =
|
||||
"class Example {\n constructor() {\n this.value = 0\n }\n\n getValue() {\n return this.value\n }\n}\n"
|
||||
const diffContent = `test.ts
|
||||
it("should handle multiple lines with proper indentation", async () => {
|
||||
const originalContent =
|
||||
"class Example {\n constructor() {\n this.value = 0\n }\n\n getValue() {\n return this.value\n }\n}\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
getValue() {
|
||||
return this.value
|
||||
|
|
@ -220,18 +268,18 @@ function hello() {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
'class Example {\n constructor() {\n this.value = 0\n }\n\n getValue() {\n // Add logging\n console.log("Getting value")\n return this.value\n }\n}\n',
|
||||
)
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
'class Example {\n constructor() {\n this.value = 0\n }\n\n getValue() {\n // Add logging\n console.log("Getting value")\n return this.value\n }\n}\n',
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should preserve whitespace exactly in the output", async () => {
|
||||
const originalContent = " indented\n more indented\n back\n"
|
||||
const diffContent = `test.ts
|
||||
it("should preserve whitespace exactly in the output", async () => {
|
||||
const originalContent = " indented\n more indented\n back\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
indented
|
||||
more indented
|
||||
|
|
@ -242,16 +290,16 @@ function hello() {
|
|||
end
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(" modified\n still indented\n end\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(" modified\n still indented\n end\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should preserve indentation when adding new lines after existing content", async () => {
|
||||
const originalContent = " onScroll={() => updateHighlights()}"
|
||||
const diffContent = `test.ts
|
||||
it("should preserve indentation when adding new lines after existing content", async () => {
|
||||
const originalContent = " onScroll={() => updateHighlights()}"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
onScroll={() => updateHighlights()}
|
||||
=======
|
||||
|
|
@ -262,17 +310,17 @@ function hello() {
|
|||
}}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
" onScroll={() => updateHighlights()}\n onDragOver={(e) => {\n e.preventDefault()\n e.stopPropagation()\n }}",
|
||||
)
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
" onScroll={() => updateHighlights()}\n onDragOver={(e) => {\n e.preventDefault()\n e.stopPropagation()\n }}",
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle varying indentation levels correctly", async () => {
|
||||
const originalContent = `
|
||||
it("should handle varying indentation levels correctly", async () => {
|
||||
const originalContent = `
|
||||
class Example {
|
||||
constructor() {
|
||||
this.value = 0;
|
||||
|
|
@ -282,7 +330,7 @@ class Example {
|
|||
}
|
||||
}`.trim()
|
||||
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
class Example {
|
||||
constructor() {
|
||||
|
|
@ -305,11 +353,11 @@ class Example {
|
|||
}
|
||||
>>>>>>> REPLACE`.trim()
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
`
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(
|
||||
`
|
||||
class Example {
|
||||
constructor() {
|
||||
this.value = 1;
|
||||
|
|
@ -320,12 +368,12 @@ class Example {
|
|||
}
|
||||
}
|
||||
}`.trim(),
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle mixed indentation styles in the same file", async () => {
|
||||
const originalContent = `class Example {
|
||||
it("should handle mixed indentation styles in the same file", async () => {
|
||||
const originalContent = `class Example {
|
||||
constructor() {
|
||||
this.value = 0;
|
||||
if (true) {
|
||||
|
|
@ -333,7 +381,7 @@ class Example {
|
|||
}
|
||||
}
|
||||
}`.trim()
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
constructor() {
|
||||
this.value = 0;
|
||||
|
|
@ -351,10 +399,10 @@ class Example {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Example {
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Example {
|
||||
constructor() {
|
||||
this.value = 1;
|
||||
if (true) {
|
||||
|
|
@ -363,17 +411,17 @@ class Example {
|
|||
}
|
||||
}
|
||||
}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle Python-style significant whitespace", async () => {
|
||||
const originalContent = `def example():
|
||||
it("should handle Python-style significant whitespace", async () => {
|
||||
const originalContent = `def example():
|
||||
if condition:
|
||||
do_something()
|
||||
for item in items:
|
||||
process(item)
|
||||
return True`.trim()
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
if condition:
|
||||
do_something()
|
||||
|
|
@ -387,28 +435,28 @@ class Example {
|
|||
process(item)
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`def example():
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`def example():
|
||||
if condition:
|
||||
do_something()
|
||||
while items:
|
||||
item = items.pop()
|
||||
process(item)
|
||||
return True`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should preserve empty lines with indentation", async () => {
|
||||
const originalContent = `function test() {
|
||||
it("should preserve empty lines with indentation", async () => {
|
||||
const originalContent = `function test() {
|
||||
const x = 1;
|
||||
|
||||
if (x) {
|
||||
return true;
|
||||
}
|
||||
}`.trim()
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
const x = 1;
|
||||
|
||||
|
|
@ -420,10 +468,10 @@ class Example {
|
|||
if (x) {
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`function test() {
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`function test() {
|
||||
const x = 1;
|
||||
|
||||
// Check x
|
||||
|
|
@ -431,18 +479,18 @@ class Example {
|
|||
return true;
|
||||
}
|
||||
}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle indentation when replacing entire blocks", async () => {
|
||||
const originalContent = `class Test {
|
||||
it("should handle indentation when replacing entire blocks", async () => {
|
||||
const originalContent = `class Test {
|
||||
method() {
|
||||
if (true) {
|
||||
console.log("test");
|
||||
}
|
||||
}
|
||||
}`.trim()
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
method() {
|
||||
if (true) {
|
||||
|
|
@ -461,10 +509,10 @@ class Example {
|
|||
}
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Test {
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Test {
|
||||
method() {
|
||||
try {
|
||||
if (true) {
|
||||
|
|
@ -475,11 +523,11 @@ class Example {
|
|||
}
|
||||
}
|
||||
}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle negative indentation relative to search content", async () => {
|
||||
const originalContent = `class Example {
|
||||
it("should handle negative indentation relative to search content", async () => {
|
||||
const originalContent = `class Example {
|
||||
constructor() {
|
||||
if (true) {
|
||||
this.init();
|
||||
|
|
@ -487,7 +535,7 @@ class Example {
|
|||
}
|
||||
}
|
||||
}`.trim()
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
this.init();
|
||||
this.setup();
|
||||
|
|
@ -496,10 +544,10 @@ class Example {
|
|||
this.setup();
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Example {
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Example {
|
||||
constructor() {
|
||||
if (true) {
|
||||
this.init();
|
||||
|
|
@ -507,39 +555,39 @@ class Example {
|
|||
}
|
||||
}
|
||||
}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle extreme negative indentation (no indent)", async () => {
|
||||
const originalContent = `class Example {
|
||||
it("should handle extreme negative indentation (no indent)", async () => {
|
||||
const originalContent = `class Example {
|
||||
constructor() {
|
||||
if (true) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
}`.trim()
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
this.init();
|
||||
=======
|
||||
this.init();
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Example {
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Example {
|
||||
constructor() {
|
||||
if (true) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle mixed indentation changes in replace block", async () => {
|
||||
const originalContent = `class Example {
|
||||
it("should handle mixed indentation changes in replace block", async () => {
|
||||
const originalContent = `class Example {
|
||||
constructor() {
|
||||
if (true) {
|
||||
this.init();
|
||||
|
|
@ -548,7 +596,7 @@ this.init();
|
|||
}
|
||||
}
|
||||
}`.trim()
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
this.init();
|
||||
this.setup();
|
||||
|
|
@ -559,10 +607,10 @@ this.init();
|
|||
this.validate();
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Example {
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`class Example {
|
||||
constructor() {
|
||||
if (true) {
|
||||
this.init();
|
||||
|
|
@ -571,11 +619,11 @@ this.init();
|
|||
}
|
||||
}
|
||||
}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should find matches from middle out", async () => {
|
||||
const originalContent = `
|
||||
it("should find matches from middle out", async () => {
|
||||
const originalContent = `
|
||||
function one() {
|
||||
return "target";
|
||||
}
|
||||
|
|
@ -596,20 +644,20 @@ function five() {
|
|||
return "target";
|
||||
}`.trim()
|
||||
|
||||
const diffContent = `test.ts
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
return "target";
|
||||
=======
|
||||
return "updated";
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
// Search around the middle (function three)
|
||||
// Even though all functions contain the target text,
|
||||
// it should match the one closest to line 9 first
|
||||
const result = await strategy.applyDiff(originalContent, diffContent, 9, 9)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`function one() {
|
||||
// Search around the middle (function three)
|
||||
// Even though all functions contain the target text,
|
||||
// it should match the one closest to line 9 first
|
||||
const result = await strategy.applyDiff(originalContent, diffContent, 9, 9)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(`function one() {
|
||||
return "target";
|
||||
}
|
||||
|
||||
|
|
@ -628,21 +676,21 @@ function four() {
|
|||
function five() {
|
||||
return "target";
|
||||
}`)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("line number stripping", () => {
|
||||
describe("line number stripping", () => {
|
||||
let strategy: MultiSearchReplaceDiffStrategy
|
||||
|
||||
beforeEach(() => {
|
||||
strategy = new MultiSearchReplaceDiffStrategy()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it("should strip line numbers from both search and replace sections", async () => {
|
||||
const originalContent = "function test() {\n return true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
describe("line number stripping", () => {
|
||||
describe("line number stripping", () => {
|
||||
let strategy: MultiSearchReplaceDiffStrategy
|
||||
|
||||
beforeEach(() => {
|
||||
strategy = new MultiSearchReplaceDiffStrategy()
|
||||
})
|
||||
|
||||
it("should strip line numbers from both search and replace sections", async () => {
|
||||
const originalContent = "function test() {\n return true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
1 | function test() {
|
||||
2 | return true;
|
||||
|
|
@ -653,16 +701,16 @@ function five() {
|
|||
3 | }
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\n return false;\n}\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\n return false;\n}\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should strip line numbers with leading spaces", async () => {
|
||||
const originalContent = "function test() {\n return true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
it("should strip line numbers with leading spaces", async () => {
|
||||
const originalContent = "function test() {\n return true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
1 | function test() {
|
||||
2 | return true;
|
||||
|
|
@ -673,16 +721,16 @@ function five() {
|
|||
3 | }
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\n return false;\n}\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\n return false;\n}\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should not strip when not all lines have numbers in either section", async () => {
|
||||
const originalContent = "function test() {\n return true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
it("should not strip when not all lines have numbers in either section", async () => {
|
||||
const originalContent = "function test() {\n return true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
1 | function test() {
|
||||
2 | return true;
|
||||
|
|
@ -693,13 +741,13 @@ function five() {
|
|||
3 | }
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it("should preserve content that naturally starts with pipe", async () => {
|
||||
const originalContent = "|header|another|\n|---|---|\n|data|more|\n"
|
||||
const diffContent = `test.ts
|
||||
it("should preserve content that naturally starts with pipe", async () => {
|
||||
const originalContent = "|header|another|\n|---|---|\n|data|more|\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
1 | |header|another|
|
||||
2 | |---|---|
|
||||
|
|
@ -710,16 +758,16 @@ function five() {
|
|||
3 | |data|updated|
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("|header|another|\n|---|---|\n|data|updated|\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("|header|another|\n|---|---|\n|data|updated|\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should preserve indentation when stripping line numbers", async () => {
|
||||
const originalContent = " function test() {\n return true;\n }\n"
|
||||
const diffContent = `test.ts
|
||||
it("should preserve indentation when stripping line numbers", async () => {
|
||||
const originalContent = " function test() {\n return true;\n }\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
1 | function test() {
|
||||
2 | return true;
|
||||
|
|
@ -730,16 +778,16 @@ function five() {
|
|||
3 | }
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(" function test() {\n return false;\n }\n")
|
||||
}
|
||||
})
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe(" function test() {\n return false;\n }\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle different line numbers between sections", async () => {
|
||||
const originalContent = "function test() {\n return true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
it("should handle different line numbers between sections", async () => {
|
||||
const originalContent = "function test() {\n return true;\n}\n"
|
||||
const diffContent = `test.ts
|
||||
<<<<<<< SEARCH
|
||||
10 | function test() {
|
||||
11 | return true;
|
||||
|
|
@ -750,11 +798,26 @@ function five() {
|
|||
22 | }
|
||||
>>>>>>> REPLACE`
|
||||
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\n return false;\n}\n")
|
||||
}
|
||||
const result = await strategy.applyDiff(originalContent, diffContent)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.content).toBe("function test() {\n return false;\n}\n")
|
||||
}
|
||||
})
|
||||
|
||||
it("detects search marker when expecting replace", () => {
|
||||
const diff = "<<<<<<< SEARCH\n" + "content\n" + "=======\n" + "new content\n" + "<<<<<<< SEARCH"
|
||||
const result = strategy["validateMarkerSequencing"](diff)
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toContain("'<<<<<<< SEARCH' found in your diff content")
|
||||
})
|
||||
|
||||
it("detects separator when expecting replace", () => {
|
||||
const diff = "<<<<<<< SEARCH\n" + "content\n" + "=======\n" + "new content\n" + "======="
|
||||
const result = strategy["validateMarkerSequencing"](diff)
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toContain("'=======' found in your diff content")
|
||||
})
|
||||
})
|
||||
|
||||
it("should not strip content that starts with pipe but no line number", async () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue