425f12db38
Changes the AlbumCoverProvider and ArtistArtProvider interfaces from MBID-only string parameters to ref-struct signatures so name-based providers (Deezer, Last.fm in upcoming tasks) can act on rows without MBIDs. Today, 53 of 213 artists in the dev DB have NULL MBIDs — featured artists, remixers, and compilation contributors created from track-tag splits where the primary-artist MBID is in the file but collaborator IDs aren't. These rows are unreachable by the current MBID-only chain. Refactoring the interface unblocks future name-based providers from acting on them. TheAudioDB and MBCAA keep MBID-only behavior internally: they return ErrNotFound when ref.MBID is empty rather than attempting a name-based fallback. The MBID guard inside EnrichAlbum/EnrichArtist is removed; providers receive the ref unconditionally and decide whether they can act on it. GetAlbumWithFirstTrackPath now JOINs artists to return artist_name alongside the existing fields, supporting AlbumRef construction. No behavioral change today (only TheAudioDB + MBCAA registered, both keep MBID-only behavior). The change unblocks T3 (Deezer) and T4 (Last.fm) which can now register and act on every artist/album regardless of MBID presence. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
117 lines
3.0 KiB
Go
117 lines
3.0 KiB
Go
package coverart
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
// fakeProvider is a minimal Provider for registry tests. Does not
|
|
// implement any capability interface.
|
|
type fakeProvider struct {
|
|
id string
|
|
display string
|
|
requiresKey bool
|
|
defaultOn bool
|
|
}
|
|
|
|
func (f *fakeProvider) ID() string { return f.id }
|
|
func (f *fakeProvider) DisplayName() string { return f.display }
|
|
func (f *fakeProvider) RequiresAPIKey() bool { return f.requiresKey }
|
|
func (f *fakeProvider) DefaultEnabled() bool { return f.defaultOn }
|
|
func (f *fakeProvider) Configure(_ ProviderSettings) error { return nil }
|
|
|
|
// fakeAlbumProvider opts into the AlbumCoverProvider capability for
|
|
// the capability-filter test.
|
|
type fakeAlbumProvider struct {
|
|
fakeProvider
|
|
}
|
|
|
|
func (f *fakeAlbumProvider) FetchAlbumCover(_ context.Context, _ AlbumRef) ([]byte, error) {
|
|
return []byte("img"), nil
|
|
}
|
|
|
|
func TestRegister_AddsProvider(t *testing.T) {
|
|
resetRegistryForTests()
|
|
defer resetRegistryForTests()
|
|
|
|
p := &fakeProvider{id: "fake1", display: "Fake One"}
|
|
Register(p)
|
|
|
|
all := AllProviders()
|
|
if len(all) != 1 {
|
|
t.Fatalf("AllProviders len = %d, want 1", len(all))
|
|
}
|
|
if all[0].ID() != "fake1" {
|
|
t.Errorf("ID = %q, want %q", all[0].ID(), "fake1")
|
|
}
|
|
}
|
|
|
|
func TestRegister_PanicsOnDuplicateID(t *testing.T) {
|
|
resetRegistryForTests()
|
|
defer resetRegistryForTests()
|
|
|
|
Register(&fakeProvider{id: "dup"})
|
|
|
|
defer func() {
|
|
if r := recover(); r == nil {
|
|
t.Fatal("expected panic on duplicate ID")
|
|
}
|
|
}()
|
|
Register(&fakeProvider{id: "dup"}) // should panic
|
|
}
|
|
|
|
func TestProviderByID_Found(t *testing.T) {
|
|
resetRegistryForTests()
|
|
defer resetRegistryForTests()
|
|
|
|
Register(&fakeProvider{id: "x", display: "X"})
|
|
|
|
p, err := ProviderByID("x")
|
|
if err != nil {
|
|
t.Fatalf("err = %v, want nil", err)
|
|
}
|
|
if p.DisplayName() != "X" {
|
|
t.Errorf("display = %q, want %q", p.DisplayName(), "X")
|
|
}
|
|
}
|
|
|
|
func TestProviderByID_NotFound(t *testing.T) {
|
|
resetRegistryForTests()
|
|
defer resetRegistryForTests()
|
|
|
|
_, err := ProviderByID("missing")
|
|
if !errors.Is(err, ErrProviderNotFound) {
|
|
t.Errorf("err = %v, want ErrProviderNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestCapabilityFiltering(t *testing.T) {
|
|
resetRegistryForTests()
|
|
defer resetRegistryForTests()
|
|
|
|
plain := &fakeProvider{id: "plain"}
|
|
withAlbum := &fakeAlbumProvider{fakeProvider: fakeProvider{id: "alb"}}
|
|
Register(plain)
|
|
Register(withAlbum)
|
|
|
|
if got := len(AllProviders()); got != 2 {
|
|
t.Fatalf("AllProviders len = %d, want 2", got)
|
|
}
|
|
|
|
// Type-assert to count AlbumCoverProvider implementers — mimics
|
|
// what SettingsService.EnabledAlbumProviders does internally.
|
|
var albumProviders []AlbumCoverProvider
|
|
for _, p := range AllProviders() {
|
|
if ap, ok := p.(AlbumCoverProvider); ok {
|
|
albumProviders = append(albumProviders, ap)
|
|
}
|
|
}
|
|
if len(albumProviders) != 1 {
|
|
t.Fatalf("AlbumCoverProvider count = %d, want 1", len(albumProviders))
|
|
}
|
|
if albumProviders[0].ID() != "alb" {
|
|
t.Errorf("AlbumCoverProvider[0].ID = %q, want %q", albumProviders[0].ID(), "alb")
|
|
}
|
|
}
|