Files
yellowjacket/backend/library/scan_test.go
T
yonlu 6f96a9411f test(05-02): add pure helper tests for scan utility functions
- TestGetRecordingName: title present, fallback to filename sans extension
- TestToNullInt64: zero as null, positive/negative as valid
- TestToNullString: empty as null, non-empty as valid
- TestSplitGenres: empty/single/multiple genre splitting on || delimiter
- TestMapTrackRow: all 16 columns including string TrackLength, NullInt64 fields
2026-03-04 16:35:00 -05:00

295 lines
6.6 KiB
Go

package library
import (
"database/sql"
"testing"
"yellowjacket/backend/metadata"
)
// ---------------------------------------------------------------------------
// Pure helper tests — no database dependency
// ---------------------------------------------------------------------------
func TestGetRecordingName(t *testing.T) {
t.Parallel()
lib := &Library{} // getRecordingName uses only tags + filePath
tests := []struct {
name string
title string
filePath string
want string
}{
{
name: "title present",
title: "Bohemian Rhapsody",
filePath: "/music/queen/bohemian.mp3",
want: "Bohemian Rhapsody",
},
{
name: "title empty falls back to filename sans extension",
title: "",
filePath: "/music/song.mp3",
want: "song",
},
{
name: "title empty with complex filename",
title: "",
filePath: "/music/Artist - Track.flac",
want: "Artist - Track",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
tags := &metadata.TrackMetadata{Title: tt.title}
got := lib.getRecordingName(tags, tt.filePath)
if got != tt.want {
t.Errorf("getRecordingName() = %q, want %q", got, tt.want)
}
})
}
}
func TestToNullInt64(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input int
want sql.NullInt64
}{
{
name: "zero is null",
input: 0,
want: sql.NullInt64{},
},
{
name: "positive is valid",
input: 5,
want: sql.NullInt64{Int64: 5, Valid: true},
},
{
name: "negative is valid",
input: -1,
want: sql.NullInt64{Int64: -1, Valid: true},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := toNullInt64(tt.input)
if got != tt.want {
t.Errorf("toNullInt64(%d) = %+v, want %+v", tt.input, got, tt.want)
}
})
}
}
func TestToNullString(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input string
want sql.NullString
}{
{
name: "empty is null",
input: "",
want: sql.NullString{},
},
{
name: "non-empty is valid",
input: "rock",
want: sql.NullString{String: "rock", Valid: true},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := toNullString(tt.input)
if got != tt.want {
t.Errorf("toNullString(%q) = %+v, want %+v", tt.input, got, tt.want)
}
})
}
}
func TestSplitGenres(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input string
want []string
}{
{
name: "empty string returns nil",
input: "",
want: nil,
},
{
name: "single genre",
input: "Rock",
want: []string{"Rock"},
},
{
name: "multiple genres",
input: "Rock||Jazz||Blues",
want: []string{"Rock", "Jazz", "Blues"},
},
{
name: "two genres",
input: "Electronic||Ambient",
want: []string{"Electronic", "Ambient"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := splitGenres(tt.input)
if tt.want == nil {
if got != nil {
t.Errorf("splitGenres(%q) = %v, want nil", tt.input, got)
}
return
}
if len(got) != len(tt.want) {
t.Fatalf("splitGenres(%q) length = %d, want %d", tt.input, len(got), len(tt.want))
}
for i, v := range got {
if v != tt.want[i] {
t.Errorf("splitGenres(%q)[%d] = %q, want %q", tt.input, i, v, tt.want[i])
}
}
})
}
}
func TestMapTrackRow(t *testing.T) {
t.Parallel()
track := mapTrackRow(
"/music/queen/bohemian.flac", // filePath
180000, // lengthMs
"Bohemian Rhapsody", // title
"Queen", // artistName
sql.NullInt64{Int64: 1, Valid: true}, // trackNumber
sql.NullInt64{Int64: 1, Valid: true}, // discNumber
"A Night at the Opera", // album
"Rock||Progressive Rock", // genre
1975, // year
"Freddie Mercury", // composer
".flac", // fileType
44100, // sampleRate
16, // bitDepth
2, // channels
1411, // bitrate
35000000, // fileSize
)
// Verify all 16 fields.
if track.TrackName != "Bohemian Rhapsody" {
t.Errorf("TrackName = %q, want %q", track.TrackName, "Bohemian Rhapsody")
}
if track.ArtistName != "Queen" {
t.Errorf("ArtistName = %q, want %q", track.ArtistName, "Queen")
}
// TrackLength is string-formatted milliseconds.
if track.TrackLength != "180000" {
t.Errorf("TrackLength = %q, want %q", track.TrackLength, "180000")
}
if track.FilePath != "/music/queen/bohemian.flac" {
t.Errorf("FilePath = %q, want %q", track.FilePath, "/music/queen/bohemian.flac")
}
if track.TrackNumber != 1 {
t.Errorf("TrackNumber = %d, want %d", track.TrackNumber, 1)
}
if track.DiscNumber != 1 {
t.Errorf("DiscNumber = %d, want %d", track.DiscNumber, 1)
}
if track.Album != "A Night at the Opera" {
t.Errorf("Album = %q, want %q", track.Album, "A Night at the Opera")
}
wantGenres := []string{"Rock", "Progressive Rock"}
if len(track.Genre) != len(wantGenres) {
t.Fatalf("Genre length = %d, want %d", len(track.Genre), len(wantGenres))
}
for i, g := range track.Genre {
if g != wantGenres[i] {
t.Errorf("Genre[%d] = %q, want %q", i, g, wantGenres[i])
}
}
if track.Year != 1975 {
t.Errorf("Year = %d, want %d", track.Year, 1975)
}
if track.Composer != "Freddie Mercury" {
t.Errorf("Composer = %q, want %q", track.Composer, "Freddie Mercury")
}
if track.FileType != ".flac" {
t.Errorf("FileType = %q, want %q", track.FileType, ".flac")
}
if track.SampleRate != 44100 {
t.Errorf("SampleRate = %d, want %d", track.SampleRate, 44100)
}
if track.BitDepth != 16 {
t.Errorf("BitDepth = %d, want %d", track.BitDepth, 16)
}
if track.Channels != 2 {
t.Errorf("Channels = %d, want %d", track.Channels, 2)
}
if track.Bitrate != 1411 {
t.Errorf("Bitrate = %d, want %d", track.Bitrate, 1411)
}
if track.FileSize != 35000000 {
t.Errorf("FileSize = %d, want %d", track.FileSize, 35000000)
}
// Verify NullInt64 with Valid=false yields 0.
trackNull := mapTrackRow(
"/music/unknown.mp3", 0, "Test", "Artist",
sql.NullInt64{}, sql.NullInt64{}, // invalid (null)
"", "", 0, "", "", 0, 0, 0, 0, 0,
)
if trackNull.TrackNumber != 0 {
t.Errorf("null TrackNumber = %d, want 0", trackNull.TrackNumber)
}
if trackNull.DiscNumber != 0 {
t.Errorf("null DiscNumber = %d, want 0", trackNull.DiscNumber)
}
}