diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-10 23:59:21 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-10 23:59:21 +0300 |
| commit | 72ac39cb2bac5c176dd1277c9482334d0441286f (patch) | |
| tree | 91c68a1f03f0da64a6380f90643dc108e133f8de /internal/llm/provider_more_test.go | |
| parent | b9f90b4ffa8260cc906fa1b195ed0ba4aaa211df (diff) | |
Replace panics with returned errors in llm.RegisterProvider
RegisterProvider now returns an error for an empty name, a nil factory,
or a duplicate registration instead of panicking, making registration
composable and testable without recover(). RegisterAllProviders caches
the one-time registration error (sync.Once cannot return a value) and
returns it to every caller.
Updated all call sites: hexailsp, hexaicli and hexaiaction propagate the
error with context; test TestMains fail fast via panic. Added unit tests
covering empty name, nil factory, duplicate, success and idempotent
re-registration.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'internal/llm/provider_more_test.go')
| -rw-r--r-- | internal/llm/provider_more_test.go | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/internal/llm/provider_more_test.go b/internal/llm/provider_more_test.go index 18cd49a..407c684 100644 --- a/internal/llm/provider_more_test.go +++ b/internal/llm/provider_more_test.go @@ -13,6 +13,48 @@ func TestWithOptions_Apply(t *testing.T) { } } +func TestRegisterProvider_EmptyName(t *testing.T) { + // An empty (or whitespace-only) name must be rejected with an error + // instead of panicking, and must not mutate the registry. + if err := RegisterProvider(" ", func(Config, ProviderKeys) (Client, error) { return nil, nil }); err == nil { + t.Fatalf("expected error for empty provider name, got nil") + } +} + +func TestRegisterProvider_NilFactory(t *testing.T) { + // A nil factory is a programming error and must surface as an error. + if err := RegisterProvider("with-nil-factory", nil); err == nil { + t.Fatalf("expected error for nil factory, got nil") + } +} + +func TestRegisterProvider_Duplicate(t *testing.T) { + // "openai" is registered by RegisterAllProviders in TestMain, so a second + // registration under the same normalized name must return an error. + if err := RegisterProvider("OpenAI", func(Config, ProviderKeys) (Client, error) { return nil, nil }); err == nil { + t.Fatalf("expected error for duplicate provider, got nil") + } +} + +func TestRegisterProvider_Success(t *testing.T) { + // A fresh, valid registration succeeds and is then resolvable. + name := "test-register-success" + if err := RegisterProvider(name, func(Config, ProviderKeys) (Client, error) { return nil, nil }); err != nil { + t.Fatalf("unexpected error registering provider: %v", err) + } + if _, ok := lookupProviderFactory(name); !ok { + t.Fatalf("provider %q not found after successful registration", name) + } +} + +func TestRegisterAllProviders_Idempotent(t *testing.T) { + // RegisterAllProviders ran in TestMain; calling it again must return the + // same cached (nil) error without re-registering and tripping a duplicate. + if err := RegisterAllProviders(); err != nil { + t.Fatalf("RegisterAllProviders returned error on repeat call: %v", err) + } +} + func TestNewFromConfig_Success_OpenAI(t *testing.T) { // OpenAI success oc := Config{Provider: "openai", OpenAIBaseURL: "http://x", OpenAIModel: "gpt"} |
