返回 DeepSeek-Reasonix
write_claims_test.go
根目录 / internal / agent / write_claims_test.go
1 package agent
2
3 import (
4 "os"
5 "path/filepath"
6 "runtime"
7 "testing"
8 )
9
10 func TestNormalizeConcurrencyLimitsDefaults(t *testing.T) {
11 total, writers := NormalizeConcurrencyLimits(0, 0)
12 if total != DefaultMaxSubagentConcurrency || writers != DefaultMaxParallelWriters {
13 t.Fatalf("got %d/%d, want %d/%d", total, writers, DefaultMaxSubagentConcurrency, DefaultMaxParallelWriters)
14 }
15 total, writers = NormalizeConcurrencyLimits(10, 10)
16 if total != 10 || writers != 10 {
17 t.Fatalf("got %d/%d, want 10/10", total, writers)
18 }
19 total, writers = NormalizeConcurrencyLimits(4, 10)
20 if total != 4 || writers != 4 {
21 t.Fatalf("writers must not exceed total: got %d/%d", total, writers)
22 }
23 total, writers = NormalizeConcurrencyLimits(100, 50)
24 if total != MaxSubagentConcurrencyLimit || writers != MaxSubagentConcurrencyLimit {
25 t.Fatalf("clamp: got %d/%d", total, writers)
26 }
27 }
28
29 func TestNormalizeWritePathsRejectsGlobsAndEscape(t *testing.T) {
30 root := t.TempDir()
31 if _, err := NormalizeWritePaths(root, []string{"docs/*.md"}); err == nil {
32 t.Fatal("expected glob rejection")
33 }
34 outside := filepath.Join(filepath.Dir(root), "outside.txt")
35 if _, err := NormalizeWritePaths(root, []string{outside}); err == nil {
36 t.Fatal("expected workspace escape rejection")
37 }
38 // Relative file is fine even if it does not exist yet.
39 got, err := NormalizeWritePaths(root, []string{"docs/01.md"})
40 if err != nil {
41 t.Fatal(err)
42 }
43 if len(got.Paths) != 1 {
44 t.Fatalf("paths = %v", got.Paths)
45 }
46 if !filepath.IsAbs(got.Paths[0]) {
47 t.Fatalf("expected absolute path, got %q", got.Paths[0])
48 }
49 }
50
51 func TestWritePathOverlapParentChildAndCase(t *testing.T) {
52 root := t.TempDir()
53 a, err := NormalizeWritePaths(root, []string{"docs"})
54 if err != nil {
55 t.Fatal(err)
56 }
57 b, err := NormalizeWritePaths(root, []string{"docs/01.md"})
58 if err != nil {
59 t.Fatal(err)
60 }
61 if !a.Overlaps(b) {
62 t.Fatal("parent/child must overlap")
63 }
64 c, err := NormalizeWritePaths(root, []string{"other.md"})
65 if err != nil {
66 t.Fatal(err)
67 }
68 if a.Overlaps(c) {
69 t.Fatal("disjoint paths must not overlap")
70 }
71 if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
72 // Case-variant of the same relative path should collide.
73 upper := filepath.Join(root, "Docs")
74 _ = os.MkdirAll(upper, 0o755)
75 d, err := NormalizeWritePaths(root, []string{"Docs"})
76 if err != nil {
77 t.Fatal(err)
78 }
79 e, err := NormalizeWritePaths(root, []string{"docs"})
80 if err != nil {
81 t.Fatal(err)
82 }
83 if !d.Overlaps(e) {
84 t.Fatal("case-equivalent paths must overlap on this platform")
85 }
86 }
87 whole, err := WholeWorkspaceWriteClaim(root)
88 if err != nil {
89 t.Fatal(err)
90 }
91 if !whole.Overlaps(c) {
92 t.Fatal("whole workspace must overlap any path claim")
93 }
94 }
95
96 func TestValidateNonOverlappingWriteClaims(t *testing.T) {
97 root := t.TempDir()
98 a, _ := NormalizeWritePaths(root, []string{"a.md"})
99 b, _ := NormalizeWritePaths(root, []string{"b.md"})
100 if err := ValidateNonOverlappingWriteClaims([]WritePathSet{a, b}); err != nil {
101 t.Fatal(err)
102 }
103 c, _ := NormalizeWritePaths(root, []string{"a.md"})
104 if err := ValidateNonOverlappingWriteClaims([]WritePathSet{a, c}); err == nil {
105 t.Fatal("expected conflict")
106 }
107 }
108
109 func TestWritePathSetAllowsPath(t *testing.T) {
110 root := t.TempDir()
111 claim, err := NormalizeWritePaths(root, []string{"docs"})
112 if err != nil {
113 t.Fatal(err)
114 }
115 inside := filepath.Join(root, "docs", "x.md")
116 if !claim.AllowsPath(inside) {
117 t.Fatalf("should allow %s", inside)
118 }
119 outside := filepath.Join(root, "other.md")
120 if claim.AllowsPath(outside) {
121 t.Fatalf("should reject %s", outside)
122 }
123 }
124
124 lines GO