package api import ( "context" "os" "path/filepath" "testing" "github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgxpool" "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) func TestAudioContentType(t *testing.T) { cases := map[string]string{ "mp3": "audio/mpeg", "MP3": "audio/mpeg", "flac": "audio/flac", "ogg": "audio/ogg", "opus": "audio/ogg", "m4a": "audio/mp4", "aac": "audio/aac", "wav": "audio/wav", "unknown": "application/octet-stream", "": "application/octet-stream", } for in, want := range cases { if got := audioContentType(in); got != want { t.Errorf("audioContentType(%q) = %q, want %q", in, got, want) } } } func TestImageContentType(t *testing.T) { cases := map[string]string{ "/a/cover.jpg": "image/jpeg", "/a/cover.JPG": "image/jpeg", "/a/cover.jpeg": "image/jpeg", "/a/cover.png": "image/png", "/a/cover.webp": "image/webp", "/a/cover.gif": "image/gif", "/a/cover.bmp": "application/octet-stream", "/a/cover": "application/octet-stream", } for in, want := range cases { if got := imageContentType(in); got != want { t.Errorf("imageContentType(%q) = %q, want %q", in, got, want) } } } func TestFindSidecarCover_PrefersCoverOverFolder(t *testing.T) { dir := t.TempDir() if err := os.WriteFile(filepath.Join(dir, "cover.jpg"), []byte("c"), 0o644); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "folder.jpg"), []byte("f"), 0o644); err != nil { t.Fatal(err) } got := findSidecarCover(filepath.Join(dir, "any-track.flac")) if got != filepath.Join(dir, "cover.jpg") { t.Errorf("got %q, want cover.jpg path", got) } } func TestFindSidecarCover_FallsBackToFolder(t *testing.T) { dir := t.TempDir() if err := os.WriteFile(filepath.Join(dir, "folder.png"), []byte("f"), 0o644); err != nil { t.Fatal(err) } got := findSidecarCover(filepath.Join(dir, "t.flac")) if got != filepath.Join(dir, "folder.png") { t.Errorf("got %q, want folder.png path", got) } } func TestFindSidecarCover_NoneFound(t *testing.T) { dir := t.TempDir() if got := findSidecarCover(filepath.Join(dir, "t.flac")); got != "" { t.Errorf("got %q, want empty string", got) } } func TestResolveAlbumCoverPath_ExplicitPresent(t *testing.T) { _, pool := testHandlers(t) truncateLibrary(t, pool) artist := seedArtist(t, pool, "A") album := seedAlbum(t, pool, artist.ID, "X", 0) dir := t.TempDir() explicit := filepath.Join(dir, "explicit.jpg") if err := os.WriteFile(explicit, []byte("e"), 0o644); err != nil { t.Fatal(err) } if _, err := pool.Exec(context.Background(), `UPDATE albums SET cover_art_path = $1 WHERE id = $2`, explicit, album.ID); err != nil { t.Fatalf("UPDATE albums: %v", err) } got := resolveAlbumCoverPath(context.Background(), dbq.New(pool), fetchAlbum(t, pool, album.ID)) if got != explicit { t.Errorf("got %q, want %q", got, explicit) } } func TestResolveAlbumCoverPath_ExplicitMissingFallsThroughToSidecar(t *testing.T) { _, pool := testHandlers(t) truncateLibrary(t, pool) artist := seedArtist(t, pool, "A") album := seedAlbum(t, pool, artist.ID, "X", 0) _, dir := seedTrackWithFile(t, pool, album.ID, artist.ID, "t", []byte("audio"), "mp3") sidecar := filepath.Join(dir, "cover.jpg") if err := os.WriteFile(sidecar, []byte("s"), 0o644); err != nil { t.Fatal(err) } if _, err := pool.Exec(context.Background(), `UPDATE albums SET cover_art_path = $1 WHERE id = $2`, filepath.Join(dir, "does-not-exist.jpg"), album.ID); err != nil { t.Fatalf("UPDATE albums: %v", err) } got := resolveAlbumCoverPath(context.Background(), dbq.New(pool), fetchAlbum(t, pool, album.ID)) if got != sidecar { t.Errorf("got %q, want %q", got, sidecar) } } func TestResolveAlbumCoverPath_NoArt(t *testing.T) { _, pool := testHandlers(t) truncateLibrary(t, pool) artist := seedArtist(t, pool, "A") album := seedAlbum(t, pool, artist.ID, "X", 0) seedTrack(t, pool, album.ID, artist.ID, "t", 1, 1000) got := resolveAlbumCoverPath(context.Background(), dbq.New(pool), album) if got != "" { t.Errorf("got %q, want empty string", got) } } // fetchAlbum reloads the album row so tests see updates made via raw SQL. func fetchAlbum(t *testing.T, pool *pgxpool.Pool, id pgtype.UUID) dbq.Album { t.Helper() a, err := dbq.New(pool).GetAlbumByID(context.Background(), id) if err != nil { t.Fatalf("GetAlbumByID: %v", err) } return a }