Files
wehub-resource-sync ead81af521
Deploy to GitHub Pages / deploy (push) Failing after 0s
CI / go (push) Has been cancelled
CI / build (darwin, macos-14) (push) Has been cancelled
CI / build (windows, windows-2025) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:31:13 +08:00

161 lines
3.7 KiB
Go

package qobuz
import (
"encoding/json"
"math/rand/v2"
"strconv"
"testing"
)
func TestParseYear(t *testing.T) {
tests := []struct {
in string
want int
}{
{"2021-05-14", 2021},
{"1999", 1999},
{"", 0},
{"abc", 0},
{"20", 0},
{"19xy-01-01", 0},
}
for _, tt := range tests {
if got := parseYear(tt.in); got != tt.want {
t.Errorf("parseYear(%q) = %d, want %d", tt.in, got, tt.want)
}
}
}
func TestTrackArtist(t *testing.T) {
withPerformer := apiTrack{Performer: apiArtist{Name: "Performer"}}
if got := trackArtist(withPerformer, nil); got != "Performer" {
t.Errorf("performer name: got %q want %q", got, "Performer")
}
album := &apiAlbum{Artist: apiArtist{Name: "AlbumArtist"}}
if got := trackArtist(apiTrack{}, album); got != "AlbumArtist" {
t.Errorf("album fallback: got %q want %q", got, "AlbumArtist")
}
if got := trackArtist(apiTrack{}, nil); got != "" {
t.Errorf("no artist: got %q want empty", got)
}
}
func TestDedupeTracksByID(t *testing.T) {
tracks := []apiTrack{
{ID: "1", Title: "first"},
{ID: "2", Title: "second"},
{ID: "1", Title: "dup of first"},
{ID: "3", Title: "third"},
{ID: "2", Title: "dup of second"},
{ID: "", Title: "no id a"},
{ID: "", Title: "no id b"},
}
got := dedupeTracksByID(tracks)
want := []struct {
id string
title string
}{
{"1", "first"}, // first occurrence wins
{"2", "second"},
{"3", "third"},
{"", "no id a"}, // empty-ID tracks are always kept
{"", "no id b"},
}
if len(got) != len(want) {
t.Fatalf("got %d tracks, want %d", len(got), len(want))
}
for i, w := range want {
if got[i].ID.String() != w.id || got[i].Title != w.title {
t.Errorf("track %d = {%q, %q}, want {%q, %q}",
i, got[i].ID.String(), got[i].Title, w.id, w.title)
}
}
}
func TestDedupeTracksByIDEmpty(t *testing.T) {
if got := dedupeTracksByID(nil); len(got) != 0 {
t.Errorf("dedupeTracksByID(nil) = %v, want empty", got)
}
}
func TestSampleTracks(t *testing.T) {
mk := func(n int) []apiTrack {
ts := make([]apiTrack, n)
for i := range ts {
ts[i] = apiTrack{ID: json.Number(strconv.Itoa(i))}
}
return ts
}
idSet := func(ts []apiTrack) map[string]bool {
m := make(map[string]bool, len(ts))
for _, tr := range ts {
m[tr.ID.String()] = true
}
return m
}
r := rand.New(rand.NewPCG(42, 1024))
// Under the cap: every track is kept, but the list must still be shuffled.
// This is the case that used to be returned in playlist order unchanged.
in := mk(100)
got := sampleTracks(in, 500, r.Shuffle)
if len(got) != 100 {
t.Fatalf("under cap: len = %d, want 100", len(got))
}
want := idSet(in)
for _, tr := range got {
if !want[tr.ID.String()] {
t.Errorf("under cap: track %s not from input", tr.ID)
}
}
sameOrder := true
for i := range got {
if got[i].ID != in[i].ID {
sameOrder = false
break
}
}
if sameOrder {
t.Error("under cap: list was not shuffled")
}
// Over the cap: exactly n tracks, all from the input, no duplicates.
big := mk(1000)
all := idSet(big)
for range 20 {
s := sampleTracks(big, 10, r.Shuffle)
if len(s) != 10 {
t.Fatalf("over cap: len = %d, want 10", len(s))
}
seen := make(map[string]bool, len(s))
for _, tr := range s {
id := tr.ID.String()
if !all[id] {
t.Fatalf("over cap: track %q not from input", id)
}
if seen[id] {
t.Fatalf("over cap: duplicate track %q", id)
}
seen[id] = true
}
}
}
func TestNewQualityNormalization(t *testing.T) {
for _, q := range []int{5, 6, 7, 27} {
if got := New(q).quality; got != q {
t.Errorf("New(%d).quality = %d, want %d", q, got, q)
}
}
for _, q := range []int{0, 1, 99} {
if got := New(q).quality; got != defaultQuality {
t.Errorf("New(%d).quality = %d, want default %d", q, got, defaultQuality)
}
}
}