Files
minstrel/internal/release/release_test.go
T
bvandeusenandClaude Opus 5.5 d191a28217 docs: server comments say what the code does, not how it came to be (#6277)
Comment blocks in cmd/minstrel and 30 smaller internal packages, rewritten
to rule 32's standard with each citation read in context: task, milestone
and rule ids go, and so do the stories they were attached to ("used to",
"Before #N", measurements from one install, quotes, pointers to Fabled
Librarian's records and to docs/superpowers files that are not in the
repo). Where a story wrapped a real constraint, the constraint stays as a
present-tense fact.

Comments that had gone stale are corrected:
- taste.Config: the tuned values are overlaid by internal/recsettings;
  it is no longer "a later follow-up".
- StorageConfig: the data dir holds art, caches and the stream secret,
  not only playlist covers.
- the Subsonic album list and getUser comments describe what they do
  today rather than a milestone that would change it.

Checked: the non-comment token stream of every changed file matches
HEAD, and gofmt -l is empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:15:05 -04:00

312 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package release
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"strings"
"testing"
)
func TestParse_ReadsWhatTheNameSays(t *testing.T) {
for _, c := range []struct {
name string
format, vbr, src string
bitrate, depth, yr int
rate float64
tier Tier
}{
// A bracketed edition with its own year: not the original album.
{"Daft Punk Random Access Memories (Drumless Edition 2023) [Flac 24-88]", FormatFLAC, "", "", 0, 24, 2023, 88.2, TierLosslessHiRes},
{"Gorillaz - Humanz - (Japanese Edition) - [CD-FLAC] 2017", FormatFLAC, "", SourceCD, 0, 0, 2017, 0, TierLossless},
{"Radiohead - OK Computer (1997) [MP3 320]", FormatMP3, "", "", 320, 0, 1997, 0, TierLossyHigh},
{"Artist - Album 2019 MP3 V0", FormatMP3, "V0", "", 0, 0, 2019, 0, TierLossyHigh},
{"Artist - Album (2020) [WEB] [AAC 256]", FormatAAC, "", SourceWEB, 256, 0, 2020, 0, TierLossyHigh},
{"Artist_-_Album-(2004)-192kbps", FormatMP3, "", "", 192, 0, 2004, 0, TierLossyLow},
{"Artist - Album [24bit-96kHz] FLAC Vinyl", FormatFLAC, "", SourceVinyl, 0, 24, 0, 96, TierLosslessHiRes},
{"Taylor Swift - 1989 (2014) [FLAC]", FormatFLAC, "", "", 0, 0, 2014, 0, TierLossless},
{"Artist - Album", "", "", "", 0, 0, 0, 0, TierUnknown},
} {
r := Parse(c.name)
got := fmt.Sprint(r.Format, r.VBR, r.Source, r.Bitrate, r.BitDepth, r.Year, r.SampleRate, TierOf(r, 0))
want := fmt.Sprint(c.format, c.vbr, c.src, c.bitrate, c.depth, c.yr, c.rate, c.tier)
if got != want {
t.Errorf("Parse(%q)\n got %s\nwant %s", c.name, got, want)
}
}
}
func TestParse_VideoAndDiscographies(t *testing.T) {
if v := Parse("Artist.Album.2018.1080p.BluRay.x264").Video; v != "1080p" {
t.Errorf("video = %q", v)
}
if d := Parse("Artist Discography 1994-2010 FLAC").Discography; d != "discography" {
t.Errorf("discography = %q", d)
}
if d := Parse("Artist - Studio Albums 1994 - 2010 [MP3]").Discography; d != "1994–2010" {
t.Errorf("year range = %q", d)
}
if d := Parse("Artist - Album (2010) [FLAC]").Discography; d != "" {
t.Errorf("one year read as a range: %q", d)
}
}
func judge(w Want, name string) Match { return Judge(w, Parse(name)) }
func TestJudge_TheAlbumAndWhatIsNot(t *testing.T) {
ram := Want{Artist: "Daft Punk", Title: "Random Access Memories", Year: 2013, PrimaryType: "Album"}
for name, veto := range map[string]string{
"Daft Punk - Random Access Memories (2013) [FLAC]": "",
"Daft_Punk-Random_Access_Memories-WEB-2013": "",
"Daft Punk Random Access Memories (Drumless Edition 2023) [Flac 24-88]": VetoVersion,
"Daft Punk - Random Access Memories (Instrumentals) [MP3]": VetoVersion,
"Daft Punk - Random Access Memories Remixes": VetoVersion,
"Daft Punk - Random Access Memories (Live) FLAC": VetoVersion,
"Daft Punk - Random Access Memories (BBC Sessions) FLAC": VetoVersion,
"Daft Punk - Random Access Memories Unplugged [MP3]": VetoVersion,
"Daft Punk - Discovery (2001) [FLAC]": VetoTitle,
"Random Access Memories (2013) [FLAC]": VetoArtist,
"Daft Punk - Discography 1997-2013 FLAC": VetoTitle,
"Daft Punk - Random Access Memories + Discovery + Homework Collection": VetoDiscography,
"Daft Punk - Random Access Memories (2013) 1080p BluRay": VetoVideo,
"Daft Punk - Random Access Memories (Single) 2013": VetoType,
"Daft Punk - Random Access Memories (Deluxe 10th Anniversary Edition) 2023": "",
} {
if got := judge(ram, name).Veto; got != veto {
t.Errorf("%q: veto %q, want %q", name, got, veto)
}
}
if !judge(ram, "Daft Punk - Random Access Memories (2013) [FLAC]").YearAgrees {
t.Error("the year did not agree")
}
}
func TestJudge_WordsTheWantedTitleHoldsDoNotVeto(t *testing.T) {
hole := Want{Artist: "Hole", Title: "Live Through This", PrimaryType: "Album"}
if m := judge(hole, "Hole - Live Through This (1994) [FLAC]"); m.Veto != "" {
t.Errorf("Live Through This: %s", m.Reason)
}
alive := Want{Artist: "Daft Punk", Title: "Alive 2007", PrimaryType: "Album", SecondaryTypes: []string{"Live"}}
if m := judge(alive, "Daft Punk - Alive 2007 (Live) [FLAC]"); m.Veto != "" {
t.Errorf("a wanted live album: %s", m.Reason)
}
alive.SecondaryTypes = nil
if m := judge(alive, "Daft Punk - Alive 2007 (Live) [FLAC]"); m.Veto != VetoVersion {
t.Errorf("live without the Live type: veto %q", m.Veto)
}
}
func TestJudge_SpellingsOfNames(t *testing.T) {
for _, c := range []struct {
w Want
name string
}{
{Want{Artist: "AC/DC", Title: "Back in Black"}, "ACDC - Back In Black (1980) FLAC"},
{Want{Artist: "AC/DC", Title: "Back in Black"}, "AC-DC - Back in Black [MP3 320]"},
{Want{Artist: "Sigur Rós", Title: "Ágætis byrjun"}, "Sigur Ros - Agaetis Byrjun (1999) [FLAC]"},
{Want{Artist: "Simon & Garfunkel", Title: "Bookends"}, "Simon and Garfunkel - Bookends"},
{Want{Artist: "The Beatles", Title: "Abbey Road"}, "Beatles - Abbey Road (Remastered 2009)"},
{Want{Artist: "Florence + the Machine", Title: "Lungs"}, "Florence and The Machine - Lungs (2009)"},
{Want{Artist: "Guns N' Roses", Title: "Appetite for Destruction"}, "Guns N Roses - Appetite For Destruction"},
} {
if m := judge(c.w, c.name); m.Veto != "" {
t.Errorf("%q for %s / %s: %s", c.name, c.w.Artist, c.w.Title, m.Reason)
}
}
// One word is never matched run together: Muse is not inside Museum.
if m := judge(Want{Artist: "Muse", Title: "Absolution"}, "Museum - Absolution"); m.Veto != VetoArtist {
t.Errorf("Museum read as Muse: %q", m.Veto)
}
}
func TestJudge_ASelfTitledAlbumNeedsMoreThanTheName(t *testing.T) {
weezer := Want{Artist: "Weezer", Title: "Weezer", Year: 1994, PrimaryType: "Album"}
if m := judge(weezer, "Weezer - Weezer (Blue Album) [FLAC]"); m.Doubt != "" || m.Veto != "" {
t.Errorf("named twice: %+v", m)
}
if m := judge(weezer, "Weezer (1994) [FLAC]"); m.Doubt != "" {
t.Errorf("the year agrees: %+v", m)
}
if m := judge(weezer, "Weezer (Green Album) FLAC"); m.Doubt == "" {
t.Error("a self-titled name with nothing else was taken as sure")
}
}
func TestTierOf_TheLadder(t *testing.T) {
for _, c := range []struct {
r Release
cat int
want Tier
}{
{Release{Format: FormatMP3, Bitrate: 256}, 0, TierLossyStandard},
{Release{Format: FormatMP3, Bitrate: 128}, 0, TierLossyPoor},
{Release{Format: FormatMP3, Bitrate: 96}, 0, TierLossyTrash},
{Release{Format: FormatMP3, VBR: "V2"}, 0, TierLossyStandard},
{Release{Format: FormatMP3}, 0, TierLossyStandard},
{Release{Format: FormatAAC, Bitrate: 192}, 0, TierLossyStandard},
{Release{Format: FormatALAC, SampleRate: 96}, 0, TierLosslessHiRes},
{Release{Format: FormatDSD}, 0, TierLosslessHiRes},
{Release{}, 3040, TierLossless},
{Release{}, 3010, TierUnknown},
} {
if got := TierOf(c.r, c.cat); got != c.want {
t.Errorf("TierOf(%+v, %d) = %s, want %s", c.r, c.cat, got, c.want)
}
}
if Rank(TierLossless) <= Rank(TierLossyHigh) || Rank(TierUnknown) >= Rank(TierLossyTrash) {
t.Error("the ladder is out of order")
}
if !NewProfile([]string{"lossless"}).Allows(TierLossless) || NewProfile([]string{"lossless"}).Allows(TierUnknown) {
t.Error("profile")
}
}
func files(paths ...string) []File {
out := make([]File, len(paths))
for i, p := range paths {
out[i] = File{Index: i, Path: p, Size: 1 << 20}
}
return out
}
func numbered(n int, ext string) []string {
var out []string
for i := 1; i <= n; i++ {
out = append(out, fmt.Sprintf("Album/%02d - Track.%s", i, ext))
}
return out
}
func TestJudgeFiles_WhatTheTorrentHolds(t *testing.T) {
w := Want{MinTracks: 10, MaxTracks: 13}
if veto, _, _ := JudgeFiles(w, files(numbered(13, "flac")...)); veto != "" {
t.Errorf("a whole album: %s", veto)
}
if veto, reason, _ := JudgeFiles(w, files(numbered(3, "flac")...)); veto != VetoIncomplete || !strings.Contains(reason, "3 tracks") {
t.Errorf("three tracks: %s %s", veto, reason)
}
if veto, _, _ := JudgeFiles(w, files("Concert/Concert.mkv", "Concert/cover.jpg")); veto != VetoVideo {
t.Errorf("a video: %s", veto)
}
if veto, _, _ := JudgeFiles(w, files("Album.rar", "Album.r00")); veto != VetoNoAudio {
t.Errorf("an archive: %s", veto)
}
if _, _, doubt := JudgeFiles(w, files(numbered(60, "mp3")...)); doubt == "" {
t.Error("sixty tracks for a thirteen-track album raised no doubt")
}
if c := Inspect(files(append(numbered(12, "flac"), "Album/cover.jpg", "Album/album.cue")...)); c.Format != FormatFLAC || c.Audio != 12 {
t.Errorf("inspect = %+v", c)
}
}
// bencode writes the few shapes a test torrent needs.
func bencode(v any) string {
switch x := v.(type) {
case string:
return fmt.Sprintf("%d:%s", len(x), x)
case int:
return fmt.Sprintf("i%de", x)
case []any:
var b strings.Builder
b.WriteString("l")
for _, e := range x {
b.WriteString(bencode(e))
}
return b.String() + "e"
case [][2]any: // an ordered dictionary
var b strings.Builder
b.WriteString("d")
for _, kv := range x {
b.WriteString(bencode(kv[0]) + bencode(kv[1]))
}
return b.String() + "e"
}
panic(fmt.Sprintf("bencode %T", v))
}
func TestParseTorrent_FilesAndInfohash(t *testing.T) {
info := bencode([][2]any{
{"files", []any{
[][2]any{{"length", 300}, {"path", []any{"01 - One.flac"}}},
[][2]any{{"attr", "p"}, {"length", 12}, {"path", []any{".pad", "12"}}},
[][2]any{{"length", 200}, {"path", []any{"Scans", "front.jpg"}}},
}},
{"name", "Artist - Album"},
{"piece length", 16384},
{"pieces", strings.Repeat("x", 20)},
})
body := "d" + bencode("announce") + bencode("http://tracker/") + bencode("info") + info + "e"
meta, err := ParseTorrent([]byte(body))
if err != nil {
t.Fatal(err)
}
sum := sha1.Sum([]byte(info))
if meta.InfoHash != hex.EncodeToString(sum[:]) {
t.Errorf("infohash = %s", meta.InfoHash)
}
if len(meta.Files) != 2 || meta.Files[0].Path != "Artist - Album/01 - One.flac" || meta.Files[1].Path != "Artist - Album/Scans/front.jpg" {
t.Errorf("files = %+v", meta.Files)
}
if _, err := ParseTorrent([]byte("<html>not a torrent</html>")); err == nil {
t.Error("HTML parsed as a torrent")
}
}
func TestTierOfFile(t *testing.T) {
cases := []struct {
format string
kbps int
want Tier
ok bool
}{
{"flac", 900, TierLossless, true},
{"FLAC", 2800, TierLosslessHiRes, true},
{"m4a", 750, TierLossless, true},
{"m4a", 256, TierLossyHigh, true},
{"mp3", 320, TierLossyHigh, true},
{"mp3", 245, TierLossyHigh, true}, // a V0, by size
{"mp3", 192, TierLossyLow, true},
{"mp3", 128, TierLossyPoor, true},
{"mp3", 96, TierLossyTrash, true},
{"opus", 160, TierLossyLow, true},
{"wma", 192, TierUnknown, false},
{"mp3", 0, TierLossyStandard, false},
}
for _, c := range cases {
got, ok := TierOfFile(c.format, c.kbps)
if got != c.want || ok != c.ok {
t.Errorf("TierOfFile(%q, %d) = %s, %v; want %s, %v", c.format, c.kbps, got, ok, c.want, c.ok)
}
}
}
func TestFileKbpsAndWords(t *testing.T) {
// 5 MB over 3:30 of audio is about 190 kbps.
k := FileKbps(5_000_000, 210_000)
if k != 190 {
t.Fatalf("FileKbps = %d, want 190", k)
}
if got := HeldWords("mp3", TierLossyLow, 191); got != "MP3, about 192 kbps" {
t.Errorf("HeldWords = %q", got)
}
if got := HeldWords("flac", TierLossless, 900); got != "FLAC" {
t.Errorf("HeldWords = %q", got)
}
if FileKbps(0, 1000) != 0 || FileKbps(1000, 0) != 0 {
t.Error("FileKbps with nothing to measure is 0")
}
}
func TestHeldCopy_TakesTheWorstFormat(t *testing.T) {
h, ok := HeldCopy([]HeldFormat{
{Format: "flac", Bytes: 300_000_000, Ms: 2_400_000},
{Format: "mp3", Bytes: 4_800_000, Ms: 200_000}, // 192 kbps
})
if !ok || h.Tier != TierLossyLow || h.Words != "MP3, about 192 kbps" {
t.Fatalf("HeldCopy = %+v, %v", h, ok)
}
if _, ok := HeldCopy([]HeldFormat{{Format: "wma", Bytes: 1, Ms: 1}}); ok {
t.Error("a format the ladder can't place says nothing")
}
}