package config import ( "strings" "testing" ) func TestResolveModel(t *testing.T) { p := &Provider{ Models: Models{ Default: "ds-chat", Sonnet: "ds-chat", Haiku: "ds-haiku", Opus: "ds-opus", Extra: map[string]string{"claude-3-5-haiku-20241022": "ds-fast"}, }, } cases := []struct { requested string want string }{ {"claude-sonnet-4-5-20250929", "ds-chat"}, {"claude-3-5-haiku-20241022", "ds-fast"}, // exact Extra match wins {"some-haiku-model", "ds-haiku"}, // keyword match {"claude-opus-4-1", "ds-opus"}, {"ds-chat", "ds-chat"}, // already an upstream name {"unknown-model", "ds-chat"}, {"", "ds-chat"}, } for _, tc := range cases { if got := p.ResolveModel(tc.requested); got != tc.want { t.Errorf("ResolveModel(%q) = %q, want %q", tc.requested, got, tc.want) } } } func TestResolveModelWithoutDefaults(t *testing.T) { p := &Provider{Models: Models{Sonnet: "kimi-k2"}} if got := p.ResolveModel("claude-3-7-sonnet"); got != "kimi-k2" { t.Errorf("sonnet request = %q, want kimi-k2", got) } // No default configured: unknown models pass through unchanged. if got := p.ResolveModel("weird-model"); got != "weird-model" { t.Errorf("unknown request = %q, want passthrough", got) } } func TestStoreRoundTrip(t *testing.T) { t.Setenv("CROSSRELAY_HOME", t.TempDir()) store, err := Load() if err != nil { t.Fatalf("Load: %v", err) } if !strings.HasPrefix(store.Config().RelayToken, "crl_") { t.Fatalf("relay token = %q, want crl_ prefix", store.Config().RelayToken) } if store.Config().Language != LanguageChinese { t.Fatalf("default language = %q", store.Config().Language) } p, err := store.AddProvider("DeepSeek", "deepseek", "https://api.deepseek.com/v1", "sk-test", Models{Default: "deepseek-chat", Sonnet: "deepseek-chat", Haiku: "deepseek-chat", Opus: "deepseek-chat"}) if err != nil { t.Fatalf("AddProvider: %v", err) } if _, err := store.ActivateClaude(p.ID); err != nil { t.Fatalf("ActivateClaude: %v", err) } reloaded, err := Load() if err != nil { t.Fatalf("reload: %v", err) } if got := reloaded.ActiveClaude(); got == nil || got.Name != "DeepSeek" { t.Fatalf("active provider after reload = %+v", got) } if len(reloaded.Config().Providers) != 1 { t.Fatalf("providers after reload = %d", len(reloaded.Config().Providers)) } } func TestAddProviderValidation(t *testing.T) { t.Setenv("CROSSRELAY_HOME", t.TempDir()) store, _ := Load() cases := []struct { name, baseURL, apiKey string }{ {"", "https://x.com/v1", "sk"}, {"p", "", "sk"}, {"p", "ftp://x.com", "sk"}, {"p", "https://x.com/v1", ""}, } for _, tc := range cases { if _, err := store.AddProvider(tc.name, "", tc.baseURL, tc.apiKey, Models{}); err == nil { t.Errorf("AddProvider(%q, %q, %q) succeeded, want error", tc.name, tc.baseURL, tc.apiKey) } } } func TestUpdateProviderKeepsKeyWhenEmpty(t *testing.T) { t.Setenv("CROSSRELAY_HOME", t.TempDir()) store, _ := Load() p, _ := store.AddProvider("p", "", "https://x.com/v1", "sk-secret", Models{Default: "m1"}) updated, err := store.UpdateProvider(p.ID, "p2", "", "https://x.com/v1/", "", Models{Default: "m2"}) if err != nil { t.Fatalf("UpdateProvider: %v", err) } if updated.APIKey != "sk-secret" { t.Errorf("api key = %q, want sk-secret", updated.APIKey) } if updated.Name != "p2" || updated.Models.Default != "m2" { t.Errorf("update lost fields: %+v", updated) } if updated.BaseURL != "https://x.com/v1" { t.Errorf("base url = %q, want trailing slash trimmed", updated.BaseURL) } } func TestDeleteProviderClearsActive(t *testing.T) { t.Setenv("CROSSRELAY_HOME", t.TempDir()) store, _ := Load() p, _ := store.AddProvider("p", "", "https://x.com/v1", "sk", Models{}) store.ActivateClaude(p.ID) if err := store.DeleteProvider(p.ID); err != nil { t.Fatalf("DeleteProvider: %v", err) } if store.ActiveClaude() != nil { t.Error("active provider survived deletion") } } func TestSetGatewayValidation(t *testing.T) { t.Setenv("CROSSRELAY_HOME", t.TempDir()) store, _ := Load() if err := store.SetGateway(Gateway{PortMode: "fixed", FixedPort: 8787}); err != nil { t.Fatalf("SetGateway: %v", err) } if err := store.SetGateway(Gateway{PortMode: "fixed", FixedPort: 0}); err == nil { t.Error("fixed port 0 accepted") } if err := store.SetGateway(Gateway{PortMode: "bogus"}); err == nil { t.Error("bogus port mode accepted") } if err := store.SetLanguage("fr"); err == nil { t.Error("unknown language accepted") } }