Files
tvboxzt/py/tests/test_AAZ音乐.py
T
2026-04-25 09:17:23 +08:00

220 lines
9.1 KiB
Python

import unittest
from importlib.machinery import SourceFileLoader
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[1]
MODULE = SourceFileLoader("aaz_music_spider", str(ROOT / "AAZ音乐.py")).load_module()
Spider = MODULE.Spider
HOME_HTML = """
<html><body>
<ul>
<li>
<div class="name"><a href="/m/1001.html" title="晴天">晴天</a></div>
<div class="mv"><a href="/v/mv1001">MV</a></div>
</li>
<li>
<div class="name"><a href="/m/1002.html" title="七里香">七里香</a></div>
</li>
</ul>
</body></html>
"""
SINGER_HTML = """
<html><body>
<li>
<div class="pic"><img src="/img/singer.jpg"></div>
<div class="name"><a href="/s/jay" title="周杰伦">周杰伦</a></div>
</li>
</body></html>
"""
PLAYLIST_HTML = """
<html><body>
<li>
<div class="pic"><img src="/img/playlist.jpg"></div>
<div class="name"><a href="/p/top100" title="华语热歌">华语热歌</a></div>
</li>
</body></html>
"""
ALBUM_HTML = """
<html><body>
<li>
<div class="pic"><img src="/img/album.jpg"></div>
<div class="name"><a href="/a/fantasy" title="范特西">范特西</a></div>
</li>
</body></html>
"""
MV_HTML = """
<html><body>
<li>
<div class="pic"><img src="/img/mv.jpg"></div>
<div class="name"><a href="/v/qingtianmv" title="晴天MV">晴天MV</a></div>
</li>
</body></html>
"""
SEARCH_HTML = """
<html><body>
<ul>
<li><div class="name"><a href="/m/2001.html" title="夜曲">夜曲</a></div></li>
<li><div class="name"><a href="/s/jay" title="周杰伦">周杰伦</a></div></li>
<li><div class="name"><a href="/p/jaybest" title="周董精选">周董精选</a></div></li>
<li><div class="name"><a href="/a/fantasy" title="范特西">范特西</a></div></li>
<li><div class="name"><a href="/v/nocturnemv" title="夜曲MV">夜曲MV</a></div></li>
</ul>
</body></html>
"""
SONG_DETAIL_HTML = """
<html>
<head><meta name="description" content="夜曲歌曲简介"></head>
<body>
<div class="djname"><h1>夜曲<a href="javascript:location.reload()">刷新</a></h1></div>
<div class="name"><a href="/s/jay">周杰伦</a></div>
所属专辑:<a href="/a/fantasy">范特西</a>
<img class="rotate" id="mcover" src="/img/song_detail.jpg">
<div>歌曲时长:03:45</div>
</body>
</html>
"""
FOLDER_DETAIL_HTML = """
<html><body>
<div class="title"><h1>周董精选</h1></div>
<div class="pic"><img src="/img/folder_detail.jpg"></div>
<div class="info">经典歌曲合集</div>
<ul>
<li><div class="name"><a href="/m/3001.html" title="安静">安静</a></div></li>
<li><div class="name"><a href="/m/3002.html" title="晴天">晴天</a></div></li>
</ul>
</body></html>
"""
PLAY_JSON = '{"url":"https://cdn.example.com/aaz/song2001.mp3","pic":"https://cdn.example.com/cover.jpg"}'
EMPTY_PLAY_JSON = '{"url":""}'
class TestAAZMusicSpider(unittest.TestCase):
def setUp(self):
Spider._instance = None
self.spider = Spider()
self.spider.init()
@patch.object(Spider, "fetch")
def test_home_content_returns_fixed_classes_and_song_cards(self, mock_fetch):
mock_fetch.return_value = SimpleNamespace(status_code=200, text=HOME_HTML)
result = self.spider.homeContent(False)
self.assertEqual(
[item["type_id"] for item in result["class"]],
["new", "top", "singer", "playtype", "album", "mv"],
)
self.assertEqual([item["vod_id"] for item in result["list"]], ["song:1001", "song:1002"])
self.assertEqual(result["list"][0]["vod_name"], "晴天")
self.assertEqual(result["list"][0]["vod_remarks"], "高清MV")
@patch.object(Spider, "fetch")
def test_home_video_content_reuses_home_list(self, mock_fetch):
mock_fetch.return_value = SimpleNamespace(status_code=200, text=HOME_HTML)
result = self.spider.homeVideoContent()
self.assertEqual([item["vod_id"] for item in result["list"]], ["song:1001", "song:1002"])
@patch.object(Spider, "fetch")
def test_category_content_maps_song_and_folder_types(self, mock_fetch):
mock_fetch.side_effect = [
SimpleNamespace(status_code=200, text=HOME_HTML),
SimpleNamespace(status_code=200, text=HOME_HTML),
SimpleNamespace(status_code=200, text=SINGER_HTML),
SimpleNamespace(status_code=200, text=PLAYLIST_HTML),
SimpleNamespace(status_code=200, text=ALBUM_HTML),
SimpleNamespace(status_code=200, text=MV_HTML),
]
self.assertEqual(self.spider.categoryContent("new", "1", False, {})["list"][0]["vod_id"], "song:1001")
self.assertEqual(self.spider.categoryContent("top", "1", False, {})["list"][1]["vod_id"], "song:1002")
self.assertEqual(self.spider.categoryContent("singer", "1", False, {})["list"][0]["vod_id"], "singer:jay")
self.assertEqual(self.spider.categoryContent("playtype", "1", False, {})["list"][0]["vod_id"], "playlist:top100")
self.assertEqual(self.spider.categoryContent("album", "1", False, {})["list"][0]["vod_id"], "album:fantasy")
self.assertEqual(self.spider.categoryContent("mv", "1", False, {})["list"][0]["vod_id"], "mv:qingtianmv")
def test_category_content_returns_empty_for_unknown_type(self):
self.assertEqual(
self.spider.categoryContent("bad", "1", False, {}),
{"page": 1, "limit": 0, "total": 0, "list": []},
)
@patch.object(Spider, "fetch")
def test_search_content_maps_mixed_result_types(self, mock_fetch):
mock_fetch.return_value = SimpleNamespace(status_code=200, text=SEARCH_HTML)
result = self.spider.searchContent("周杰伦", False, "1")
self.assertEqual(
[item["vod_id"] for item in result["list"]],
["song:2001", "singer:jay", "playlist:jaybest", "album:fantasy", "mv:nocturnemv"],
)
def test_search_content_returns_empty_for_blank_keyword(self):
self.assertEqual(
self.spider.searchContent("", False, "1"),
{"page": 1, "limit": 0, "total": 0, "list": []},
)
@patch.object(Spider, "fetch")
def test_detail_content_builds_song_metadata_and_single_play_url(self, mock_fetch):
mock_fetch.return_value = SimpleNamespace(status_code=200, text=SONG_DETAIL_HTML)
vod = self.spider.detailContent(["song:2001"])["list"][0]
self.assertEqual(vod["vod_name"], "夜曲")
self.assertEqual(vod["vod_pic"], "https://www.aaz.cx/img/song_detail.jpg")
self.assertEqual(vod["vod_remarks"], "周杰伦 | 范特西 | 03:45")
self.assertEqual(vod["vod_play_from"], "AAZ音乐")
self.assertEqual(vod["vod_play_url"], "播放$song:2001")
@patch.object(Spider, "fetch")
def test_detail_content_builds_folder_track_list_for_singer_playlist_album_and_mv(self, mock_fetch):
mock_fetch.side_effect = [
SimpleNamespace(status_code=200, text=FOLDER_DETAIL_HTML),
SimpleNamespace(status_code=200, text=FOLDER_DETAIL_HTML),
SimpleNamespace(status_code=200, text=FOLDER_DETAIL_HTML),
SimpleNamespace(status_code=200, text=FOLDER_DETAIL_HTML),
]
singer_vod = self.spider.detailContent(["singer:jay"])["list"][0]
playlist_vod = self.spider.detailContent(["playlist:jaybest"])["list"][0]
album_vod = self.spider.detailContent(["album:fantasy"])["list"][0]
mv_vod = self.spider.detailContent(["mv:nocturnemv"])["list"][0]
expected = "安静$song:3001#晴天$song:3002"
self.assertEqual(singer_vod["vod_play_url"], expected)
self.assertEqual(playlist_vod["vod_play_url"], expected)
self.assertEqual(album_vod["vod_play_url"], expected)
self.assertEqual(mv_vod["vod_play_url"], expected)
def test_detail_content_returns_empty_list_for_invalid_vod_id(self):
self.assertEqual(self.spider.detailContent(["bad"])["list"], [])
@patch.object(Spider, "post")
def test_player_content_resolves_song_id_to_direct_url(self, mock_post):
mock_post.return_value = SimpleNamespace(status_code=200, text=PLAY_JSON)
result = self.spider.playerContent("AAZ音乐", "song:2001", {})
self.assertEqual(result["parse"], 0)
self.assertEqual(result["url"], "https://cdn.example.com/aaz/song2001.mp3")
self.assertEqual(result["header"]["Referer"], "https://www.aaz.cx/")
self.assertEqual(mock_post.call_args.args[0], "https://www.aaz.cx/js/play.php")
self.assertEqual(mock_post.call_args.kwargs["data"], "id=2001&type=music")
self.assertEqual(
mock_post.call_args.kwargs["headers"]["Content-Type"],
"application/x-www-form-urlencoded; charset=UTF-8",
)
@patch.object(Spider, "post")
def test_player_content_returns_empty_url_for_invalid_or_empty_payload(self, mock_post):
mock_post.return_value = SimpleNamespace(status_code=200, text=EMPTY_PLAY_JSON)
self.assertEqual(self.spider.playerContent("AAZ音乐", "song:2001", {})["url"], "")
self.assertEqual(self.spider.playerContent("AAZ音乐", "bad", {})["url"], "")
if __name__ == "__main__":
unittest.main()