clone

an unofficial pure go sdk for the typesafe api: typed answers, retries and no dependencies

main
typesafe-go / options_test.go
options_test.go 2.6K
1package typesafe23import (4 "context"5 "net/http"6 "testing"7 "time"8)910func clearEnvironment(t *testing.T) {11 t.Helper()12 for _, key := range []string{"TYPESAFE_API_KEY", "TYPESAFE_BASE_URL", "TYPESAFE_DEFAULT_MODEL"} {13 t.Setenv(key, "")14 }15}1617func TestClientOptionsValidate(t *testing.T) {18 clearEnvironment(t)19 if _, err := NewClient(); err == nil {20 t.Fatal("missing API key must fail")21 }22 tests := map[string]Option{23 "empty key": WithAPIKey(" "), "negative timeout": WithTimeout(-time.Second),24 "zero timeout": WithTimeout(0), "negative retries": WithMaxRetries(-1),25 "nil transport": WithHTTPClient(nil), "empty model": WithModel(" "),26 "invalid URL": WithBaseURL(":bad"), "URL credentials": WithBaseURL("https://a:b@example.com"),27 "URL query": WithBaseURL("https://example.com?x=y"), "URL fragment": WithBaseURL("https://example.com/#x"),28 "URL scheme": WithBaseURL("file:///tmp/x"), "nil option": nil,29 "bad policy": WithRetryPolicy(RetryPolicy{Jitter: 2}),30 }31 for name, option := range tests {32 t.Run(name, func(t *testing.T) {33 if _, err := NewClient(WithAPIKey("key"), option); err == nil {34 t.Fatal("invalid configuration accepted")35 }36 })37 }38}3940func TestEnvironmentAndExplicitPrecedence(t *testing.T) {41 clearEnvironment(t)42 t.Setenv("TYPESAFE_API_KEY", " env-key ")43 t.Setenv("TYPESAFE_DEFAULT_MODEL", " env-model ")44 t.Setenv("TYPESAFE_BASE_URL", "https://env.example/")45 client, err := NewClient()46 if err != nil {47 t.Fatal(err)48 }49 if client.config.apiKey != "env-key" || client.config.model != "env-model" || client.config.baseURL != "https://env.example" {50 t.Fatal("environment configuration not resolved")51 }52 client, err = NewClient(WithAPIKey("explicit"), WithModel("explicit"), WithBaseURL("https://explicit.example"))53 if err != nil || client.config.apiKey != "explicit" || client.config.model != "explicit" || client.config.baseURL != "https://explicit.example" {54 t.Fatal("explicit configuration did not take precedence")55 }56}5758func TestHeadersAreCopiedAndProtected(t *testing.T) {59 headers := http.Header{"X-Custom": {"original"}, "authorization": {"injected"}, "X-Typesafe-Retry-Count": {"999"}}60 client := testClient(t, func(w http.ResponseWriter, r *http.Request) {61 if r.Header.Get("X-Custom") != "original" || r.Header.Get("Authorization") != "Bearer test-key" {62 t.Error("headers were mutated or authentication overridden")63 }64 if r.Header.Get("X-TypeSafe-Retry-Count") != "" {65 t.Error("retry count overridden")66 }67 writeResponse(t, w, `{"models":[]}`)68 }, WithHeaders(headers))69 headers.Set("X-Custom", "mutated")70 if _, err := client.ListModels(context.Background()); err != nil {71 t.Fatal(err)72 }73}