Update, bugfixes on diff and edit handling

This commit is contained in:
2026-02-18 21:49:05 +00:00
parent 9205b2bc26
commit 6980d3b294
23 changed files with 3406 additions and 2083 deletions
+79 -7
View File
@@ -357,7 +357,7 @@ func TestDetectIndentation(t *testing.T) {
name string
content string
want string
pos uint32
pos int
}{
{
name: "no indent",
@@ -410,6 +410,71 @@ func TestGenerateDiff(t *testing.T) {
}
}
func TestGenerateDiffLineLevelAccuracy(t *testing.T) {
// Regression test: diff must operate at line level, not character level.
// A character-level diff would split "hello" and "hello world" mid-line,
// producing broken output like:
// fmt.Println("hello
// + world
// ")
original := "package main\n\nfunc hello() {\n\tfmt.Println(\"hello\")\n}\n"
modified := "package main\n\nfunc hello() {\n\tfmt.Println(\"hello world\")\n}\n"
diff := generateDiff(original, modified, "test.go")
// The diff must show whole-line removals and additions
if !strings.Contains(diff, "-\tfmt.Println(\"hello\")\n") {
t.Errorf("diff should show full removed line, got:\n%s", diff)
}
if !strings.Contains(diff, "+\tfmt.Println(\"hello world\")\n") {
t.Errorf("diff should show full added line, got:\n%s", diff)
}
// The diff must NOT split lines at character boundaries
if strings.Contains(diff, "+hello") && !strings.Contains(diff, "Println") {
t.Errorf("diff appears to be character-level (split mid-line), got:\n%s", diff)
}
// Context lines should not be marked as changed
for line := range strings.SplitSeq(diff, "\n") {
if strings.HasPrefix(line, "-") || strings.HasPrefix(line, "+") {
// Changed lines should only be the Println lines
if strings.Contains(line, "package main") ||
strings.Contains(line, "func hello()") {
t.Errorf("unchanged line incorrectly marked as changed: %q", line)
}
}
}
}
func TestGenerateDiffNoPhantomChanges(t *testing.T) {
// Regression test: replacing a line range should not produce phantom
// +/- lines for unchanged code after the edit region.
original := "line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\n"
modified := "line1\nREPLACED\nline3\nline4\nline5\nline6\nline7\nline8\n"
diff := generateDiff(original, modified, "test.txt")
// Count changed lines (excluding headers)
addCount := 0
delCount := 0
for line := range strings.SplitSeq(diff, "\n") {
if strings.HasPrefix(line, "+") && !strings.HasPrefix(line, "+++") {
addCount++
}
if strings.HasPrefix(line, "-") && !strings.HasPrefix(line, "---") {
delCount++
}
}
if addCount != 1 {
t.Errorf("expected 1 added line, got %d. Diff:\n%s", addCount, diff)
}
if delCount != 1 {
t.Errorf("expected 1 deleted line, got %d. Diff:\n%s", delCount, diff)
}
}
// ==================== Text-based editing tests ====================
func TestTextEditWithExactText(t *testing.T) {
@@ -593,7 +658,7 @@ SECRET_KEY=abc123
}
}
func TestTextEditMultipleMatchesError(t *testing.T) {
func TestTextEditMultipleMatchesSelectsFirst(t *testing.T) {
registry := parser.NewRegistry()
defer registry.Close()
e := NewEngine(registry)
@@ -624,12 +689,19 @@ more code
t.Fatalf("apply failed: %v", err)
}
// Should fail because of multiple matches
if result.Success {
t.Error("expected error for multiple matches without index")
// Index 0 (default) should select the first match
if !result.Success {
t.Fatalf("expected success for multiple matches with default index 0: %s", result.Error)
}
if !strings.Contains(result.Error, "matches") {
t.Errorf("error should mention multiple matches: %s", result.Error)
// Verify only first TODO was replaced
fileContent, _ := os.ReadFile(tmpFile)
contentStr := string(fileContent)
if !strings.Contains(contentStr, "DONE: fix this") {
t.Error("first TODO should be replaced with DONE")
}
if !strings.Contains(contentStr, "TODO: also fix this") {
t.Error("second TODO should be unchanged")
}
}