-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathagent_test.go
More file actions
304 lines (256 loc) · 8.64 KB
/
agent_test.go
File metadata and controls
304 lines (256 loc) · 8.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
package agentx
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSupportedAgents(t *testing.T) {
// Verify all expected agents are in the list
expected := []AgentType{
AgentTypeClaudeCode,
AgentTypeCursor,
AgentTypeWindsurf,
AgentTypeCopilot,
AgentTypeAider,
AgentTypeCody,
AgentTypeContinue,
AgentTypeCodePuppy,
AgentTypeKiro,
AgentTypeOpenCode,
AgentTypeCodex,
AgentTypeGoose,
AgentTypeAmp,
AgentTypeCline,
AgentTypeDroid,
AgentTypePi,
AgentTypeGemini,
AgentTypeOpenClaw,
AgentTypeConductor,
}
assert.Equal(t, len(expected), len(SupportedAgents), "SupportedAgents count mismatch")
for _, e := range expected {
found := false
for _, s := range SupportedAgents {
if s == e {
found = true
break
}
}
assert.True(t, found, "expected agent %s not found in SupportedAgents", e)
}
}
func TestAgentTypeConstants(t *testing.T) {
// Verify agent type slugs are correct
tests := []struct {
agentType AgentType
expected string
}{
{AgentTypeClaudeCode, "claude"},
{AgentTypeCursor, "cursor"},
{AgentTypeWindsurf, "windsurf"},
{AgentTypeCopilot, "copilot"},
{AgentTypeAider, "aider"},
{AgentTypeCody, "cody"},
{AgentTypeContinue, "continue"},
{AgentTypeCodePuppy, "code-puppy"},
{AgentTypeKiro, "kiro"},
{AgentTypeOpenCode, "opencode"},
{AgentTypeCodex, "codex"},
{AgentTypeGoose, "goose"},
{AgentTypeAmp, "amp"},
{AgentTypeCline, "cline"},
{AgentTypeDroid, "droid"},
{AgentTypeOpenClaw, "openclaw"},
{AgentTypeConductor, "conductor"},
}
for _, tt := range tests {
assert.Equal(t, tt.expected, string(tt.agentType), "AgentType %v mismatch", tt.agentType)
}
}
func TestMockEnvironment(t *testing.T) {
env := NewMockEnvironment(map[string]string{
"CLAUDECODE": "1",
"AGENT_ENV": "claude",
})
assert.Equal(t, "1", env.GetEnv("CLAUDECODE"), "GetEnv failed for CLAUDECODE")
assert.Equal(t, "claude", env.GetEnv("AGENT_ENV"), "GetEnv failed for AGENT_ENV")
assert.Equal(t, "", env.GetEnv("NONEXISTENT"), "GetEnv should return empty for nonexistent key")
val, ok := env.LookupEnv("CLAUDECODE")
assert.True(t, ok, "LookupEnv should return true for CLAUDECODE")
assert.Equal(t, "1", val, "LookupEnv value mismatch for CLAUDECODE")
_, ok = env.LookupEnv("NONEXISTENT")
assert.False(t, ok, "LookupEnv should return false for nonexistent key")
}
func TestSystemEnvironment(t *testing.T) {
env := NewSystemEnvironment()
// These should not error
_, err := env.HomeDir()
require.NoError(t, err, "HomeDir() should not error")
_, err = env.ConfigDir()
require.NoError(t, err, "ConfigDir() should not error")
_, err = env.DataDir()
require.NoError(t, err, "DataDir() should not error")
_, err = env.CacheDir()
require.NoError(t, err, "CacheDir() should not error")
goos := env.GOOS()
assert.NotEmpty(t, goos, "GOOS() should not be empty")
}
func TestRegistry(t *testing.T) {
reg := NewRegistry()
// Register a mock agent
agent := &mockAgent{
agentType: AgentTypeClaudeCode,
name: "Claude Code",
}
err := reg.Register(agent)
require.NoError(t, err, "Register() should not error")
// Get the agent back
got, ok := reg.Get(AgentTypeClaudeCode)
assert.True(t, ok, "Get() should return true for registered agent")
assert.Equal(t, AgentTypeClaudeCode, got.Type(), "Get() returned wrong agent type")
// List should include the agent
list := reg.List()
assert.Equal(t, 1, len(list), "List() should return 1 agent")
// Get nonexistent
_, ok = reg.Get(AgentTypeCursor)
assert.False(t, ok, "Get() should return false for unregistered agent")
}
func TestDetector(t *testing.T) {
reg := NewRegistry()
// Register a mock agent that always detects
agent := &mockAgent{
agentType: AgentTypeClaudeCode,
name: "Claude Code",
detectResult: true,
}
reg.Register(agent)
detector := reg.Detector()
// Should detect the agent
ctx := context.Background()
detected, err := detector.Detect(ctx)
require.NoError(t, err, "Detect() should not error")
require.NotNil(t, detected, "Detect() should return an agent")
assert.Equal(t, AgentTypeClaudeCode, detected.Type(), "Detect() returned wrong type")
}
func TestDetectOrchestrator(t *testing.T) {
reg := NewRegistry()
agent := &mockAgent{
agentType: AgentTypeClaudeCode,
name: "Claude Code",
detectResult: true,
}
orch := &mockAgent{
agentType: AgentTypeConductor,
name: "Conductor",
role: RoleOrchestrator,
detectResult: true,
}
reg.Register(agent)
reg.Register(orch)
ctx := context.Background()
d := reg.Detector()
// Detect() should return only the coding agent, not the orchestrator
detected, err := d.Detect(ctx)
require.NoError(t, err)
require.NotNil(t, detected)
assert.Equal(t, AgentTypeClaudeCode, detected.Type())
// DetectOrchestrator() should return only the orchestrator
detectedOrch, err := d.DetectOrchestrator(ctx)
require.NoError(t, err)
require.NotNil(t, detectedOrch)
assert.Equal(t, AgentTypeConductor, detectedOrch.Type())
}
func TestDetectOrchestrator_NoneRegistered(t *testing.T) {
reg := NewRegistry()
agent := &mockAgent{
agentType: AgentTypeClaudeCode,
name: "Claude Code",
detectResult: true,
}
reg.Register(agent)
ctx := context.Background()
d := reg.Detector()
// no orchestrators registered, should return nil
detectedOrch, err := d.DetectOrchestrator(ctx)
require.NoError(t, err)
assert.Nil(t, detectedOrch)
}
func TestDetect_SkipsOrchestrators(t *testing.T) {
reg := NewRegistry()
// register only an orchestrator
orch := &mockAgent{
agentType: AgentTypeOpenClaw,
name: "OpenClaw",
role: RoleOrchestrator,
detectResult: true,
}
reg.Register(orch)
ctx := context.Background()
d := reg.Detector()
// Detect() should return nil since only orchestrators are registered
detected, err := d.Detect(ctx)
require.NoError(t, err)
assert.Nil(t, detected)
}
func TestRequireAgent_NoAgent(t *testing.T) {
// Save and restore DefaultRegistry
orig := DefaultRegistry
defer func() { DefaultRegistry = orig }()
DefaultRegistry = NewRegistry()
// no agents registered — RequireAgent should return error message
msg := RequireAgent("ox session start")
assert.NotEmpty(t, msg, "RequireAgent should return error when no agent detected")
assert.Contains(t, msg, "ox session start")
assert.Contains(t, msg, "coding agent")
}
func TestRequireAgent_WithAgent(t *testing.T) {
orig := DefaultRegistry
defer func() { DefaultRegistry = orig }()
DefaultRegistry = NewRegistry()
DefaultRegistry.Register(&mockAgent{
agentType: AgentTypeClaudeCode,
name: "Claude Code",
detectResult: true,
})
msg := RequireAgent("ox session start")
assert.Empty(t, msg, "RequireAgent should return empty when agent is detected")
}
func TestRegister_Nil(t *testing.T) {
reg := NewRegistry()
err := reg.Register(nil)
assert.Error(t, err, "Register(nil) should error")
}
// mockAgent is a test implementation of Agent
type mockAgent struct {
agentType AgentType
name string
url string
role AgentRole
detectResult bool
capabilities Capabilities
}
func (a *mockAgent) Type() AgentType { return a.agentType }
func (a *mockAgent) Name() string { return a.name }
func (a *mockAgent) URL() string { return a.url }
func (a *mockAgent) Role() AgentRole {
if a.role != "" {
return a.role
}
return RoleAgent
}
func (a *mockAgent) Detect(ctx context.Context, env Environment) (bool, error) {
return a.detectResult, nil
}
func (a *mockAgent) UserConfigPath(env Environment) (string, error) { return "/mock/user/config", nil }
func (a *mockAgent) ProjectConfigPath() string { return ".mock" }
func (a *mockAgent) ContextFiles() []string { return []string{"MOCK.md"} }
func (a *mockAgent) SupportsXDGConfig() bool { return true }
func (a *mockAgent) Capabilities() Capabilities { return a.capabilities }
func (a *mockAgent) HookManager() HookManager { return nil }
func (a *mockAgent) CommandManager() CommandManager { return nil }
func (a *mockAgent) RulesManager() RulesManager { return nil }
func (a *mockAgent) IsInstalled(ctx context.Context, env Environment) (bool, error) { return true, nil }
func (a *mockAgent) DetectVersion(_ context.Context, _ Environment) string { return "" }
func (a *mockAgent) SupportsSession() bool { return false }
func (a *mockAgent) SessionID(_ Environment) string { return "" }