package library import ( "testing" "github.com/dhowden/tag" ) // stubMeta is a minimal tag.Metadata used to feed the dhowden mbz extractor // the same Raw()/Format() shape its real parsers produce. The other interface // methods return zero values — the extractor only branches on Format and // iterates Raw(). type stubMeta struct { format tag.Format raw map[string]interface{} } func (s stubMeta) Format() tag.Format { return s.format } func (s stubMeta) FileType() tag.FileType { return tag.UnknownFileType } func (s stubMeta) Title() string { return "" } func (s stubMeta) Album() string { return "" } func (s stubMeta) Artist() string { return "" } func (s stubMeta) AlbumArtist() string { return "" } func (s stubMeta) Composer() string { return "" } func (s stubMeta) Year() int { return 0 } func (s stubMeta) Genre() string { return "" } func (s stubMeta) Track() (int, int) { return 0, 0 } func (s stubMeta) Disc() (int, int) { return 0, 0 } func (s stubMeta) Picture() *tag.Picture { return nil } func (s stubMeta) Lyrics() string { return "" } func (s stubMeta) Comment() string { return "" } func (s stubMeta) Raw() map[string]interface{} { return s.raw } func TestExtractMBIDs_Vorbis(t *testing.T) { // dhowden lowercases all Vorbis comment keys at parse time. m := stubMeta{ format: tag.VORBIS, raw: map[string]interface{}{ "musicbrainz_albumid": "abc", "musicbrainz_artistid": "def", }, } a, ar := extractMBIDs(m) if a != "abc" || ar != "def" { t.Errorf("got (%q, %q), want (\"abc\", \"def\")", a, ar) } } func TestExtractMBIDs_ID3v2(t *testing.T) { // dhowden stores TXXX frames under bare "TXXX"/"TXXX_N" keys with // *tag.Comm values whose Description holds the Picard tag name. m := stubMeta{ format: tag.ID3v2_4, raw: map[string]interface{}{ "TXXX": &tag.Comm{ Description: "MusicBrainz Album Id", Text: "abc-123", }, "TXXX_0": &tag.Comm{ Description: "MusicBrainz Artist Id", Text: "def-456", }, }, } a, ar := extractMBIDs(m) if a != "abc-123" || ar != "def-456" { t.Errorf("got (%q, %q), want (\"abc-123\", \"def-456\")", a, ar) } } func TestExtractMBIDs_MP4(t *testing.T) { // dhowden stores freeform iTunes atoms under their bare sub-name. // mbz.Extract maps the human-readable form back to its lowercase key. m := stubMeta{ format: tag.MP4, raw: map[string]interface{}{ "MusicBrainz Album Id": "abc", "MusicBrainz Artist Id": "def", }, } a, ar := extractMBIDs(m) if a != "abc" || ar != "def" { t.Errorf("got (%q, %q), want (\"abc\", \"def\")", a, ar) } } func TestExtractMBIDs_MissingTagsReturnEmpty(t *testing.T) { m := stubMeta{format: tag.VORBIS, raw: map[string]interface{}{}} a, ar := extractMBIDs(m) if a != "" || ar != "" { t.Errorf("got (%q, %q), want empty", a, ar) } } func TestExtractMBIDs_VorbisUppercaseKeysMiss(t *testing.T) { // Regression guard: real dhowden never produces uppercase Vorbis // keys. If a future change starts looking up "MUSICBRAINZ_ALBUMID" // directly, this test must keep returning empty so we don't // silently re-introduce the v0 bug where every album skipped. m := stubMeta{ format: tag.VORBIS, raw: map[string]interface{}{ "MUSICBRAINZ_ALBUMID": "wrong-case", "MUSICBRAINZ_ARTISTID": "wrong-case", }, } a, ar := extractMBIDs(m) if a != "" || ar != "" { t.Errorf("uppercase Vorbis keys must not match dhowden output; got (%q, %q)", a, ar) } } func TestExtractMBIDs_ID3v2StripsTrailingNUL(t *testing.T) { // dhowden's readTextWithDescrFrame leaves the ID3v2.4 frame- // terminator NUL on TXXX values. Postgres rejects NULs in text // columns (SQLSTATE 22021), so we must strip them. m := stubMeta{ format: tag.ID3v2_4, raw: map[string]interface{}{ "TXXX": &tag.Comm{ Description: "MusicBrainz Album Id", Text: "abc-123\x00", }, "TXXX_0": &tag.Comm{ Description: "MusicBrainz Artist Id", Text: "def-456\x00", }, }, } a, ar := extractMBIDs(m) if a != "abc-123" || ar != "def-456" { t.Errorf("got (%q, %q), want trailing NUL stripped", a, ar) } } func TestExtractMBIDs_ID3v2MultiValueTakesFirst(t *testing.T) { // Some Picard configs emit multi-value TXXX:MusicBrainz Artist Id // for collaborations, NUL-separated. Minstrel uses the primary // release artist for MBCAA, so first wins. m := stubMeta{ format: tag.ID3v2_4, raw: map[string]interface{}{ "TXXX": &tag.Comm{ Description: "MusicBrainz Artist Id", Text: "primary-mbid\x00collab-mbid", }, }, } _, ar := extractMBIDs(m) if ar != "primary-mbid" { t.Errorf("got %q, want %q", ar, "primary-mbid") } } func TestCleanMBID_OnlyNULReturnsEmpty(t *testing.T) { // Defensive: a TXXX value that is purely NULs (or empty after // trimming) must round-trip to empty so the caller skips the row // instead of writing a NUL-only string to Postgres. if got := cleanMBID("\x00\x00"); got != "" { t.Errorf("got %q, want empty", got) } if got := cleanMBID(""); got != "" { t.Errorf("got %q, want empty", got) } }