from pathlib import Path from unittest.mock import patch import pytest from app.domain.metainfo import MetaInfo, MetaInfoPath, find_metainfo from app.schemas.types import MediaType @pytest.mark.parametrize( ("title", "source", "media_id"), [ ("葬送的芙莉莲 {[bangumiid=400602;type=tv;s=1]}", "bangumi", "400602"), ("Frieren {[anilistid=154587;type=tv;s=1]}", "anilist", "154587"), ("Frieren [anilist=154587] S01E01", "anilist", "154587"), ], ) def test_find_metainfo_supports_anime_source_ids( title: str, source: str, media_id: str, ) -> None: """显式动画来源标签应提取统一来源ID并从标题中移除。""" parsed_title, metainfo = find_metainfo(title) assert metainfo["media_source"] == source assert metainfo["media_id"] == media_id assert f"{source}id=" not in parsed_title assert f"{source}=" not in parsed_title def test_metainfo_custom_words_support_anilist_id() -> None: """自定义识别词替换结果中的AniList ID应进入统一元数据字段。""" meta = MetaInfo( "Sousou no Frieren 01", custom_words=[ "Sousou no Frieren => Frieren {[anilistid=154587;type=tv;s=1]}" ], ) assert meta.media_source == "anilist" assert meta.media_id == "154587" assert meta.type == MediaType.TV assert meta.begin_season == 1 def test_metainfo_path_inherits_bangumi_id_from_parent() -> None: """文件路径识别应从父目录继承Bangumi来源ID。""" meta = MetaInfoPath( Path("/anime/葬送的芙莉莲 [bangumi=400602]/Frieren.S01E01.mkv") ) assert meta.media_source == "bangumi" assert meta.media_id == "400602" assert meta.begin_season == 1 assert meta.begin_episode == 1 def test_extended_ids_fall_back_when_installed_rust_is_old() -> None: """当前Rust扩展缺少新字段时应直接使用Python解析器。""" with patch( "app.adapters.system.rust.supports_extended_media_ids", return_value=False, ), patch( "app.adapters.system.rust.find_metainfo", side_effect=AssertionError("旧Rust扩展不应处理扩展来源ID"), ): _, metainfo = find_metainfo("Frieren [anilist=154587]") assert metainfo["media_source"] == "anilist" assert metainfo["media_id"] == "154587" @pytest.mark.parametrize( "title", [ "Movie {[tmdbid=0;type=movies]}", "Movie [tmdbid=0]", "Anime [anilist=0]", ], ) def test_python_metainfo_rejects_zero_identity_and_removes_tag(title: str) -> None: """Python 标签解析器应移除零值标签,但不得生成媒体身份。""" with patch("app.adapters.system.rust.find_metainfo", return_value=None): parsed_title, metainfo = find_metainfo(title) assert metainfo["media_source"] is None assert metainfo["media_id"] is None assert "=0" not in parsed_title def test_metainfo_normalizes_zero_identity_from_old_rust_extension() -> None: """旧 Rust 扩展返回零值身份时,主程序边界仍应将统一对清空。""" rust_result = { "title": "Movie", "metainfo": { "media_source": "themoviedb", "media_id": "0", "tmdbid": 0, }, } with patch( "app.adapters.system.rust.find_metainfo", return_value=rust_result, ): parsed_title, metainfo = find_metainfo("Movie [tmdbid=0]") assert parsed_title == "Movie" assert metainfo["media_source"] is None assert metainfo["media_id"] is None assert "tmdbid" not in metainfo