"""Tests for the Albums-view follow-up (#689's client half): the feedpak `track`/`disc` fields flowing scanner → songs columns → the `track` sort the album track list orders by.""" import importlib import sys import pytest from fastapi.testclient import TestClient @pytest.fixture() def server(tmp_path, monkeypatch, isolate_logging): monkeypatch.setenv("CONFIG_DIR", str(tmp_path / "config")) dlc = tmp_path / "dlc" dlc.mkdir() monkeypatch.setenv("DLC_DIR", str(dlc)) monkeypatch.setenv("FEEDBACK_SKIP_STARTUP_TASKS", "1") sys.modules.pop("server", None) srv = importlib.import_module("server") try: yield srv finally: conn = getattr(getattr(srv, "meta_db", None), "conn", None) if conn is not None: getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)() conn.close() sys.modules.pop("server", None) @pytest.fixture() def client(server): return TestClient(server.app) def _put(server, fn, title, track=None, disc=None, album="The Album", artist="Artist", genre=""): server.meta_db.put(fn, 0, 0, { "title": title, "artist": artist, "album": album, "year": "1990", "duration": 100, "arrangements": [{"name": "Lead", "index": 0}], "track_number": track, "disc": disc, "genre": genre, }) def test_sloppak_extract_meta_reads_track_and_disc(server): d = server.DLC_DIR / "a.sloppak" d.mkdir(parents=True) (d / "manifest.yaml").write_text( "title: Song\nartist: Artist\nduration: 100\n" "arrangements: []\nstems: []\ntrack: 7\ndisc: 2\n", encoding="utf-8") import sloppak meta = sloppak.extract_meta(d) assert meta["track_number"] == 7 assert meta["disc"] == 2 # Unauthored → None (the album view falls back to title order). (d / "manifest.yaml").write_text( "title: Song\nartist: Artist\nduration: 100\n" "arrangements: []\nstems: []\n", encoding="utf-8") meta = sloppak.extract_meta(d) assert meta["track_number"] is None assert meta["disc"] is None def test_track_sort_orders_by_disc_then_track_nulls_last(server, client): _put(server, "d2t1.sloppak", "Zeta", track=1, disc=2) _put(server, "d1t2.sloppak", "Yankee", track=2, disc=1) _put(server, "d1t1.sloppak", "Xray", track=1, disc=1) _put(server, "nonum-b.sloppak", "Bravo") # unauthored → bottom, _put(server, "nonum-a.sloppak", "Alpha") # ordered by title body = client.get("/api/library", params={ "artist": "Artist", "album": "The Album", "sort": "track", "size": 50}).json() assert [s["filename"] for s in body["songs"]] == [ "d1t1.sloppak", "d1t2.sloppak", "d2t1.sloppak", "nonum-a.sloppak", "nonum-b.sloppak"] def test_track_and_disc_survive_put_roundtrip(server): _put(server, "a.sloppak", "Song", track=3, disc=1) row = server.meta_db.conn.execute( "SELECT track_number, disc FROM songs WHERE filename = 'a.sloppak'").fetchone() assert row == (3, 1) def test_albums_endpoint_honours_genre_filter(server, client): """The albums grid must respect the Genre drawer filter the client sends — without this the /api/library/albums route silently dropped `genre` and surfaced albums with no matching tracks.""" _put(server, "rock.sloppak", "Rocker", album="Rock LP", genre="Rock") _put(server, "jazz.sloppak", "Smooth", album="Jazz LP", genre="Jazz") all_albums = client.get("/api/library/albums", params={"artist": "Artist"}).json() assert {a["album"] for a in all_albums["albums"]} == {"Rock LP", "Jazz LP"} filtered = client.get("/api/library/albums", params={"artist": "Artist", "genre": "Rock"}).json() assert [a["album"] for a in filtered["albums"]] == ["Rock LP"]