refactor: delete dead code, dedupe helpers, add tests for untested packages

Dead code
  Removed, each verified to have no non-test caller: promptSearchSelection
  (77 lines, superseded by promptSearchSelectionMenu), AddPlaylistByTrackIDs,
  download.NewWithVerifySSL, qobuz.Client.GetTrackMetadata,
  tidal.Client.trackSupportsAtmos (test-only, and the comment above
  GetDownloadable already documented its removal from the live path) and its
  now-orphaned test, yandex.canonicalTrackRequestID (a no-op returning its
  trimmed input; the call site uses strings.TrimSpace directly) and the unused
  defaultEstimatedKbps constant.

Config keys that did nothing
  qobuz.download_booklets and misc.check_for_updates were declared, defaulted
  and documented in config.toml.example but read by no code. The whole
  [youtube] block went too: there is no YouTube provider. go-toml ignores
  unknown keys, verified, so existing user configs still load.

Duplicated helpers
  tidal.stringify and yandex.firstNonEmpty were byte-identical copies of
  jsonutil.StringFromAny and jsonutil.FirstNonEmpty. displayArtistNames
  existed three times, byte-identical, in internal/app, provider/yandex and
  provider/beatport; it now lives in jsonutil. The CLI's normalizeCodec
  delegates to config.NormalizeCodec so the flag and the config file are
  checked by the same rules.

Tests for packages that had none
  internal/jsonutil (0% -> 100%) and internal/netutil (0% -> 78%), the latter
  covering redactURL, which is a security control, and the zero-timeout
  contract that internal/download and the qobuz body copy depend on.
  internal/config rose to 82% with coverage of the new Validate(), the
  0600 permissions, CloneConfigData not sharing slices, and a concurrent
  UpdateTokens test that exercises the mutex under -race.

Test suite is ~85x faster
  Provider tests built clients with the default 60 requests/minute, so the
  rate limiter slept 1s per HTTP call: deezer took 31s, tidal 11s, qobuz 8s.
  Each provider test package now builds its config through a testConfigData
  helper that disables throttling. Whole suite: ~60s -> 0.7s, and 2.8s
  under -race.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
JorenandClaude Opus 5 committed 2026-10-03 17:05:55 +02:00
1 parent 201aa5daa7
commit b3b6a2eb1d
19 files changed
+701 -392

No files matched your search

