Skip to content

Commit 43c2e85

Browse files
committed
test(settings): cover providers-first UX, dynamic options, verification
Tests for: providers before models in tree, model tiers are selects, options filtered by configured providers, empty-providers placeholder, profile filtering, AfterSet verify success/failure, ResolvedOptions fallback, nil verifyProvider handler.
1 parent 0d3ae54 commit 43c2e85

File tree

1 file changed

+202
-0
lines changed

1 file changed

+202
-0
lines changed

settings/settings_test.go

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,208 @@ func TestGWSCallbackAndNgrok(t *testing.T) {
498498
}
499499
}
500500

501+
func TestProvidersBeforeModels(t *testing.T) {
502+
cfg := config.Default()
503+
svc := testService(cfg)
504+
505+
modelsNode := svc.Tree()[1]
506+
if modelsNode.Category == nil || modelsNode.Category.Label != "Models" {
507+
t.Fatal("expected Models category at index 1")
508+
}
509+
510+
first := modelsNode.Category.Children[0]
511+
if first.Category == nil || first.Category.Key != "models.providers" {
512+
t.Errorf("first child of Models should be Providers, got %+v", first)
513+
}
514+
}
515+
516+
func TestModelTierFieldsAreSelects(t *testing.T) {
517+
cfg := config.Default()
518+
svc := testService(cfg)
519+
520+
for _, key := range []string{"models.default", "models.complex", "models.fast", "models.nano"} {
521+
f := findField(svc, key)
522+
if f == nil {
523+
t.Fatalf("%s field not found", key)
524+
}
525+
if f.Type != TypeSelect {
526+
t.Errorf("%s type = %d, want TypeSelect (%d)", key, f.Type, TypeSelect)
527+
}
528+
if f.OptionsFunc == nil {
529+
t.Errorf("%s should have OptionsFunc", key)
530+
}
531+
}
532+
}
533+
534+
func TestModelOptionsShowOnlyConfiguredProviders(t *testing.T) {
535+
cfg := &config.Config{
536+
Models: &config.ModelsConfig{
537+
Providers: map[string]config.ModelProviderConfig{
538+
"anthropic": {APIKeyRef: "keychain:obk/anthropic"},
539+
},
540+
},
541+
}
542+
svc := testService(cfg)
543+
544+
field := findField(svc, "models.default")
545+
if field == nil {
546+
t.Fatal("models.default not found")
547+
}
548+
549+
opts := svc.ResolvedOptions(field)
550+
for _, o := range opts {
551+
if o.Value == "" {
552+
continue
553+
}
554+
if !strings.HasPrefix(o.Value, "anthropic/") {
555+
t.Errorf("option %q should be from anthropic, got %q", o.Label, o.Value)
556+
}
557+
}
558+
if len(opts) < 2 {
559+
t.Errorf("expected at least (none) + 1 anthropic model, got %d options", len(opts))
560+
}
561+
}
562+
563+
func TestModelOptionsNoProvidersConfigured(t *testing.T) {
564+
cfg := &config.Config{}
565+
svc := testService(cfg)
566+
567+
field := findField(svc, "models.default")
568+
if field == nil {
569+
t.Fatal("models.default not found")
570+
}
571+
572+
opts := svc.ResolvedOptions(field)
573+
if len(opts) != 1 {
574+
t.Fatalf("expected 1 placeholder option, got %d", len(opts))
575+
}
576+
if opts[0].Value != "" {
577+
t.Errorf("placeholder option value = %q, want empty", opts[0].Value)
578+
}
579+
}
580+
581+
func TestProfileFilteredByConfiguredProviders(t *testing.T) {
582+
cfg := &config.Config{
583+
Models: &config.ModelsConfig{
584+
Providers: map[string]config.ModelProviderConfig{
585+
"gemini": {APIKeyRef: "keychain:obk/gemini"},
586+
},
587+
},
588+
}
589+
svc := testService(cfg)
590+
591+
field := findField(svc, "models.profile")
592+
if field == nil {
593+
t.Fatal("models.profile not found")
594+
}
595+
596+
opts := svc.ResolvedOptions(field)
597+
for _, o := range opts {
598+
if o.Value == "" {
599+
continue
600+
}
601+
p, ok := config.Profiles[o.Value]
602+
if !ok {
603+
continue
604+
}
605+
for _, req := range p.Providers {
606+
if req != "gemini" {
607+
t.Errorf("profile %q requires %q but only gemini is configured", o.Value, req)
608+
}
609+
}
610+
}
611+
}
612+
613+
func TestAfterSetCalledOnAPIKey(t *testing.T) {
614+
cfg := config.Default()
615+
verified := false
616+
svc := New(cfg,
617+
WithSaveFn(func(*config.Config) error { return nil }),
618+
WithStoreCred(func(ref, value string) error { return nil }),
619+
WithLoadCred(func(ref string) (string, error) { return "key", nil }),
620+
WithVerifyProvider(func(name string, pcfg config.ModelProviderConfig) error {
621+
verified = true
622+
return nil
623+
}),
624+
)
625+
626+
field := findField(svc, "models.providers.anthropic.api_key")
627+
if field == nil {
628+
t.Fatal("anthropic api_key not found")
629+
}
630+
if field.AfterSet == nil {
631+
t.Fatal("api_key field should have AfterSet")
632+
}
633+
634+
if err := svc.SetValue(field, "sk-test"); err != nil {
635+
t.Fatal(err)
636+
}
637+
638+
msg := field.AfterSet(svc)
639+
if !verified {
640+
t.Error("verifyProvider was not called")
641+
}
642+
if !strings.Contains(msg, "verified") {
643+
t.Errorf("AfterSet msg = %q, want to contain 'verified'", msg)
644+
}
645+
}
646+
647+
func TestAfterSetVerifyFailure(t *testing.T) {
648+
cfg := config.Default()
649+
svc := New(cfg,
650+
WithSaveFn(func(*config.Config) error { return nil }),
651+
WithStoreCred(func(ref, value string) error { return nil }),
652+
WithLoadCred(func(ref string) (string, error) { return "key", nil }),
653+
WithVerifyProvider(func(name string, pcfg config.ModelProviderConfig) error {
654+
return fmt.Errorf("invalid key")
655+
}),
656+
)
657+
658+
field := findField(svc, "models.providers.openai.api_key")
659+
if field == nil {
660+
t.Fatal("openai api_key not found")
661+
}
662+
663+
if err := svc.SetValue(field, "sk-bad"); err != nil {
664+
t.Fatal(err)
665+
}
666+
667+
msg := field.AfterSet(svc)
668+
if !strings.Contains(msg, "Warning") {
669+
t.Errorf("AfterSet msg = %q, want to contain 'Warning'", msg)
670+
}
671+
if !strings.Contains(msg, "invalid key") {
672+
t.Errorf("AfterSet msg = %q, want to contain error detail", msg)
673+
}
674+
}
675+
676+
func TestResolvedOptionsFallsBackToStatic(t *testing.T) {
677+
cfg := config.Default()
678+
svc := testService(cfg)
679+
680+
field := findField(svc, "mode")
681+
if field == nil {
682+
t.Fatal("mode field not found")
683+
}
684+
685+
opts := svc.ResolvedOptions(field)
686+
if len(opts) != 3 {
687+
t.Errorf("mode options count = %d, want 3", len(opts))
688+
}
689+
}
690+
691+
func TestVerifyProviderNilHandler(t *testing.T) {
692+
cfg := config.Default()
693+
svc := New(cfg,
694+
WithSaveFn(func(*config.Config) error { return nil }),
695+
)
696+
697+
err := svc.VerifyProvider("anthropic", config.ModelProviderConfig{})
698+
if err != nil {
699+
t.Errorf("nil verifyProvider should return nil, got %v", err)
700+
}
701+
}
702+
501703
func findField(svc *Service, key string) *Field {
502704
return findFieldInNodes(svc.Tree(), key)
503705
}

0 commit comments

Comments
 (0)