返回 DeepSeek-Reasonix
profile_spec_test.go
根目录 / internal / agent / profile_spec_test.go
1 package agent
2
3 import (
4 "testing"
5
6 "reasonix/internal/tool"
7 )
8
9 func TestIntersectToolLists(t *testing.T) {
10 got, err := IntersectToolLists(nil, []string{"read_file", "bash"}, []string{"bash", "write_file"})
11 if err != nil {
12 t.Fatal(err)
13 }
14 if len(got) != 1 || got[0] != "bash" {
15 t.Fatalf("got %v, want [bash]", got)
16 }
17 if _, err := IntersectToolLists(nil, []string{"read_file"}, []string{"write_file"}); err == nil {
18 t.Fatal("empty intersection should error")
19 }
20 got, err = IntersectToolLists(nil, nil, []string{"bash"})
21 if err != nil || len(got) != 1 || got[0] != "bash" {
22 t.Fatalf("profile empty → call list: %v %v", got, err)
23 }
24 got, err = IntersectToolLists(nil, []string{"bash"}, nil)
25 if err != nil || len(got) != 1 || got[0] != "bash" {
26 t.Fatalf("call empty → profile list: %v %v", got, err)
27 }
28 }
29
30 func TestIntersectToolListsExpandsPatternsAgainstLiveRegistry(t *testing.T) {
31 reg := tool.NewRegistry()
32 reg.Add(fakeTool{name: "mcp__github__search", readOnly: true})
33 reg.Add(fakeTool{name: "mcp__slack__search", readOnly: true})
34
35 tests := []struct {
36 name string
37 profileTools []string
38 callTools []string
39 }{
40 {
41 name: "profile pattern call literal",
42 profileTools: []string{"mcp__*__search"},
43 callTools: []string{"mcp__github__search"},
44 },
45 {
46 name: "profile literal call pattern",
47 profileTools: []string{"mcp__github__search"},
48 callTools: []string{"mcp__*__search"},
49 },
50 }
51 for _, tt := range tests {
52 t.Run(tt.name, func(t *testing.T) {
53 got, err := IntersectToolLists(reg, tt.profileTools, tt.callTools)
54 if err != nil {
55 t.Fatal(err)
56 }
57 if len(got) != 1 || got[0] != "mcp__github__search" {
58 t.Fatalf("got %v, want [mcp__github__search]", got)
59 }
60 })
61 }
62 }
63
64 func TestResolveModelEffortPrecedence(t *testing.T) {
65 // config override wins over call params.
66 m, e := ResolveModelEffort("cfg-m", "cfg-e", "call-m", "call-e", "prof-m", "prof-e", "glob-m", "glob-e")
67 if m != "cfg-m" || e != "cfg-e" {
68 t.Fatalf("got %s/%s", m, e)
69 }
70 // call wins over frontmatter when no config.
71 m, e = ResolveModelEffort("", "", "call-m", "call-e", "prof-m", "prof-e", "glob-m", "glob-e")
72 if m != "call-m" || e != "call-e" {
73 t.Fatalf("got %s/%s", m, e)
74 }
75 // frontmatter over global.
76 m, e = ResolveModelEffort("", "", "", "", "prof-m", "prof-e", "glob-m", "glob-e")
77 if m != "prof-m" || e != "prof-e" {
78 t.Fatalf("got %s/%s", m, e)
79 }
80 // global fallback.
81 m, e = ResolveModelEffort("", "", "", "", "", "", "glob-m", "glob-e")
82 if m != "glob-m" || e != "glob-e" {
83 t.Fatalf("got %s/%s", m, e)
84 }
85 }
86
87 func TestResolveProfileDefinition(t *testing.T) {
88 lookup := func(name string) (ProfileDefinition, bool) {
89 if name != "doc-rewriter" {
90 return ProfileDefinition{}, false
91 }
92 return ProfileDefinition{Name: "doc-rewriter", Body: "rewrite docs", ReadOnly: false}, true
93 }
94 if _, err := ResolveProfileDefinition(lookup, "missing"); err == nil {
95 t.Fatal("expected unknown profile error")
96 }
97 if _, err := ResolveProfileDefinition(nil, "doc-rewriter"); err == nil {
98 t.Fatal("expected unconfigured error")
99 }
100 def, err := ResolveProfileDefinition(lookup, "doc-rewriter")
101 if err != nil || def.Body != "rewrite docs" {
102 t.Fatalf("got %+v %v", def, err)
103 }
104 }
105
106 func TestNamedBuiltinProfile(t *testing.T) {
107 for _, name := range []string{"explore", "research", "review", "security-review", "security_review"} {
108 if !NamedBuiltinProfile(name) {
109 t.Fatalf("%s should be named builtin", name)
110 }
111 }
112 if NamedBuiltinProfile("doc-rewriter") {
113 t.Fatal("custom profile is not named builtin")
114 }
115 }
116
116 lines GO