diff --git a/test_suite_enricher.py b/test_suite_enricher.py index 71bc588..e61121b 100755 --- a/test_suite_enricher.py +++ b/test_suite_enricher.py @@ -188,6 +188,140 @@ def test_extract_hints_multi_disc() -> str: return f"disc numbers detected: {disc_nums}" +# --------------------------------------------------------------------------- +# Vertical tracklist parser Tests +# --------------------------------------------------------------------------- + +def test_vertical_tracklist_basic() -> str: + from hint_extractor import _normalize_vertical_tracklist + text = "1\nKatka dovádí\n3:22\n2\nZáludná\n2:15\n3\nPolka pro trubku\n4:01" + result = _normalize_vertical_tracklist(text) + assert result is not None, "should recognize vertical format" + assert "1. Katka" in result, f"got: {result!r}" + assert "2. Záludná" in result, f"got: {result!r}" + return f"normalized: {result[:60]!r}" + + +def test_vertical_tracklist_without_duration() -> str: + from hint_extractor import _normalize_vertical_tracklist + text = "1\nFirst Song\n2\nSecond Song\n3\nThird Song" + result = _normalize_vertical_tracklist(text) + assert result is not None, "should work without durations" + assert "1. First Song" in result, f"got: {result!r}" + return f"no-duration OK: {result[:60]!r}" + + +def test_vertical_tracklist_not_triggered_for_normal() -> str: + from hint_extractor import _normalize_vertical_tracklist + text = "1. Dancing Queen\n2. Waterloo\n3. Fernando" + result = _normalize_vertical_tracklist(text) + assert result is None, f"should return None for normal format, got: {result!r}" + return "correctly returns None for standard format" + + +# --------------------------------------------------------------------------- +# Single-CD disc handling Tests +# --------------------------------------------------------------------------- + +def test_single_cd_tracklist_match() -> str: + """Track-Nummer-Match darf nicht disc_num erfordern (Single-CD hat disc=None).""" + from hint_extractor import _parse_tracklist + from models import TrackHints, AlbumHints, AlbumScan + from pathlib import Path + import tempfile + + with tempfile.TemporaryDirectory() as tmpdir: + root = Path(tmpdir) / "Tufaranka_-_Katka_dovadi" + root.mkdir() + (root / "01_-_Tufaranka_-_AudioTrack_01.mp3").write_bytes(b"\x00" * 100) + (root / "tracklist.txt").write_text("1\nKatka dovádí\n3:22\n2\nZáludná\n2:15\n3\nPolka\n4:01") + + from scanner import scan_album + from hint_extractor import extract_hints + scan = scan_album(root) + hints = extract_hints(scan, use_ocr=False) + track = hints.tracks[0] + assert track.title == "Katka dovádí", f"expected tracklist title, got: {track.title!r}" + return f"single-CD match OK: title={track.title!r}" + + +# --------------------------------------------------------------------------- +# Genre normalization Tests +# --------------------------------------------------------------------------- + +def test_genre_normalize_german() -> str: + from metadata_resolver import normalize_genre + assert normalize_genre("volksmusik") == "Folk", "volksmusik → Folk" + assert normalize_genre("klassik") == "Classical", "klassik → Classical" + assert normalize_genre("marschmusik") == "March", "marschmusik → March" + return "German genres normalized correctly" + + +def test_genre_normalize_english_variants() -> str: + from metadata_resolver import normalize_genre + assert normalize_genre("rhythm and blues") == "R&B" + assert normalize_genre("rock and roll") == "Rock 'n' Roll" + return "English variants normalized correctly" + + +def test_genre_normalize_titlecase() -> str: + from metadata_resolver import normalize_genre + assert normalize_genre("JAZZ") == "Jazz", f"got: {normalize_genre('JAZZ')!r}" + assert normalize_genre("folk") == "Folk", f"got: {normalize_genre('folk')!r}" + assert normalize_genre("Big Band") == "Big Band" # unchanged + return "Titlecase normalization OK" + + +# --------------------------------------------------------------------------- +# _is_classical() Tests +# --------------------------------------------------------------------------- + +def test_is_classical_by_genre() -> str: + from executor import _is_classical + assert _is_classical("Gardiner", "Bach", "Classical"), "Classical genre should trigger" + assert _is_classical("Herreweghe", "Handel", "Baroque"), "Baroque should trigger" + return "genre-based detection OK" + + +def test_is_classical_by_composer() -> str: + from executor import _is_classical + assert _is_classical("Gardiner", "Bach", ""), "Bach as track_artist should trigger" + assert _is_classical("Hurford", "beethoven", ""), "beethoven should trigger" + return "composer-name detection OK" + + +def test_is_classical_false_for_pop() -> str: + from executor import _is_classical + assert not _is_classical("Trini Lopez", "Trini Lopez", "Pop"), "same artist = not classical" + assert not _is_classical("ABBA", "ABBA", "Pop"), "ABBA is not classical" + assert not _is_classical("Trini Lopez", "", "R&B"), "empty track_artist = not classical" + return "pop albums correctly not classical" + + +def test_is_classical_false_for_folk() -> str: + from executor import _is_classical + assert not _is_classical("Tufaranka", "Tufaranka", "Folk"), "Folk is not classical" + return "Folk correctly not classical" + + +# --------------------------------------------------------------------------- +# cover normalize Tests +# --------------------------------------------------------------------------- + +def test_normalize_cover_renames_front_jpg() -> str: + from cover_handler import normalize_cover_to_folder_jpg + import tempfile, shutil + with tempfile.TemporaryDirectory() as tmpdir: + root = Path(tmpdir) + front = root / "Front.jpg" + front.write_bytes(b"\xff\xd8" + b"\x00" * 200) + result = normalize_cover_to_folder_jpg(front) + assert result.name == "folder.jpg", f"expected folder.jpg, got {result.name!r}" + assert (root / "folder.jpg").exists(), "folder.jpg should exist" + assert not front.exists(), "Front.jpg should be gone" + return "Front.jpg → folder.jpg rename OK" + + # --------------------------------------------------------------------------- # executor Tests # --------------------------------------------------------------------------- @@ -252,6 +386,19 @@ def main() -> None: ("UNIT_15_proposed_filename_single_disc", test_proposed_filename_single_disc), ("UNIT_16_proposed_filename_multi_disc", test_proposed_filename_multi_disc), ("UNIT_17_proposed_filename_sanitizes_chars", test_proposed_filename_sanitizes_chars), + # Neue Tests + ("UNIT_18_vertical_tracklist_basic", test_vertical_tracklist_basic), + ("UNIT_19_vertical_tracklist_no_duration", test_vertical_tracklist_without_duration), + ("UNIT_20_vertical_tracklist_no_false_pos", test_vertical_tracklist_not_triggered_for_normal), + ("UNIT_21_single_cd_tracklist_match", test_single_cd_tracklist_match), + ("UNIT_22_genre_normalize_german", test_genre_normalize_german), + ("UNIT_23_genre_normalize_english", test_genre_normalize_english_variants), + ("UNIT_24_genre_normalize_titlecase", test_genre_normalize_titlecase), + ("UNIT_25_is_classical_by_genre", test_is_classical_by_genre), + ("UNIT_26_is_classical_by_composer", test_is_classical_by_composer), + ("UNIT_27_is_classical_false_pop", test_is_classical_false_for_pop), + ("UNIT_28_is_classical_false_folk", test_is_classical_false_for_folk), + ("UNIT_29_normalize_cover_renames", test_normalize_cover_renames_front_jpg), ] for test_id, fn in cases: