soulsync/tests/quality/test_source_map.py
dev 774d0f6c65 feat(quality): make every audio format controllable via ranked targets
The ranked-target list is now the single source of truth for which formats
download, in the user's exact priority order, for ALL sources — no hardcoded
format hierarchy decides anything. A candidate passes only if it matches a
ranked target; if nothing matches, the existing Use-Fallback toggle decides.

- source_map: new shared format_from_extension() + AUDIO_EXTENSIONS — one
  source of truth for extension→format used by every extension-based source, so
  adding a format lights it up everywhere. Soulseek now classifies through it
  (opus/wav/aiff were previously dropped as 'unknown').
- file_ops.probe_audio_quality (generic import-time guard, all sources): add
  WMA; detect ALAC from the real codec (an .m4a is AAC or ALAC).
- soulseek: drop the AAC-specific opt-in gate — AAC now follows the same
  universal rule as every format.
- model.tier_score: documented as ONLY a same-format tiebreak + fallback order,
  never cross-format priority (the list owns that); add opus/alac bases.
- UI: ranked-target editor offers all formats (FLAC/ALAC/WAV·AIFF lossless with
  bit-depth+sample-rate; MP3/AAC/OGG/Opus/WMA lossy with min-bitrate).
- tests: AAC retargeted to the universal model; new coverage for
  format_from_extension and matches_target across all formats.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 23:01:20 +02:00

147 lines
4.5 KiB
Python

"""Tests for core.quality.source_map — each download source's tier/string
mapped into a unified AudioQuality.
These mappers express each source's *claimed* capability tier. The values
are later verified post-download by the quality guard, so over-claiming is
the failure mode to avoid: an unknown tier must NOT pretend to be lossless.
"""
import pytest
from core.quality.source_map import (
quality_from_tidal_tier,
quality_from_qobuz,
quality_from_deezer,
quality_from_amazon,
format_from_extension,
AUDIO_EXTENSIONS,
)
# ── Shared extension → format (used by every extension-based source) ────────
@pytest.mark.parametrize("ext,fmt", [
("flac", "flac"), (".flac", "flac"),
("mp3", "mp3"),
("m4a", "aac"), ("aac", "aac"), ("mp4", "aac"),
("ogg", "ogg"), ("oga", "ogg"),
("opus", "opus"),
("wav", "wav"), ("wave", "wav"),
("aiff", "wav"), ("aif", "wav"), # PCM → wav tier
("wma", "wma"),
("alac", "alac"),
("xyz", "unknown"), ("", "unknown"), (None, "unknown"),
])
def test_format_from_extension(ext, fmt):
assert format_from_extension(ext) == fmt
def test_audio_extensions_cover_all_known_formats():
for e in (".flac", ".mp3", ".m4a", ".ogg", ".opus", ".wav", ".aiff", ".wma"):
assert e in AUDIO_EXTENSIONS
# ── Tidal / HiFi (Tidal-backed) ────────────────────────────────────────────
@pytest.mark.parametrize("tier", ["HI_RES_LOSSLESS", "HI_RES", "hi_res", "hires", "HIRES"])
def test_tidal_hires_is_flac_24_96(tier):
aq = quality_from_tidal_tier(tier)
assert aq.format == "flac"
assert aq.bit_depth == 24
assert aq.sample_rate == 96000
@pytest.mark.parametrize("tier", ["LOSSLESS", "lossless"])
def test_tidal_lossless_is_flac_16_44(tier):
aq = quality_from_tidal_tier(tier)
assert aq.format == "flac"
assert aq.bit_depth == 16
assert aq.sample_rate == 44100
def test_tidal_high_is_lossy_aac_320():
aq = quality_from_tidal_tier("HIGH")
assert aq.format == "aac"
assert aq.bitrate == 320
assert aq.bit_depth is None # lossy: no bit depth
def test_tidal_low_is_lossy_aac_96():
aq = quality_from_tidal_tier("LOW")
assert aq.format == "aac"
assert aq.bitrate == 96
def test_tidal_unknown_tier_does_not_overclaim():
# An unrecognised tier must not masquerade as lossless.
aq = quality_from_tidal_tier("SOMETHING_NEW")
assert aq.format == "unknown"
assert aq.bit_depth is None
assert aq.sample_rate is None
# ── Qobuz (real API values) ────────────────────────────────────────────────
def test_qobuz_hires_khz_to_hz():
aq = quality_from_qobuz(96.0, 24)
assert aq.format == "flac"
assert aq.sample_rate == 96000
assert aq.bit_depth == 24
def test_qobuz_cd_quality_fractional_khz():
aq = quality_from_qobuz(44.1, 16)
assert aq.format == "flac"
assert aq.sample_rate == 44100
assert aq.bit_depth == 16
def test_qobuz_192k():
aq = quality_from_qobuz(192.0, 24)
assert aq.sample_rate == 192000
assert aq.bit_depth == 24
# ── Deezer (config code) ───────────────────────────────────────────────────
def test_deezer_flac_is_16_44():
aq = quality_from_deezer("flac")
assert aq.format == "flac"
assert aq.bit_depth == 16
assert aq.sample_rate == 44100
def test_deezer_mp3_320():
aq = quality_from_deezer("mp3_320")
assert aq.format == "mp3"
assert aq.bitrate == 320
assert aq.bit_depth is None
def test_deezer_mp3_128():
aq = quality_from_deezer("mp3_128")
assert aq.format == "mp3"
assert aq.bitrate == 128
# ── Amazon (real sampleRate preferred, tier fallback) ──────────────────────
def test_amazon_prefers_real_sample_rate():
aq = quality_from_amazon("HD", sample_rate=88200, bit_depth=24)
assert aq.format == "flac"
assert aq.sample_rate == 88200
assert aq.bit_depth == 24
def test_amazon_hd_tier_fallback():
aq = quality_from_amazon("HD")
assert aq.format == "flac"
assert aq.sample_rate == 44100
assert aq.bit_depth == 16
def test_amazon_uhd_tier_fallback():
aq = quality_from_amazon("UHD")
assert aq.format == "flac"
assert aq.bit_depth == 24
assert aq.sample_rate == 96000