add internal/domain/playlist_test.go
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func mkTrack(id string, created time.Time, rating int) Track {
|
||||
return Track{
|
||||
ID: id,
|
||||
Genre: "synthwave",
|
||||
Title: "Song " + id,
|
||||
Style: "dreamy synth",
|
||||
Source: "generated",
|
||||
CreatedAt: UnixTime{created},
|
||||
Rating: rating,
|
||||
}
|
||||
}
|
||||
|
||||
func TestExcludesDisliked(t *testing.T) {
|
||||
now := time.Now()
|
||||
tracks := []Track{
|
||||
mkTrack("a", now.Add(-3*time.Hour), 0),
|
||||
mkTrack("b", now.Add(-2*time.Hour), -1), // disliked
|
||||
mkTrack("c", now.Add(-1*time.Hour), 1),
|
||||
}
|
||||
got := FilterPlayable(tracks)
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("want 2 playable, got %d", len(got))
|
||||
}
|
||||
for _, tr := range got {
|
||||
if tr.ID == "b" {
|
||||
t.Fatal("disliked track b must be excluded")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRollingPlaylistSizeAndNoDupes(t *testing.T) {
|
||||
now := time.Now()
|
||||
var tracks []Track
|
||||
for i := 0; i < 20; i++ {
|
||||
tracks = append(tracks, mkTrack(string(rune('a'+i)), now.Add(time.Duration(i)*time.Minute), 0))
|
||||
}
|
||||
pl := BuildPlaylist(tracks, 8, 3, time.Now().Unix())
|
||||
if len(pl) != 8 {
|
||||
t.Fatalf("want 8, got %d", len(pl))
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
for _, tr := range pl {
|
||||
if seen[tr.ID] {
|
||||
t.Fatalf("duplicate %s in playlist", tr.ID)
|
||||
}
|
||||
seen[tr.ID] = true
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewnessBiasPrefersNewest(t *testing.T) {
|
||||
now := time.Now()
|
||||
var tracks []Track
|
||||
for i := 0; i < 50; i++ {
|
||||
tracks = append(tracks, mkTrack(idFor(i), now.Add(-time.Duration(50-i)*time.Minute), 0))
|
||||
}
|
||||
// strong bias: bias=1 means newest rank0 weight=1, rank49 weight=1/50
|
||||
newestCount := 0
|
||||
const runs = 200
|
||||
for r := 0; r < runs; r++ {
|
||||
pl := BuildPlaylist(tracks, 5, 1, int64(r*7919))
|
||||
for _, tr := range pl {
|
||||
if tr.ID == idFor(49) { // the newest
|
||||
newestCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
// with strong bias the newest track should appear in most playlists
|
||||
if newestCount < runs/2 {
|
||||
t.Fatalf("newest track appeared in only %d/%d playlists — bias not working", newestCount, runs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUniformWhenBiasHigh(t *testing.T) {
|
||||
// bias >> pool size => near-uniform; just sanity check no panic and full size
|
||||
now := time.Now()
|
||||
var tracks []Track
|
||||
for i := 0; i < 10; i++ {
|
||||
tracks = append(tracks, mkTrack(idFor(i), now.Add(-time.Duration(10-i)*time.Minute), 0))
|
||||
}
|
||||
pl := BuildPlaylist(tracks, 10, 1000, 42)
|
||||
if len(pl) != 10 {
|
||||
t.Fatalf("want 10, got %d", len(pl))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyAndSmallPool(t *testing.T) {
|
||||
if pl := BuildPlaylist(nil, 8, 3, 1); len(pl) != 0 {
|
||||
t.Fatal("empty pool must give empty playlist")
|
||||
}
|
||||
now := time.Now()
|
||||
pl := BuildPlaylist([]Track{mkTrack("x", now, 0)}, 8, 3, 1)
|
||||
if len(pl) != 1 {
|
||||
t.Fatalf("pool of 1 should give playlist of 1, got %d", len(pl))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTitleForDisplay(t *testing.T) {
|
||||
tr := mkTrack("t1", time.Now(), 0)
|
||||
if got := tr.DisplayTitle(); got != "Song t1" {
|
||||
t.Fatalf("DisplayTitle = %q", got)
|
||||
}
|
||||
tr.Title = ""
|
||||
if got := tr.DisplayTitle(); got != tr.Style {
|
||||
t.Fatalf("fallback DisplayTitle = %q, want style %q", got, tr.Style)
|
||||
}
|
||||
}
|
||||
|
||||
func idFor(i int) string {
|
||||
return "id" + string(rune('A'+i%26)) + string(rune('a'+i/26))
|
||||
}
|
||||
Reference in New Issue
Block a user