返回 DeepSeek-Reasonix
publish_test.go
根目录 / internal / tool / builtin / publish_test.go
1 package builtin
2
3 import (
4 "context"
5 "errors"
6 "os"
7 "path/filepath"
8 "testing"
9 )
10
11 func TestWriteFileRejectsChangeBetweenReadAndPublish(t *testing.T) {
12 dir := t.TempDir()
13 f := filepath.Join(dir, "x.txt")
14 if err := os.WriteFile(f, []byte("old"), 0o644); err != nil {
15 t.Fatal(err)
16 }
17 src, err := readEditSource(context.Background(), nil, f)
18 if err != nil {
19 t.Fatal(err)
20 }
21 if err := os.WriteFile(f, []byte("external"), 0o644); err != nil {
22 t.Fatal(err)
23 }
24 if err := src.write(context.Background(), nil, f, "new"); !errors.Is(err, ErrFileChanged) {
25 t.Fatalf("write after external edit: %v, want ErrFileChanged", err)
26 }
27 got, err := os.ReadFile(f)
28 if err != nil {
29 t.Fatal(err)
30 }
31 if string(got) != "external" {
32 t.Fatalf("destination overwritten: %q", got)
33 }
34 }
35
36 func TestWriteFileRejectsCreateWhenFileAppears(t *testing.T) {
37 f := filepath.Join(t.TempDir(), "new.txt")
38 src, err := readEditSource(context.Background(), nil, f)
39 if !os.IsNotExist(err) {
40 t.Fatalf("missing file err = %v, want NotExist", err)
41 }
42 if err := os.WriteFile(f, []byte("raced"), 0o644); err != nil {
43 t.Fatal(err)
44 }
45 if err := src.write(context.Background(), nil, f, "created"); !errors.Is(err, ErrFileChanged) {
46 t.Fatalf("create after race: %v, want ErrFileChanged", err)
47 }
48 got, _ := os.ReadFile(f)
49 if string(got) != "raced" {
50 t.Fatalf("raced file overwritten: %q", got)
51 }
52 }
53
54 type mutatingOverlay struct {
55 content string
56 writes int
57 }
58
59 func (m *mutatingOverlay) ReadTextFile(ctx context.Context, path string) (string, bool) {
60 return m.content, true
61 }
62
63 func (m *mutatingOverlay) WriteTextFile(ctx context.Context, path, content string) (bool, error) {
64 m.writes++
65 m.content = content
66 return true, nil
67 }
68
69 func TestEditSourceRejectsOverlayChange(t *testing.T) {
70 f := filepath.Join(t.TempDir(), "buf.txt")
71 if err := os.WriteFile(f, []byte("disk"), 0o644); err != nil {
72 t.Fatal(err)
73 }
74 ov := &mutatingOverlay{content: "buffer"}
75 src, err := readEditSource(context.Background(), ov, f)
76 if err != nil {
77 t.Fatal(err)
78 }
79 ov.content = "someone else typed"
80 if err := src.write(context.Background(), ov, f, "tool write"); !errors.Is(err, ErrFileChanged) {
81 t.Fatalf("overlay write: %v, want ErrFileChanged", err)
82 }
83 if ov.writes != 0 {
84 t.Fatalf("overlay write count = %d, want 0", ov.writes)
85 }
86 }
87
87 lines GO