+27 -38
View File
@@ -12,10 +12,11 @@ import (
"testing"
"streamrip-go/internal/config"
"streamrip-go/internal/jsonutil"
)
func TestLoginMissingToken(t *testing.T) {
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Tidal.AccessToken = ""
c := New(&config.Config{File: cfgData, Session: cfgData})
err := c.Login(context.Background())
@@ -37,7 +38,7 @@ func TestSearch(t *testing.T) {
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "US"
c := New(&config.Config{File: cfgData, Session: cfgData})
@@ -73,7 +74,7 @@ func TestGetVideoDownloadable(t *testing.T) {
}))
defer server.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "US"
c := New(&config.Config{File: cfgData, Session: cfgData})
@@ -143,7 +144,7 @@ func TestGetMetadataArtistPaginatesAlbums(t *testing.T) {
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "US"
c := New(&config.Config{File: cfgData, Session: cfgData})
@@ -185,7 +186,7 @@ func TestGetMetadataTrackAddsLyricsAndSyncedLyrics(t *testing.T) {
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "MY"
c := New(&config.Config{File: cfgData, Session: cfgData})
@@ -197,10 +198,10 @@ func TestGetMetadataTrackAddsLyricsAndSyncedLyrics(t *testing.T) {
if err != nil {
t.Fatalf("GetMetadata() err = %v", err)
}
if got := stringify(meta["lyrics"]); got != "plain lyrics line" {
if got := jsonutil.StringFromAny(meta["lyrics"]); got != "plain lyrics line" {
t.Fatalf("lyrics = %q, want plain lyrics line", got)
}
if got := stringify(meta["lyrics_synced"]); got != "[00:00.00]plain lyrics line" {
if got := jsonutil.StringFromAny(meta["lyrics_synced"]); got != "[00:00.00]plain lyrics line" {
t.Fatalf("lyrics_synced = %q, want synced lrc", got)
}
}
@@ -219,7 +220,7 @@ func TestGetMetadataTrackIgnoresLyricsEndpointFailure(t *testing.T) {
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "US"
c := New(&config.Config{File: cfgData, Session: cfgData})
@@ -257,7 +258,7 @@ func TestAPIRequestRetriesTooManyRequests(t *testing.T) {
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Downloads.RequestsPerMinute = 0
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "US"
@@ -274,8 +275,8 @@ func TestAPIRequestRetriesTooManyRequests(t *testing.T) {
if calls != 2 {
t.Fatalf("calls = %d, want 2", calls)
}
if stringify(resp["title"]) != "Song" {
t.Fatalf("title = %q, want Song", stringify(resp["title"]))
if jsonutil.StringFromAny(resp["title"]) != "Song" {
t.Fatalf("title = %q, want Song", jsonutil.StringFromAny(resp["title"]))
}
}
@@ -297,7 +298,7 @@ func TestAPIPostRetriesTooManyRequests(t *testing.T) {
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Downloads.RequestsPerMinute = 0
c := New(&config.Config{File: cfgData, Session: cfgData})
@@ -311,8 +312,8 @@ func TestAPIPostRetriesTooManyRequests(t *testing.T) {
if calls != 2 {
t.Fatalf("calls = %d, want 2", calls)
}
if stringify(resp["access_token"]) != "fresh-token" {
t.Fatalf("access_token = %q, want fresh-token", stringify(resp["access_token"]))
if jsonutil.StringFromAny(resp["access_token"]) != "fresh-token" {
t.Fatalf("access_token = %q, want fresh-token", jsonutil.StringFromAny(resp["access_token"]))
}
}
@@ -342,7 +343,7 @@ func TestGetDownloadablePrefersAtmosWhenEnabled(t *testing.T) {
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "US"
cfgData.Tidal.PreferAtmos = true
@@ -377,28 +378,6 @@ func TestPlaybackLooksAtmosFromManifest(t *testing.T) {
}
}
func TestTrackSupportsAtmosFromTags(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v1/tracks/42" {
w.WriteHeader(http.StatusNotFound)
return
}
_ = json.NewEncoder(w).Encode(map[string]any{"id": 42, "audioModes": []any{"STEREO"}, "mediaMetadata": map[string]any{"tags": []any{"LOSSLESS", "DOLBY_ATMOS"}}})
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "US"
c := New(&config.Config{File: cfgData, Session: cfgData})
c.loggedIn = true
c.baseURL = ts.URL + "/v1"
if !c.trackSupportsAtmos(context.Background(), "42") {
t.Fatalf("expected atmos support from mediaMetadata tags")
}
}
func TestFormatsForQuality(t *testing.T) {
tests := []struct {
name string
@@ -448,7 +427,7 @@ func TestGetDownloadableLosslessUsesTrackManifestWhenPlaybackIsAAC(t *testing.T)
}))
defer ts.Close()
cfgData := config.DefaultConfigData()
cfgData := testConfigData()
cfgData.Tidal.AccessToken = "token"
cfgData.Tidal.CountryCode = "US"
c := New(&config.Config{File: cfgData, Session: cfgData})
@@ -473,3 +452,13 @@ func TestGetDownloadableLosslessUsesTrackManifestWhenPlaybackIsAAC(t *testing.T)
t.Fatalf("unexpected audio profile: %+v", d.Audio)
}
}
// testConfigData returns defaults with request throttling disabled.
//
// At the default 60 requests/minute the rate limiter sleeps 1s per request,
// which accounted for most of this suite's runtime (deezer alone was 31s).
func testConfigData() config.ConfigData {
d := config.DefaultConfigData()
d.Downloads.RequestsPerMinute = -1
return d
}