Files
zero/internal/tools/file_commit_test.go
KRATOS faec8ee201 feat(acp): emit structured file changes in tool updates (#999)
* feat(tools): retain bounded structured file diffs

* feat(acp): emit structured file changes in tool updates

* fix(acp): harden structured file diff transport

* fix(tools): reject unsafe rich diff previews

* fix(acp): preserve safe rich diff semantics

* fix(tools): bind structured diffs to committed changes

* fix(acp): preserve structured diff identity

* fix(tools): close rich diff race gaps

* fix(tools): report partial patch paths from workspace

* fix(tools): finalize structured diff evidence

* fix(tools): separate unverified patch writes

* test(tools): cover failed formatter recovery

* fix(acp): serialize file deletions as nullable diffs

* fix(tools): recreate files after formatter failure

* test(acp): require nullable diff fields on wire
2026-09-15 08:31:39 +08:00

132 lines
4.2 KiB
Go

package tools
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
)
func installFileWriteRace(t *testing.T, mutate func(string)) {
t.Helper()
prior := fileWriteBeforeCommit
fileWriteBeforeCommit = mutate
t.Cleanup(func() { fileWriteBeforeCommit = prior })
}
func installFileWriteStat(t *testing.T, stat func(*os.File) (os.FileInfo, error)) {
t.Helper()
prior := fileWriteStat
fileWriteStat = stat
t.Cleanup(func() { fileWriteStat = prior })
}
func TestWriteFileRefusesCreateAndOverwriteRaces(t *testing.T) {
t.Run("create", func(t *testing.T) {
root := t.TempDir()
target := filepath.Join(root, "created.txt")
installFileWriteRace(t, func(path string) {
if err := os.WriteFile(path, []byte("other writer\n"), 0o644); err != nil {
t.Fatal(err)
}
})
result := NewScopedWriteFileTool(root, nil).Run(context.Background(), map[string]any{
"path": "created.txt", "content": "zero\n",
})
if result.Status != StatusError {
t.Fatalf("raced create status = %s, want error", result.Status)
}
if got, err := os.ReadFile(target); err != nil || string(got) != "other writer\n" {
t.Fatalf("raced create content = %q, err=%v", got, err)
}
})
t.Run("overwrite", func(t *testing.T) {
root := t.TempDir()
target := filepath.Join(root, "existing.txt")
if err := os.WriteFile(target, []byte("observed\n"), 0o644); err != nil {
t.Fatal(err)
}
installFileWriteRace(t, func(path string) {
if err := os.WriteFile(path, []byte("other writer\n"), 0o644); err != nil {
t.Fatal(err)
}
})
result := NewScopedWriteFileTool(root, nil).Run(context.Background(), map[string]any{
"path": "existing.txt", "content": "zero\n", "overwrite": true,
})
if result.Status != StatusError || !strings.Contains(result.Output, errFileChangedDuringWrite.Error()) {
t.Fatalf("raced overwrite = %s: %s", result.Status, result.Output)
}
if got, err := os.ReadFile(target); err != nil || string(got) != "other writer\n" {
t.Fatalf("raced overwrite content = %q, err=%v", got, err)
}
})
}
func TestEditFileRefusesPreimageRace(t *testing.T) {
root := t.TempDir()
target := filepath.Join(root, "existing.txt")
if err := os.WriteFile(target, []byte("observed\n"), 0o644); err != nil {
t.Fatal(err)
}
installFileWriteRace(t, func(path string) {
if err := os.WriteFile(path, []byte("other writer\n"), 0o644); err != nil {
t.Fatal(err)
}
})
result := NewScopedEditFileTool(root, nil).Run(context.Background(), map[string]any{
"path": "existing.txt", "old_string": "observed", "new_string": "zero",
})
if result.Status != StatusError || !strings.Contains(result.Output, errFileChangedDuringWrite.Error()) {
t.Fatalf("raced edit = %s: %s", result.Status, result.Output)
}
if got, err := os.ReadFile(target); err != nil || string(got) != "other writer\n" {
t.Fatalf("raced edit content = %q, err=%v", got, err)
}
}
func TestOverwriteDoesNotStatOpenedFileAfterFinalPreimageComparison(t *testing.T) {
for name, run := range map[string]func(string) Result{
"write overwrite": func(root string) Result {
return NewScopedWriteFileTool(root, nil).Run(context.Background(), map[string]any{
"path": "existing.txt", "content": "zero\n", "overwrite": true,
})
},
"edit": func(root string) Result {
return NewScopedEditFileTool(root, nil).Run(context.Background(), map[string]any{
"path": "existing.txt", "old_string": "observed", "new_string": "zero",
})
},
} {
t.Run(name, func(t *testing.T) {
root := t.TempDir()
target := filepath.Join(root, "existing.txt")
if err := os.WriteFile(target, []byte("observed\n"), 0o644); err != nil {
t.Fatal(err)
}
statCalls := 0
installFileWriteStat(t, func(file *os.File) (os.FileInfo, error) {
statCalls++
if statCalls == 2 {
// This preserves the inode, so identity-only checks cannot detect it.
if err := os.WriteFile(target, []byte("other writer\n"), 0o644); err != nil {
t.Fatal(err)
}
}
return file.Stat()
})
result := run(root)
if result.Status != StatusOK {
t.Fatalf("overwrite status = %s: %s", result.Status, result.Output)
}
if statCalls != 1 {
t.Fatalf("opened file was statted %d times; the final byte comparison must be followed directly by mutation", statCalls)
}
})
}
}