fix: T16 verification cleanups

- golangci-lint: errcheck on resp.Body.Close in Lidarr client + revive
  unused-parameter in delete_test.go
- coverage: 2 error-branch tests added to lidarrquarantine.Service
  (DeleteFile + DeleteViaLidarr track-not-found paths) bring per-package
  coverage to 81.4% (target >=80%)
- search/tracks.test.ts: same TrackMenu name-collision fix T13 applied to
  TrackRow.test.ts — exact-string button match instead of regex
This commit is contained in:
2026-04-30 20:49:11 -04:00
parent 3bfec944c7
commit 3e3ad89645
5 changed files with 54 additions and 6 deletions
+1 -1
View File
@@ -64,6 +64,6 @@ func (c *Client) DeleteAlbum(ctx context.Context, lidarrAlbumID int, deleteFiles
if err != nil {
return err
}
resp.Body.Close()
_ = resp.Body.Close()
return nil
}
+1 -1
View File
@@ -203,7 +203,7 @@ func TestDeleteAlbum_NetworkErrorReturnsErrUnreachable(t *testing.T) {
}
func TestDeleteAlbum_ZeroIDRejected(t *testing.T) {
c, srv := newTestClient(func(w http.ResponseWriter, _ *http.Request) {
c, srv := newTestClient(func(_ http.ResponseWriter, _ *http.Request) {
t.Error("server should not be called with zero id")
})
defer srv.Close()
+2 -2
View File
@@ -18,7 +18,7 @@ func (c *Client) LookupArtistByMBID(ctx context.Context, mbid string) (LidarrArt
if err != nil {
return LidarrArtist{}, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
var rows []LidarrArtist
if err := json.NewDecoder(resp.Body).Decode(&rows); err != nil {
@@ -41,7 +41,7 @@ func (c *Client) LookupAlbumByMBID(ctx context.Context, mbid string) (LidarrAlbu
if err != nil {
return LidarrAlbum{}, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
var rows []LidarrAlbum
if err := json.NewDecoder(resp.Body).Decode(&rows); err != nil {
+41
View File
@@ -491,3 +491,44 @@ func TestDeleteViaLidarr_LidarrAlbumNotFound(t *testing.T) {
t.Errorf("err = %v, want ErrLidarrAlbumNotFound", err)
}
}
func TestDeleteFile_TrackNotFound(t *testing.T) {
pool := newPool(t)
user := seedUser(t, pool, "alice")
var bogus pgtype.UUID
bogus.Bytes = [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
bogus.Valid = true
svc := NewService(pool, lidarrconfig.New(pool), nil)
_, err := svc.DeleteFile(context.Background(), bogus, user.ID)
if !errors.Is(err, ErrTrackNotFound) {
t.Errorf("err = %v, want ErrTrackNotFound", err)
}
}
func TestDeleteViaLidarr_TrackNotFound(t *testing.T) {
pool := newPool(t)
user := seedUser(t, pool, "alice")
stub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}))
t.Cleanup(stub.Close)
cfg := lidarrconfig.New(pool)
if err := cfg.Save(context.Background(), lidarrconfig.Config{
Enabled: true, BaseURL: stub.URL, APIKey: "k",
}); err != nil {
t.Fatalf("save config: %v", err)
}
clientFn := func() *lidarr.Client { return lidarr.NewClient(stub.URL, "k") }
svc := NewService(pool, cfg, clientFn)
var bogus pgtype.UUID
bogus.Bytes = [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
bogus.Valid = true
_, _, err := svc.DeleteViaLidarr(context.Background(), bogus, user.ID)
if !errors.Is(err, ErrTrackNotFound) {
t.Errorf("err = %v, want ErrTrackNotFound", err)
}
}
+9 -2
View File
@@ -35,6 +35,13 @@ vi.mock('@tanstack/svelte-query', async (orig) => {
return { ...actual, useQueryClient: () => ({}) };
});
vi.mock('$lib/api/quarantine', () => ({
flagTrack: vi.fn(),
unflagTrack: vi.fn(),
listMyQuarantine: vi.fn().mockResolvedValue([]),
createMyQuarantineQuery: vi.fn()
}));
import TracksOverflow from './+page.svelte';
import { createSearchTracksInfiniteQuery } from '$lib/api/queries';
import { playRadio } from '$lib/player/store.svelte';
@@ -62,7 +69,7 @@ describe('search tracks overflow', () => {
mockInfiniteQuery({ pages: [page([track], 1)] })
);
render(TracksOverflow);
expect(screen.getByRole('button', { name: /So What/ })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'So What' })).toBeInTheDocument();
});
test('clicking a track row triggers playRadio with the track id', async () => {
@@ -70,7 +77,7 @@ describe('search tracks overflow', () => {
mockInfiniteQuery({ pages: [page([track], 1)] })
);
render(TracksOverflow);
await fireEvent.click(screen.getByRole('button', { name: /So What/ }));
await fireEvent.click(screen.getByRole('button', { name: 'So What' }));
expect(playRadio).toHaveBeenCalledWith('t1');
});