package subsonic import ( "testing" "git.noroutes.net/NoRoutes/vibetunes/internal/audiofeatures" "git.noroutes.net/NoRoutes/vibetunes/internal/database" ) func makeGenreSong(t *testing.T, s *Server, folderID, genreID, title string) *database.Song { t.Helper() mf, err := database.CreateMediaFile(s.DB, folderID, title+".mp3", 100, 0, "hash-"+title, "mp3", "song", 10, 128, 44100, 2) if err != nil { t.Fatal(err) } song, err := database.UpsertSong(s.DB, database.UpsertSongInput{MediaFileID: mf.ID, Title: title}) if err != nil { t.Fatal(err) } if err := database.LinkSongGenre(s.DB, song.ID, genreID); err != nil { t.Fatal(err) } return song } func TestSimilarSongsForReordersGenreCandidatesBySonicDistance(t *testing.T) { s, db := newTestServer(t) folder, err := database.CreateMusicFolder(db, "Music", "/music", "music") if err != nil { t.Fatal(err) } genre, err := database.FindOrCreateGenre(db, "Rock") if err != nil { t.Fatal(err) } seed := makeGenreSong(t, s, folder.ID, genre.ID, "Seed") if err := database.UpsertAudioFeatures(db, seed.ID, &audiofeatures.Features{TempoBPM: 100, TempoValid: true}); err != nil { t.Fatal(err) } near := makeGenreSong(t, s, folder.ID, genre.ID, "Near") if err := database.UpsertAudioFeatures(db, near.ID, &audiofeatures.Features{TempoBPM: 105, TempoValid: true}); err != nil { t.Fatal(err) } far := makeGenreSong(t, s, folder.ID, genre.ID, "Far") if err := database.UpsertAudioFeatures(db, far.ID, &audiofeatures.Features{TempoBPM: 200, TempoValid: true}); err != nil { t.Fatal(err) } _ = makeGenreSong(t, s, folder.ID, genre.ID, "Unanalyzed") songs, err := similarSongsFor(db, seed.ID, 10) if err != nil { t.Fatalf("similarSongsFor: %v", err) } if len(songs) != 3 { t.Fatalf("songs = %v, want 3 (near, far, unanalyzed)", songs) } pos := map[string]int{} for i, sg := range songs { pos[sg.Title] = i } if pos["Near"] >= pos["Far"] { t.Errorf("expected Near (105bpm) to rank before Far (200bpm), got order %v", songs) } if pos["Unanalyzed"] != len(songs)-1 { t.Errorf("expected the unanalyzed candidate last, got order %v", songs) } } func TestSimilarSongsForNoAudioFeaturesLeavesOrderAlone(t *testing.T) { s, db := newTestServer(t) folder, err := database.CreateMusicFolder(db, "Music", "/music", "music") if err != nil { t.Fatal(err) } genre, err := database.FindOrCreateGenre(db, "Rock") if err != nil { t.Fatal(err) } seed := makeGenreSong(t, s, folder.ID, genre.ID, "Seed") makeGenreSong(t, s, folder.ID, genre.ID, "Other") songs, err := similarSongsFor(db, seed.ID, 10) if err != nil { t.Fatalf("similarSongsFor: %v", err) } if len(songs) != 1 || songs[0].Title != "Other" { t.Fatalf("songs = %v, want [Other] (no analysis on either side, no reorder crash)", songs) } }