package coverart import ( "context" "errors" "testing" ) // fakeArtistProvider opts into ArtistArtProvider for capability tests. type fakeArtistProvider struct { fakeProvider } func (f *fakeArtistProvider) FetchArtistArt(_ context.Context, _ string) (thumb, fanart []byte, err error) { return []byte("t"), []byte("f"), nil } // fakeTestableAlbumProvider implements TestableProvider for the // TestProvider test. type fakeTestableAlbumProvider struct { fakeAlbumProvider testErr error } func (f *fakeTestableAlbumProvider) TestConnection(_ context.Context) error { return f.testErr } func TestSettingsService_BootInsertsDefaultRows(t *testing.T) { pool := newPool(t) resetRegistryForTests() defer resetRegistryForTests() Register(&fakeAlbumProvider{fakeProvider: fakeProvider{id: "fake-album", display: "Fake Album", defaultOn: true}}) Register(&fakeArtistProvider{fakeProvider: fakeProvider{id: "fake-artist", display: "Fake Artist", defaultOn: false}}) s, err := NewSettingsService(context.Background(), pool, discardLogger()) if err != nil { t.Fatalf("NewSettingsService: %v", err) } // Both providers should now have rows; only fake-album is enabled. enabled := s.EnabledAlbumProviders() if len(enabled) != 1 { t.Fatalf("EnabledAlbumProviders = %d, want 1", len(enabled)) } if enabled[0].ID() != "fake-album" { t.Errorf("enabled[0].ID = %q, want fake-album", enabled[0].ID()) } // fake-artist defaultOn=false, so it should NOT be in EnabledArtistProviders. artists := s.EnabledArtistProviders() if len(artists) != 0 { t.Errorf("EnabledArtistProviders = %d, want 0", len(artists)) } if s.CurrentVersion() != 1 { t.Errorf("CurrentVersion = %d, want 1", s.CurrentVersion()) } } func TestSettingsService_UpdateProvider_FlippingEnabledBumpsVersion(t *testing.T) { pool := newPool(t) resetRegistryForTests() defer resetRegistryForTests() Register(&fakeAlbumProvider{fakeProvider: fakeProvider{id: "fake-album", defaultOn: true}}) s, err := NewSettingsService(context.Background(), pool, discardLogger()) if err != nil { t.Fatal(err) } startVersion := s.CurrentVersion() disabled := false bumped, err := s.UpdateProvider(context.Background(), "fake-album", ProviderUpdatePatch{Enabled: &disabled}) if err != nil { t.Fatalf("UpdateProvider: %v", err) } if !bumped { t.Error("versionBumped = false, want true after disabling") } if s.CurrentVersion() <= startVersion { t.Errorf("CurrentVersion = %d, want > %d", s.CurrentVersion(), startVersion) } enabled := s.EnabledAlbumProviders() if len(enabled) != 0 { t.Errorf("after disable: EnabledAlbumProviders = %d, want 0", len(enabled)) } } func TestSettingsService_UpdateProvider_KeyOnlyDoesNotBumpVersion(t *testing.T) { pool := newPool(t) resetRegistryForTests() defer resetRegistryForTests() Register(&fakeAlbumProvider{fakeProvider: fakeProvider{id: "fake-album", defaultOn: true}}) s, err := NewSettingsService(context.Background(), pool, discardLogger()) if err != nil { t.Fatal(err) } startVersion := s.CurrentVersion() newKey := "abc123" bumped, err := s.UpdateProvider(context.Background(), "fake-album", ProviderUpdatePatch{APIKey: &newKey}) if err != nil { t.Fatalf("UpdateProvider: %v", err) } if bumped { t.Error("versionBumped = true, want false for key-only change") } if s.CurrentVersion() != startVersion { t.Errorf("CurrentVersion changed: %d → %d, want unchanged", startVersion, s.CurrentVersion()) } infos := s.ListProviderInfo() var info ProviderInfo for _, i := range infos { if i.ID == "fake-album" { info = i break } } if !info.APIKeySet { t.Error("APIKeySet = false, want true after setting key") } } func TestSettingsService_UpdateProvider_ClearKey(t *testing.T) { pool := newPool(t) resetRegistryForTests() defer resetRegistryForTests() Register(&fakeAlbumProvider{fakeProvider: fakeProvider{id: "fake-album", defaultOn: true}}) s, err := NewSettingsService(context.Background(), pool, discardLogger()) if err != nil { t.Fatal(err) } // Set a key, then clear it. setKey := "abc" if _, err := s.UpdateProvider(context.Background(), "fake-album", ProviderUpdatePatch{APIKey: &setKey}); err != nil { t.Fatal(err) } emptyKey := "" if _, err := s.UpdateProvider(context.Background(), "fake-album", ProviderUpdatePatch{APIKey: &emptyKey}); err != nil { t.Fatal(err) } infos := s.ListProviderInfo() for _, i := range infos { if i.ID == "fake-album" && i.APIKeySet { t.Error("APIKeySet = true after clear, want false") } } } func TestSettingsService_TestProvider_Routing(t *testing.T) { pool := newPool(t) resetRegistryForTests() defer resetRegistryForTests() plain := &fakeAlbumProvider{fakeProvider: fakeProvider{id: "plain", defaultOn: true}} testable := &fakeTestableAlbumProvider{ fakeAlbumProvider: fakeAlbumProvider{fakeProvider: fakeProvider{id: "testable", defaultOn: true}}, testErr: nil, } Register(plain) Register(testable) s, err := NewSettingsService(context.Background(), pool, discardLogger()) if err != nil { t.Fatal(err) } // Testable returns nil → success. if err := s.TestProvider(context.Background(), "testable"); err != nil { t.Errorf("TestProvider(testable) = %v, want nil", err) } // Plain doesn't implement TestableProvider → ErrNotTestable. if err := s.TestProvider(context.Background(), "plain"); !errors.Is(err, ErrNotTestable) { t.Errorf("TestProvider(plain) = %v, want ErrNotTestable", err) } // Missing → ErrProviderNotFound. if err := s.TestProvider(context.Background(), "missing"); !errors.Is(err, ErrProviderNotFound) { t.Errorf("TestProvider(missing) = %v, want ErrProviderNotFound", err) } } func TestSettingsService_ListProviderInfo_Capabilities(t *testing.T) { pool := newPool(t) resetRegistryForTests() defer resetRegistryForTests() plain := &fakeProvider{id: "plain", defaultOn: true} album := &fakeAlbumProvider{fakeProvider: fakeProvider{id: "album-only", defaultOn: true}} artist := &fakeArtistProvider{fakeProvider: fakeProvider{id: "artist-only", defaultOn: true}} Register(plain) Register(album) Register(artist) s, err := NewSettingsService(context.Background(), pool, discardLogger()) if err != nil { t.Fatal(err) } infos := s.ListProviderInfo() if len(infos) != 3 { t.Fatalf("ListProviderInfo len = %d, want 3", len(infos)) } byID := map[string]ProviderInfo{} for _, i := range infos { byID[i.ID] = i } if got := byID["plain"].Supports; len(got) != 0 { t.Errorf("plain.Supports = %v, want empty", got) } if got := byID["album-only"].Supports; len(got) != 1 || got[0] != "album_cover" { t.Errorf("album-only.Supports = %v, want [album_cover]", got) } if got := byID["artist-only"].Supports; len(got) != 2 || got[0] != "artist_thumb" || got[1] != "artist_fanart" { t.Errorf("artist-only.Supports = %v, want [artist_thumb, artist_fanart]", got) } }