soulsync/tests/test_track_repair_canonical.py
BoulderBadgeDad f5752e3dc0 Canonical album version — Stage 4: Track Number Repair prefers canonical (read)
_resolve_album_tracklist gains a Fallback -1: if the album has a pinned
canonical (source, album_id), use it before the existing 6-level cascade — so
Track Number Repair resolves the SAME release the Reorganizer does (Stage 3) and
the two stop contradicting each other (#765, the Spotify-4 vs MusicBrainz-3
conflict).

Gated + additive: the entire existing cascade is untouched for albums without a
canonical, so this job's all-01-album rescue (which relies on the MusicBrainz/
AudioDB fallbacks for albums with no DB source ID) is fully preserved — that's
the regression we explicitly refused to take in a reactive fix.

New helper _lookup_canonical_from_db() mirrors _lookup_album_ids_from_db
(file-path -> track -> album), returns None when no DB / no match / columns
absent / unresolved.

Tests: tests/test_track_repair_canonical.py (4) — returns canonical when pinned,
None when unresolved / file untracked / no DB. Existing track_number_repair
tests still pass (no regression).
2026-06-02 11:47:42 -07:00

52 lines
1.9 KiB
Python

"""Track Number Repair canonical lookup (#765 Stage 4, read side)."""
from __future__ import annotations
import types
from core.repair_jobs.track_number_repair import _lookup_canonical_from_db
from database.music_database import MusicDatabase
def _ctx(db):
return types.SimpleNamespace(db=db)
def _seed(db, *, with_canonical: bool, file_path: str = "/music/Evolve/01 - Believer.flac"):
conn = db._get_connection()
cur = conn.cursor()
cur.execute("INSERT INTO artists (id, name) VALUES ('art1', 'Imagine Dragons')")
cur.execute("INSERT INTO albums (id, title, artist_id) VALUES ('alb1', 'Evolve', 'art1')")
cur.execute(
"INSERT INTO tracks (id, album_id, artist_id, title, track_number, duration, file_path) "
"VALUES ('t1', 'alb1', 'art1', 'Believer', 1, 204000, ?)",
(file_path,),
)
conn.commit()
conn.close()
if with_canonical:
db.set_album_canonical("alb1", "spotify", "sp_evolve", 0.96)
def test_returns_canonical_when_pinned(tmp_path):
db = MusicDatabase(str(tmp_path / "m.db"))
fp = "/music/Evolve/01 - Believer.flac"
_seed(db, with_canonical=True, file_path=fp)
assert _lookup_canonical_from_db([(fp, "01 - Believer.flac", 1)], _ctx(db)) == ("spotify", "sp_evolve")
def test_none_when_unresolved(tmp_path):
db = MusicDatabase(str(tmp_path / "m.db"))
fp = "/music/Evolve/01 - Believer.flac"
_seed(db, with_canonical=False, file_path=fp)
assert _lookup_canonical_from_db([(fp, "01 - Believer.flac", 1)], _ctx(db)) is None
def test_none_when_file_not_tracked(tmp_path):
db = MusicDatabase(str(tmp_path / "m.db"))
_seed(db, with_canonical=True)
assert _lookup_canonical_from_db([("/some/other/path.flac", "x.flac", 1)], _ctx(db)) is None
def test_none_when_no_db():
assert _lookup_canonical_from_db([("/p.flac", "p.flac", 1)], types.SimpleNamespace(db=None)) is None