d2a3e64b89
refactor: as the config module changed test: add test for config test: add test for local fetcher and local enrichers test: add test for manual insertion fix: some random bugs left by the last commit
124 lines
3.9 KiB
Python
124 lines
3.9 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from pathlib import Path
|
|
|
|
from lrx_cli.config import AppConfig
|
|
from lrx_cli.enrichers.audio_tag import AudioTagEnricher
|
|
from lrx_cli.enrichers.file_name import FileNameEnricher
|
|
from lrx_cli.models import CacheStatus, TrackMeta
|
|
from lrx_cli.fetchers.local import LocalFetcher
|
|
|
|
_GENERAL = AppConfig().general
|
|
|
|
|
|
def _local_track(path: Path) -> TrackMeta:
|
|
return TrackMeta(url=f"file://{path}")
|
|
|
|
|
|
def test_local_fetcher_unavailable_for_non_local_track():
|
|
fetcher = LocalFetcher(_GENERAL)
|
|
assert not fetcher.is_available(TrackMeta(title="Song", artist="Artist"))
|
|
|
|
|
|
def test_local_fetcher_available_for_local_track(tmp_path):
|
|
fetcher = LocalFetcher(_GENERAL)
|
|
assert fetcher.is_available(_local_track(tmp_path / "song.flac"))
|
|
|
|
|
|
def test_local_fetcher_returns_empty_for_non_file_url():
|
|
fetcher = LocalFetcher(_GENERAL)
|
|
track = TrackMeta(url="https://example.com/song.mp3")
|
|
result = asyncio.run(fetcher.fetch(track))
|
|
assert result.synced is None and result.unsynced is None
|
|
|
|
|
|
def test_local_fetcher_reads_synced_sidecar(tmp_path):
|
|
audio = tmp_path / "song.flac"
|
|
lrc = audio.with_suffix(".lrc")
|
|
lrc.write_text("[00:01.00]Hello\n[00:03.00]World\n")
|
|
|
|
fetcher = LocalFetcher(_GENERAL)
|
|
result = asyncio.run(fetcher.fetch(_local_track(audio)))
|
|
|
|
assert result.synced is not None
|
|
assert result.synced.status == CacheStatus.SUCCESS_SYNCED
|
|
assert result.synced.source is not None
|
|
assert "sidecar" in result.synced.source
|
|
|
|
|
|
def test_local_fetcher_reads_unsynced_sidecar(tmp_path):
|
|
audio = tmp_path / "song.flac"
|
|
lrc = audio.with_suffix(".lrc")
|
|
lrc.write_text("Hello\nWorld\n")
|
|
|
|
fetcher = LocalFetcher(_GENERAL)
|
|
result = asyncio.run(fetcher.fetch(_local_track(audio)))
|
|
|
|
assert result.unsynced is not None
|
|
assert result.synced is None
|
|
|
|
|
|
def test_local_fetcher_empty_sidecar_ignored(tmp_path):
|
|
audio = tmp_path / "song.flac"
|
|
(audio.with_suffix(".lrc")).write_text(" ")
|
|
|
|
fetcher = LocalFetcher(_GENERAL)
|
|
result = asyncio.run(fetcher.fetch(_local_track(audio)))
|
|
|
|
assert result.synced is None and result.unsynced is None
|
|
|
|
|
|
def _enrich(path: str, **existing) -> dict | None:
|
|
enricher = FileNameEnricher()
|
|
track = TrackMeta(url=f"file://{path}", **existing)
|
|
return asyncio.run(enricher.enrich(track))
|
|
|
|
|
|
def test_filename_enricher_artist_title_split(tmp_path):
|
|
result = _enrich(str(tmp_path / "Utada Hikaru - First Love.flac"))
|
|
assert result == {
|
|
"artist": "Utada Hikaru",
|
|
"title": "First Love",
|
|
"album": tmp_path.name,
|
|
}
|
|
|
|
|
|
def test_filename_enricher_track_number_prefix(tmp_path):
|
|
# "01. Title" — no " - " separator, regex strips leading "01. "
|
|
result = _enrich(str(tmp_path / "01. First Love.flac"))
|
|
assert result and result.get("title") == "First Love"
|
|
assert "artist" not in result
|
|
|
|
|
|
def test_filename_enricher_title_only(tmp_path):
|
|
result = _enrich(str(tmp_path / "First Love.flac"))
|
|
assert result and result.get("title") == "First Love"
|
|
|
|
|
|
def test_filename_enricher_does_not_overwrite_existing_fields(tmp_path):
|
|
result = _enrich(
|
|
str(tmp_path / "Artist - Title.flac"),
|
|
artist="Existing Artist",
|
|
title="Existing Title",
|
|
)
|
|
assert result is None or ("artist" not in result and "title" not in result)
|
|
|
|
|
|
def test_filename_enricher_non_local_returns_none():
|
|
enricher = FileNameEnricher()
|
|
track = TrackMeta(title="Song", artist="Artist")
|
|
assert asyncio.run(enricher.enrich(track)) is None
|
|
|
|
|
|
def test_audio_tag_enricher_non_local_returns_none():
|
|
enricher = AudioTagEnricher()
|
|
track = TrackMeta(title="Song", artist="Artist")
|
|
assert asyncio.run(enricher.enrich(track)) is None
|
|
|
|
|
|
def test_audio_tag_enricher_missing_file_returns_none(tmp_path):
|
|
enricher = AudioTagEnricher()
|
|
track = _local_track(tmp_path / "nonexistent.flac")
|
|
assert asyncio.run(enricher.enrich(track)) is None
|