161 lines
3.5 KiB
Go
161 lines
3.5 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestDefaults(t *testing.T) {
|
|
d := Defaults()
|
|
|
|
if d.Port != 8976 {
|
|
t.Errorf("expected port 8976, got %d", d.Port)
|
|
}
|
|
if d.CursorCLIPath != "agent" {
|
|
t.Errorf("expected cursor_cli_path 'agent', got %q", d.CursorCLIPath)
|
|
}
|
|
if d.DefaultModel != "auto" {
|
|
t.Errorf("expected default_model 'auto', got %q", d.DefaultModel)
|
|
}
|
|
if d.Timeout != 300 {
|
|
t.Errorf("expected timeout 300, got %d", d.Timeout)
|
|
}
|
|
if d.MaxConcurrent != 5 {
|
|
t.Errorf("expected max_concurrent 5, got %d", d.MaxConcurrent)
|
|
}
|
|
if d.LogLevel != "INFO" {
|
|
t.Errorf("expected log_level 'INFO', got %q", d.LogLevel)
|
|
}
|
|
if d.UseACP {
|
|
t.Errorf("expected use_acp false by default, got true")
|
|
}
|
|
}
|
|
|
|
func TestLoadValidYAML(t *testing.T) {
|
|
content := `port: 9000
|
|
cursor_cli_path: mycli
|
|
default_model: gpt-5.2
|
|
timeout: 60
|
|
max_concurrent: 10
|
|
use_acp: true
|
|
log_level: DEBUG
|
|
available_models:
|
|
- gpt-5.2
|
|
- claude-sonnet-4-20250514
|
|
`
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "config.yaml")
|
|
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
cfg, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
want := Config{
|
|
Port: 9000,
|
|
CursorCLIPath: "mycli",
|
|
DefaultModel: "gpt-5.2",
|
|
Timeout: 60,
|
|
MaxConcurrent: 10,
|
|
UseACP: true,
|
|
ChatOnlyWorkspace: true,
|
|
LogLevel: "DEBUG",
|
|
AvailableModels: []string{"gpt-5.2", "claude-sonnet-4-20250514"},
|
|
SystemPrompt: DefaultSystemPrompt,
|
|
CursorMode: "plan",
|
|
WorkspaceRoot: "",
|
|
}
|
|
|
|
if !reflect.DeepEqual(*cfg, want) {
|
|
t.Errorf("mismatch\n got: %+v\nwant: %+v", *cfg, want)
|
|
}
|
|
}
|
|
|
|
func TestLoadMissingFile(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "does-not-exist.yaml")
|
|
|
|
cfg, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("expected no error for missing file, got: %v", err)
|
|
}
|
|
|
|
d := Defaults()
|
|
if !reflect.DeepEqual(*cfg, d) {
|
|
t.Errorf("expected defaults\n got: %+v\nwant: %+v", *cfg, d)
|
|
}
|
|
}
|
|
|
|
func TestLoadInvalidYAML(t *testing.T) {
|
|
content := `{{not valid yaml`
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "bad.yaml")
|
|
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := Load(path)
|
|
if err == nil {
|
|
t.Fatal("expected error for invalid YAML, got nil")
|
|
}
|
|
}
|
|
|
|
func TestLoadValidation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
yaml string
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "zero port",
|
|
yaml: "port: 0\ncursor_cli_path: agent\ntimeout: 10\n",
|
|
wantErr: "port must be > 0",
|
|
},
|
|
{
|
|
name: "empty cursor_cli_path",
|
|
yaml: "port: 80\ncursor_cli_path: \"\"\ntimeout: 10\n",
|
|
wantErr: "cursor_cli_path must not be empty",
|
|
},
|
|
{
|
|
name: "zero timeout",
|
|
yaml: "port: 80\ncursor_cli_path: agent\ntimeout: 0\n",
|
|
wantErr: "timeout must be > 0",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "config.yaml")
|
|
if err := os.WriteFile(path, []byte(tt.yaml), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := Load(path)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if got := err.Error(); !contains(got, tt.wantErr) {
|
|
t.Errorf("error %q should contain %q", got, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func contains(s, substr string) bool {
|
|
return len(s) >= len(substr) && searchSubstring(s, substr)
|
|
}
|
|
|
|
func searchSubstring(s, substr string) bool {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|