fix(quick-13): resolve lint issues in main source files
- Fix errcheck for db.Close() in testhelper.go - Fix errcheck, nlreturn, wsl, gofumpt issues in genevents/main.go - Fix gofumpt and wsl issues in library.go
This commit is contained in:
@@ -72,7 +72,10 @@ func TestConfig_LoadSave_Roundtrip(t *testing.T) {
|
||||
}
|
||||
|
||||
if loaded.Theme.BackgroundShade != theme.BackgroundLight {
|
||||
t.Errorf("Theme.BackgroundShade = %q, want %q", loaded.Theme.BackgroundShade, theme.BackgroundLight)
|
||||
t.Errorf(
|
||||
"Theme.BackgroundShade = %q, want %q",
|
||||
loaded.Theme.BackgroundShade, theme.BackgroundLight,
|
||||
)
|
||||
}
|
||||
|
||||
// Verify tracklist.
|
||||
@@ -86,13 +89,19 @@ func TestConfig_LoadSave_Roundtrip(t *testing.T) {
|
||||
}
|
||||
for i, want := range wantColumns {
|
||||
if loaded.TrackList.Columns[i].ID != want {
|
||||
t.Errorf("TrackList.Columns[%d].ID = %q, want %q", i, loaded.TrackList.Columns[i].ID, want)
|
||||
t.Errorf(
|
||||
"TrackList.Columns[%d].ID = %q, want %q",
|
||||
i, loaded.TrackList.Columns[i].ID, want,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify favorites.
|
||||
if loaded.Favorites.IconStyle != favorites.IconStar {
|
||||
t.Errorf("Favorites.IconStyle = %q, want %q", loaded.Favorites.IconStyle, favorites.IconStar)
|
||||
t.Errorf(
|
||||
"Favorites.IconStyle = %q, want %q",
|
||||
loaded.Favorites.IconStyle, favorites.IconStar,
|
||||
)
|
||||
}
|
||||
|
||||
if loaded.Favorites.PinDefault != false {
|
||||
@@ -105,7 +114,10 @@ func TestConfig_LoadSave_Roundtrip(t *testing.T) {
|
||||
}
|
||||
|
||||
if loaded.Library.ScanConcurrency != library.ScanConcurrencySSD {
|
||||
t.Errorf("Library.ScanConcurrency = %q, want %q", loaded.Library.ScanConcurrency, library.ScanConcurrencySSD)
|
||||
t.Errorf(
|
||||
"Library.ScanConcurrency = %q, want %q",
|
||||
loaded.Library.ScanConcurrency, library.ScanConcurrencySSD,
|
||||
)
|
||||
}
|
||||
|
||||
// Verify window.
|
||||
@@ -206,9 +218,6 @@ func TestConfig_ApplyDefaults_NilSubConfigs(t *testing.T) {
|
||||
if c.Favorites == nil {
|
||||
t.Error("Favorites should not be nil after applyDefaults")
|
||||
}
|
||||
|
||||
// Library is intentionally left nil by applyDefaults when it
|
||||
// starts as nil (no library dir configured yet).
|
||||
}
|
||||
|
||||
// containsSubstring is a test helper for checking error messages.
|
||||
|
||||
@@ -44,28 +44,50 @@ func seedSearchData(t *testing.T, db *DB) {
|
||||
intPtr := func(v int64) *int64 { return &v }
|
||||
|
||||
tracks := []track{
|
||||
{1, "/music/queen/bohemian_rhapsody.mp3", "Bohemian Rhapsody", "Queen", "A Night at the Opera", intPtr(11), intPtr(1), 1975, "Rock", "Freddie Mercury", 354000, 0, 44100, 16, 2, 320000, 8500000},
|
||||
{2, "/music/beyonce/halo.flac", "Halo", "Beyoncé", "Lemonade", intPtr(1), intPtr(1), 2008, "Pop", "Ryan Tedder", 261000, 1, 96000, 24, 2, 1411000, 42000000},
|
||||
{3, "/music/acdc/back_in_black.mp3", "Back in Black", "AC/DC", "Back in Black", intPtr(1), intPtr(1), 1980, "Hard Rock", "Angus Young", 255000, 0, 44100, 16, 2, 320000, 6100000},
|
||||
{4, "/music/pinkfloyd/comfortably_numb.flac", "Comfortably Numb", "Pink Floyd", "The Dark Side of the Moon", intPtr(6), intPtr(1), 1979, "Progressive Rock", "David Gilmour", 382000, 1, 96000, 24, 2, 1411000, 54000000},
|
||||
{5, "/music/queen/another_one_bites_the_dust.mp3", "Another One Bites the Dust", "Queen", "The Game", intPtr(3), intPtr(1), 1980, "Funk Rock", "John Deacon", 215000, 0, 44100, 16, 2, 320000, 5200000},
|
||||
{6, "/music/acdc/thunderstruck.mp3", "Thunderstruck", "AC/DC", "The Razors Edge", intPtr(1), intPtr(1), 1990, "Hard Rock", "Angus Young", 292000, 0, 44100, 16, 2, 320000, 7000000},
|
||||
{7, "/music/qotsa/queen_of_the_stone_age.mp3", "Queen of the Stone Age", "Queens of the Stone Age", "Rated R", intPtr(1), intPtr(1), 2000, "Stoner Rock", "Josh Homme", 310000, 0, 44100, 16, 2, 320000, 7400000},
|
||||
{
|
||||
1, "/music/queen/bohemian_rhapsody.mp3", "Bohemian Rhapsody", "Queen",
|
||||
"A Night at the Opera", intPtr(11), intPtr(1), 1975, "Rock",
|
||||
"Freddie Mercury", 354000, 0, 44100, 16, 2, 320000, 8500000,
|
||||
},
|
||||
{
|
||||
2, "/music/beyonce/halo.flac", "Halo", "Beyoncé", "Lemonade",
|
||||
intPtr(1), intPtr(1), 2008, "Pop", "Ryan Tedder", 261000, 1,
|
||||
96000, 24, 2, 1411000, 42000000,
|
||||
},
|
||||
{
|
||||
3, "/music/acdc/back_in_black.mp3", "Back in Black", "AC/DC",
|
||||
"Back in Black", intPtr(1), intPtr(1), 1980, "Hard Rock",
|
||||
"Angus Young", 255000, 0, 44100, 16, 2, 320000, 6100000,
|
||||
},
|
||||
{
|
||||
4, "/music/pinkfloyd/comfortably_numb.flac", "Comfortably Numb",
|
||||
"Pink Floyd", "The Dark Side of the Moon", intPtr(6), intPtr(1),
|
||||
1979, "Progressive Rock", "David Gilmour", 382000, 1, 96000, 24,
|
||||
2, 1411000, 54000000,
|
||||
},
|
||||
{
|
||||
5, "/music/queen/another_one_bites_the_dust.mp3",
|
||||
"Another One Bites the Dust", "Queen", "The Game", intPtr(3),
|
||||
intPtr(1), 1980, "Funk Rock", "John Deacon", 215000, 0, 44100,
|
||||
16, 2, 320000, 5200000,
|
||||
},
|
||||
{
|
||||
6, "/music/acdc/thunderstruck.mp3", "Thunderstruck", "AC/DC",
|
||||
"The Razors Edge", intPtr(1), intPtr(1), 1990, "Hard Rock",
|
||||
"Angus Young", 292000, 0, 44100, 16, 2, 320000, 7000000,
|
||||
},
|
||||
{
|
||||
7, "/music/qotsa/queen_of_the_stone_age.mp3",
|
||||
"Queen of the Stone Age", "Queens of the Stone Age", "Rated R",
|
||||
intPtr(1), intPtr(1), 2000, "Stoner Rock", "Josh Homme", 310000,
|
||||
0, 44100, 16, 2, 320000, 7400000,
|
||||
},
|
||||
}
|
||||
|
||||
// Build unique sets.
|
||||
type artistEntry struct {
|
||||
id int64
|
||||
text string
|
||||
}
|
||||
|
||||
type albumEntry struct {
|
||||
id int64
|
||||
name string
|
||||
}
|
||||
|
||||
artistMap := map[string]int64{}
|
||||
albumMap := map[string]int64{}
|
||||
|
||||
var artistID, albumID int64
|
||||
|
||||
for _, tr := range tracks {
|
||||
@@ -104,6 +126,7 @@ func seedSearchData(t *testing.T, db *DB) {
|
||||
|
||||
// Insert genres + recording_genres.
|
||||
genreMap := map[string]int64{}
|
||||
|
||||
var genreID int64
|
||||
|
||||
for _, tr := range tracks {
|
||||
@@ -131,8 +154,11 @@ func seedSearchData(t *testing.T, db *DB) {
|
||||
|
||||
// Insert recording.
|
||||
_, err := db.ExecContext(
|
||||
"INSERT INTO recordings (id, name, artist_credit_id, track_number, disc_number, year, genre, composer) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
tr.id, tr.title, acID, tr.trackNum, tr.discNum, tr.year, tr.genre, tr.composer,
|
||||
"INSERT INTO recordings (id, name, artist_credit_id, "+
|
||||
"track_number, disc_number, year, genre, composer) "+
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
tr.id, tr.title, acID, tr.trackNum, tr.discNum,
|
||||
tr.year, tr.genre, tr.composer,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("insert recording %d %q: %v", tr.id, tr.title, err)
|
||||
@@ -140,8 +166,12 @@ func seedSearchData(t *testing.T, db *DB) {
|
||||
|
||||
// Insert audio_files.
|
||||
_, err = db.ExecContext(
|
||||
"INSERT INTO audio_files (id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
tr.id, tr.filePath, tr.lenMs, tr.ftID, tr.id, tr.sr, tr.bd, tr.ch, tr.br, tr.fsize,
|
||||
"INSERT INTO audio_files (id, file_path, "+
|
||||
"length_milliseconds, file_type_id, recording_id, "+
|
||||
"sample_rate, bit_depth, channels, bitrate, file_size) "+
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
tr.id, tr.filePath, tr.lenMs, tr.ftID, tr.id,
|
||||
tr.sr, tr.bd, tr.ch, tr.br, tr.fsize,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("insert audio_file %d: %v", tr.id, err)
|
||||
@@ -149,7 +179,9 @@ func seedSearchData(t *testing.T, db *DB) {
|
||||
|
||||
// Link recording to release_group.
|
||||
_, err = db.ExecContext(
|
||||
"INSERT INTO release_group_recordings (release_group_id, recording_id, track_number, disc_number) VALUES (?, ?, ?, ?)",
|
||||
"INSERT INTO release_group_recordings "+
|
||||
"(release_group_id, recording_id, track_number, disc_number) "+
|
||||
"VALUES (?, ?, ?, ?)",
|
||||
rgID, tr.id, tr.trackNum, tr.discNum,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -368,6 +400,7 @@ func TestSearchFTS_SpecialCharacters(t *testing.T) {
|
||||
|
||||
// Verify at least one AC/DC track is present.
|
||||
found := false
|
||||
|
||||
for _, r := range results {
|
||||
if r.Artist == "AC/DC" {
|
||||
found = true
|
||||
@@ -432,6 +465,7 @@ func TestSearchFTS_Diacritics(t *testing.T) {
|
||||
}
|
||||
|
||||
found := false
|
||||
|
||||
for _, r := range results {
|
||||
if r.Artist == "Beyoncé" {
|
||||
found = true
|
||||
@@ -489,6 +523,7 @@ func TestSearchFTSByFilename(t *testing.T) {
|
||||
}
|
||||
|
||||
found := false
|
||||
|
||||
for _, r := range results {
|
||||
if r.Title == "Bohemian Rhapsody" {
|
||||
found = true
|
||||
@@ -620,7 +655,9 @@ func TestInsertAndDeleteSearchIndex(t *testing.T) {
|
||||
}
|
||||
|
||||
// Insert into search index.
|
||||
if err := db.InsertSearchIndex(1, "/test/track.mp3", "Test Track", "Test Artist", "Test Album"); err != nil {
|
||||
if err := db.InsertSearchIndex(
|
||||
1, "/test/track.mp3", "Test Track", "Test Artist", "Test Album",
|
||||
); err != nil {
|
||||
t.Fatalf("InsertSearchIndex: %v", err)
|
||||
}
|
||||
|
||||
@@ -781,11 +818,13 @@ func TestMigrationsApplied(t *testing.T) {
|
||||
|
||||
if !rows.Next() {
|
||||
_ = rows.Close()
|
||||
|
||||
t.Fatal("PRAGMA user_version: no row returned")
|
||||
}
|
||||
|
||||
if err := rows.Scan(&version); err != nil {
|
||||
_ = rows.Close()
|
||||
|
||||
t.Fatalf("scan user_version: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ func NewTestDB(t *testing.T) *DB {
|
||||
|
||||
queries := sqlcgen.New(db)
|
||||
|
||||
t.Cleanup(func() { db.Close() })
|
||||
t.Cleanup(func() { _ = db.Close() })
|
||||
|
||||
return &DB{
|
||||
db: db,
|
||||
|
||||
@@ -32,6 +32,7 @@ func main() {
|
||||
|
||||
if *output == "" || *output == "/dev/stdout" {
|
||||
fmt.Print(ts)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -57,6 +58,7 @@ type constEntry struct {
|
||||
// groups in declaration order.
|
||||
func parseEvents(path string) ([]constGroup, error) {
|
||||
fset := token.NewFileSet()
|
||||
|
||||
f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse %s: %w", path, err)
|
||||
@@ -82,11 +84,14 @@ func parseEvents(path string) ([]constGroup, error) {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for i, name := range vs.Names {
|
||||
if i >= len(vs.Values) {
|
||||
continue
|
||||
}
|
||||
|
||||
bl, ok := vs.Values[i].(*ast.BasicLit)
|
||||
|
||||
if !ok || bl.Kind != token.STRING {
|
||||
continue
|
||||
}
|
||||
@@ -110,6 +115,7 @@ func parseEvents(path string) ([]constGroup, error) {
|
||||
func cleanComment(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
s = strings.TrimSuffix(s, ".")
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -126,6 +132,7 @@ func generateTypeScript(groups []constGroup) string {
|
||||
if g.Comment != "" {
|
||||
b.WriteString(" // " + g.Comment + "\n")
|
||||
}
|
||||
|
||||
for _, c := range g.Consts {
|
||||
b.WriteString(fmt.Sprintf(" %s: %q,\n", c.Name, c.Value))
|
||||
}
|
||||
@@ -146,20 +153,26 @@ func generateTypeScript(groups []constGroup) string {
|
||||
// then renames it into place for atomic replacement.
|
||||
func writeAtomic(path, data string) error {
|
||||
dir := filepath.Dir(path)
|
||||
|
||||
tmp, err := os.CreateTemp(dir, ".genevents-*.tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpName := tmp.Name()
|
||||
|
||||
if _, err := tmp.WriteString(data); err != nil {
|
||||
tmp.Close()
|
||||
os.Remove(tmpName)
|
||||
_ = tmp.Close()
|
||||
_ = os.Remove(tmpName)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tmp.Close(); err != nil {
|
||||
os.Remove(tmpName)
|
||||
_ = os.Remove(tmpName)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Rename(tmpName, path)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ func TestFavoritesConfig_Validate_InvalidIconStyle(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := &Config{IconStyle: "diamond"}
|
||||
|
||||
err := c.Validate()
|
||||
if err == nil {
|
||||
t.Fatal("Validate() expected error for unknown icon style, got nil")
|
||||
|
||||
@@ -229,6 +229,7 @@ func (l *Library) Scan() (*ScanMetrics, error) {
|
||||
"count", len(existingFiles),
|
||||
"library-directory", l.conf.DirectoryPath,
|
||||
)
|
||||
|
||||
workChan := make(chan scanWork, 100)
|
||||
resultChan := make(chan importResult, 100)
|
||||
|
||||
@@ -531,10 +532,14 @@ func (l *Library) Scan() (*ScanMetrics, error) {
|
||||
// point so it is safe to close.
|
||||
thumbStart := time.Now()
|
||||
|
||||
runtime.EventsEmit(l.ctx, events.LibraryScanProgress,
|
||||
ScanProgress{Phase: "thumbnails", Total: totalFiles,
|
||||
Processed: a + s + u, Added: a, Skipped: s, Updated: u},
|
||||
)
|
||||
runtime.EventsEmit(l.ctx, events.LibraryScanProgress, ScanProgress{
|
||||
Phase: "thumbnails",
|
||||
Total: totalFiles,
|
||||
Processed: a + s + u,
|
||||
Added: a,
|
||||
Skipped: s,
|
||||
Updated: u,
|
||||
})
|
||||
|
||||
close(thumbChan)
|
||||
thumbWg.Wait()
|
||||
@@ -542,10 +547,10 @@ func (l *Library) Scan() (*ScanMetrics, error) {
|
||||
metrics.ThumbnailWallClock = time.Since(thumbStart)
|
||||
|
||||
// --- Phase 5: orphan cleanup ---
|
||||
runtime.EventsEmit(l.ctx, events.LibraryScanProgress,
|
||||
ScanProgress{Phase: "orphans", Total: totalFiles,
|
||||
Processed: a + s + u, Added: a, Skipped: s, Updated: u},
|
||||
)
|
||||
runtime.EventsEmit(l.ctx, events.LibraryScanProgress, ScanProgress{
|
||||
Phase: "orphans", Total: totalFiles,
|
||||
Processed: a + s + u, Added: a, Skipped: s, Updated: u,
|
||||
})
|
||||
|
||||
orphanStart := time.Now()
|
||||
|
||||
|
||||
@@ -396,7 +396,10 @@ func TestCachedLinkArtist(t *testing.T) {
|
||||
lib.cachedLinkArtist(q, cache, metrics, "Queen", ac.ID)
|
||||
|
||||
if len(cache.linkedCredits) != 1 {
|
||||
t.Errorf("linkedCredits after duplicate = %d, want 1 (should skip)", len(cache.linkedCredits))
|
||||
t.Errorf(
|
||||
"linkedCredits after duplicate = %d, want 1 (should skip)",
|
||||
len(cache.linkedCredits),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,6 +539,7 @@ func TestResolveReleaseGroup(t *testing.T) {
|
||||
// Cache key is composite: "albumName\x00artistCreditID".
|
||||
cacheKey := fmt.Sprintf("%s\x00%d", "A Night at the Opera", ac.ID)
|
||||
cachedRG := cache.releaseGroups[cacheKey]
|
||||
|
||||
if !cachedRG.CoverArtID.Valid {
|
||||
t.Error("expected CoverArtID to be set after update")
|
||||
}
|
||||
@@ -616,7 +620,9 @@ func TestOrphanDeletion(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add FTS search index entry.
|
||||
if err := db.InsertSearchIndex(af.ID, "/music/test.mp3", "Test Song", "Test Artist", ""); err != nil {
|
||||
if err := db.InsertSearchIndex(
|
||||
af.ID, "/music/test.mp3", "Test Song", "Test Artist", "",
|
||||
); err != nil {
|
||||
t.Fatalf("insert search index: %v", err)
|
||||
}
|
||||
|
||||
@@ -651,11 +657,12 @@ func TestOrphanDeletion(t *testing.T) {
|
||||
// become stale but harmless (they reference a non-existent
|
||||
// audio_file ID, so JOINs return no results).
|
||||
// ClearSearchIndex (used during full rescan) handles bulk cleanup.
|
||||
// DeleteSearchIndex on contentless FTS5 is expected to error.
|
||||
// Not a fatal error — documents the contentless FTS5 limitation.
|
||||
err = db.DeleteSearchIndex(af.ID)
|
||||
if err == nil {
|
||||
t.Log("DeleteSearchIndex succeeded (unexpected for contentless FTS5)")
|
||||
}
|
||||
// Not a fatal error — documents the contentless FTS5 limitation.
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -705,7 +712,10 @@ func TestEntityCache_EmptyFields(t *testing.T) {
|
||||
}
|
||||
|
||||
if albumACID.Int64 != trackAC.ID {
|
||||
t.Errorf("empty AlbumArtist should reuse track credit: got %d, want %d", albumACID.Int64, trackAC.ID)
|
||||
t.Errorf(
|
||||
"empty AlbumArtist should reuse track credit: got %d, want %d",
|
||||
albumACID.Int64, trackAC.ID,
|
||||
)
|
||||
}
|
||||
|
||||
// resolveAlbumArtistCredit when AlbumArtist matches Artist also reuses.
|
||||
@@ -716,6 +726,9 @@ func TestEntityCache_EmptyFields(t *testing.T) {
|
||||
|
||||
sameACID := lib.resolveAlbumArtistCredit(q, cache, metrics, sameTags, trackAC.ID)
|
||||
if sameACID.Int64 != trackAC.ID {
|
||||
t.Errorf("matching AlbumArtist should reuse track credit: got %d, want %d", sameACID.Int64, trackAC.ID)
|
||||
t.Errorf(
|
||||
"matching AlbumArtist should reuse track credit: got %d, want %d",
|
||||
sameACID.Int64, trackAC.ID,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +126,11 @@ func TestUserVolume_ToVolume_Roundtrip(t *testing.T) {
|
||||
|
||||
diff := int(roundtripped) - int(i)
|
||||
if diff < -1 || diff > 1 {
|
||||
t.Errorf("Roundtrip UserVolume(%d) -> Volume(%f) -> UserVolume(%d): drift %d exceeds ±1",
|
||||
i, vol, roundtripped, diff)
|
||||
t.Errorf(
|
||||
"Roundtrip UserVolume(%d) -> Volume(%f) -> UserVolume(%d): "+
|
||||
"drift %d exceeds ±1",
|
||||
i, vol, roundtripped, diff,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,8 +141,11 @@ func TestUserVolume_ToVolume_Roundtrip(t *testing.T) {
|
||||
roundtripped := vol.ToUserVolume()
|
||||
|
||||
if roundtripped != uv {
|
||||
t.Errorf("Exact roundtrip UserVolume(%d) -> Volume(%f) -> UserVolume(%d): want exact match",
|
||||
uv, vol, roundtripped)
|
||||
t.Errorf(
|
||||
"Exact roundtrip UserVolume(%d) -> Volume(%f) -> "+
|
||||
"UserVolume(%d): want exact match",
|
||||
uv, vol, roundtripped,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ func newTestQueueDirect(tracks int, currentIndex int) *Queue {
|
||||
}
|
||||
|
||||
q.tracks = make([]Track, tracks)
|
||||
for i := 0; i < tracks; i++ {
|
||||
for i := range tracks {
|
||||
q.tracks[i] = Track{FilePath: "/test/track.mp3", Position: int64(i)}
|
||||
}
|
||||
|
||||
@@ -135,11 +135,15 @@ func TestGenerateShuffleOrder_Properties(t *testing.T) {
|
||||
|
||||
// Property 2: current track is at shuffleOrder[0].
|
||||
if q.shuffleOrder[0] != tc.currentIdx {
|
||||
t.Errorf("shuffleOrder[0]: got %d, want %d (currentIndex)", q.shuffleOrder[0], tc.currentIdx)
|
||||
t.Errorf(
|
||||
"shuffleOrder[0]: got %d, want %d (currentIndex)",
|
||||
q.shuffleOrder[0], tc.currentIdx,
|
||||
)
|
||||
}
|
||||
|
||||
// Property 3: all indices present (no duplicates, no missing).
|
||||
seen := make(map[int]bool, tc.trackCount)
|
||||
|
||||
for _, idx := range q.shuffleOrder {
|
||||
if idx < 0 || idx >= tc.trackCount {
|
||||
t.Errorf("shuffleOrder contains out-of-range index: %d", idx)
|
||||
@@ -153,7 +157,10 @@ func TestGenerateShuffleOrder_Properties(t *testing.T) {
|
||||
}
|
||||
|
||||
if len(seen) != tc.trackCount {
|
||||
t.Errorf("unique indices in shuffleOrder: got %d, want %d", len(seen), tc.trackCount)
|
||||
t.Errorf(
|
||||
"unique indices in shuffleOrder: got %d, want %d",
|
||||
len(seen), tc.trackCount,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -177,6 +184,7 @@ func TestNextIndex_ShuffleMode(t *testing.T) {
|
||||
// Advance to index 4 and get next.
|
||||
q.currentIndex = 4
|
||||
got = q.nextIndex()
|
||||
|
||||
if got != 0 {
|
||||
t.Errorf("nextIndex (shuffle, pos 2): got %d, want 0", got)
|
||||
}
|
||||
@@ -184,6 +192,7 @@ func TestNextIndex_ShuffleMode(t *testing.T) {
|
||||
// At the end of shuffle order with RepeatOff.
|
||||
q.currentIndex = 1 // last in shuffleOrder
|
||||
got = q.nextIndex()
|
||||
|
||||
if got != -1 {
|
||||
t.Errorf("nextIndex (shuffle, end, repeatOff): got %d, want -1", got)
|
||||
}
|
||||
@@ -191,7 +200,11 @@ func TestNextIndex_ShuffleMode(t *testing.T) {
|
||||
// At the end of shuffle order with RepeatAll.
|
||||
q.repeatMode = RepeatAll
|
||||
got = q.nextIndex()
|
||||
|
||||
if got != 2 {
|
||||
t.Errorf("nextIndex (shuffle, end, repeatAll): got %d, want 2 (wraps to shuffleOrder[0])", got)
|
||||
t.Errorf(
|
||||
"nextIndex (shuffle, end, repeatAll): got %d, want 2 "+
|
||||
"(wraps to shuffleOrder[0])", got,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,10 @@ func TestSaveState_RestoreState_Roundtrip(t *testing.T) {
|
||||
// Each track's FilePath, Title, Artist.
|
||||
for i := range s1.Tracks {
|
||||
if s2.Tracks[i].FilePath != s1.Tracks[i].FilePath {
|
||||
t.Errorf("track[%d] FilePath: got %q, want %q", i, s2.Tracks[i].FilePath, s1.Tracks[i].FilePath)
|
||||
t.Errorf(
|
||||
"track[%d] FilePath: got %q, want %q",
|
||||
i, s2.Tracks[i].FilePath, s1.Tracks[i].FilePath,
|
||||
)
|
||||
}
|
||||
|
||||
if s2.Tracks[i].Title != s1.Tracks[i].Title {
|
||||
@@ -43,7 +46,10 @@ func TestSaveState_RestoreState_Roundtrip(t *testing.T) {
|
||||
}
|
||||
|
||||
if s2.Tracks[i].Artist != s1.Tracks[i].Artist {
|
||||
t.Errorf("track[%d] Artist: got %q, want %q", i, s2.Tracks[i].Artist, s1.Tracks[i].Artist)
|
||||
t.Errorf(
|
||||
"track[%d] Artist: got %q, want %q",
|
||||
i, s2.Tracks[i].Artist, s1.Tracks[i].Artist,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +77,10 @@ func TestSaveState_RestoreState_Roundtrip(t *testing.T) {
|
||||
} else {
|
||||
for i := range q.shuffleOrder {
|
||||
if q2.shuffleOrder[i] != q.shuffleOrder[i] {
|
||||
t.Errorf("shuffleOrder[%d]: got %d, want %d", i, q2.shuffleOrder[i], q.shuffleOrder[i])
|
||||
t.Errorf(
|
||||
"shuffleOrder[%d]: got %d, want %d",
|
||||
i, q2.shuffleOrder[i], q.shuffleOrder[i],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ type mockTrackLoader struct {
|
||||
|
||||
func (m *mockTrackLoader) LoadFile(filePath string) error {
|
||||
m.loadedFile = filePath
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -53,7 +54,7 @@ func seedAudioFiles(t *testing.T, db *database.DB, count int) []string {
|
||||
|
||||
paths := make([]string, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
for i := range count {
|
||||
recID := i + 1
|
||||
afID := i + 1
|
||||
fp := fmt.Sprintf("/test/track%d.mp3", i+1)
|
||||
@@ -68,7 +69,9 @@ func seedAudioFiles(t *testing.T, db *database.DB, count int) []string {
|
||||
}
|
||||
|
||||
_, err = db.ExecContext(
|
||||
"INSERT OR IGNORE INTO audio_files (id, file_path, length_milliseconds, file_type_id, recording_id) VALUES (?, ?, 180000, 0, ?)",
|
||||
"INSERT OR IGNORE INTO audio_files (id, file_path, "+
|
||||
"length_milliseconds, file_type_id, recording_id) "+
|
||||
"VALUES (?, ?, 180000, 0, ?)",
|
||||
afID, fp, recID,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -292,7 +295,10 @@ func TestRemoveTrack_RemoveCurrentTrack(t *testing.T) {
|
||||
|
||||
// After removing currentIndex=2, index should be clamped to valid range.
|
||||
if state.CurrentIndex < 0 || state.CurrentIndex >= len(state.Tracks) {
|
||||
t.Errorf("currentIndex out of range: got %d, track count %d", state.CurrentIndex, len(state.Tracks))
|
||||
t.Errorf(
|
||||
"currentIndex out of range: got %d, track count %d",
|
||||
state.CurrentIndex, len(state.Tracks),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ func TestThemeConfig_Validate_InvalidHexColor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := &Config{AccentColor: tt.color, BackgroundShade: BackgroundDark}
|
||||
|
||||
err := c.Validate()
|
||||
if err == nil {
|
||||
t.Error("Validate() expected error for invalid hex color, got nil")
|
||||
@@ -61,6 +62,7 @@ func TestThemeConfig_Validate_InvalidBackgroundShade(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := &Config{AccentColor: "#ffd43b", BackgroundShade: "neon"}
|
||||
|
||||
err := c.Validate()
|
||||
if err == nil {
|
||||
t.Fatal("Validate() expected error for unknown shade, got nil")
|
||||
|
||||
Reference in New Issue
Block a user