"""Tests for LinkParser module Tests URL parsing for various platforms: - Bilibili video URLs - Bilibili article URLs - Zhihu answer URLs - Zhihu zhuanlan URLs - Short link resolution (b23.tv) - Unknown URL handling """ import pytest from unittest.mock import patch, MagicMock class TestLinkParserBilibiliVideo: """Tests for Bilibili video URL parsing""" def test_parse_bilibili_video_url_returns_correct_parsed_link(self): """Test 1: 解析B站视频URL返回正确的 ParsedLink (platform=bilibili, type=video, id=BVxxx)""" from kb_workflow.pipeline.link_parser import LinkParser, ParsedLink parser = LinkParser() result = parser.parse("https://www.bilibili.com/video/BV1GJ411x7Qw") assert result is not None assert result.platform == "bilibili" assert result.content_type == "video" assert result.content_id == "BV1GJ411x7Qw" assert result.original_url == "https://www.bilibili.com/video/BV1GJ411x7Qw" def test_parse_bilibili_video_url_without_www(self): """B站视频URL不带www也能正确解析""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("https://bilibili.com/video/BV1GJ411x7Qw") assert result is not None assert result.platform == "bilibili" assert result.content_type == "video" assert result.content_id == "BV1GJ411x7Qw" def test_parse_bilibili_video_url_with_http(self): """B站视频URL使用http也能正确解析""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("http://www.bilibili.com/video/BV1GJ411x7Qw") assert result is not None assert result.platform == "bilibili" assert result.content_type == "video" class TestLinkParserBilibiliArticle: """Tests for Bilibili article URL parsing""" def test_parse_bilibili_article_url_returns_correct_parsed_link(self): """Test 2: 解析B站专栏URL返回正确的 ParsedLink (platform=bilibili, type=article, id=cvxxx)""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("https://www.bilibili.com/read/cv12345678") assert result is not None assert result.platform == "bilibili" assert result.content_type == "article" assert result.content_id == "cv12345678" def test_parse_bilibili_article_url_with_article_prefix(self): """B站专栏URL使用article前缀也能正确解析""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("https://www.bilibili.com/article/cv12345678") assert result is not None assert result.platform == "bilibili" assert result.content_type == "article" assert result.content_id == "cv12345678" class TestLinkParserZhihuAnswer: """Tests for Zhihu answer URL parsing""" def test_parse_zhihu_answer_url_returns_correct_parsed_link(self): """Test 3: 解析知乎问答URL返回正确的 ParsedLink (platform=zhihu, type=answer, id=xxx)""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("https://www.zhihu.com/question/12345678/answer/87654321") assert result is not None assert result.platform == "zhihu" assert result.content_type == "answer" assert result.content_id == "87654321" def test_parse_zhihu_answer_url_without_www(self): """知乎问答URL不带www也能正确解析""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("https://zhihu.com/question/12345678/answer/87654321") assert result is not None assert result.platform == "zhihu" assert result.content_type == "answer" class TestLinkParserZhihuZhuanlan: """Tests for Zhihu zhuanlan URL parsing""" def test_parse_zhihu_zhuanlan_url_returns_correct_parsed_link(self): """Test 4: 解析知乎专栏URL返回正确的 ParsedLink (platform=zhihu, type=zhuanlan, id=xxx)""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("https://zhuanlan.zhihu.com/p/12345678") assert result is not None assert result.platform == "zhihu" assert result.content_type == "zhuanlan" assert result.content_id == "12345678" class TestLinkParserShortLink: """Tests for short link resolution""" @patch("kb_workflow.pipeline.link_parser.requests.head") def test_parse_b23tv_shortlink_resolves_to_real_url(self, mock_head): """Test 5: 解析b23.tv短链返回解析后的真实URL""" from kb_workflow.pipeline.link_parser import LinkParser # Mock the redirect response mock_response = MagicMock() mock_response.status_code = 200 mock_response.url = "https://www.bilibili.com/video/BV1GJ411x7Qw" mock_head.return_value = mock_response parser = LinkParser() result = parser.parse("https://b23.tv/abc123") assert result is not None assert result.platform == "bilibili" assert result.content_type == "video" assert result.content_id == "BV1GJ411x7Qw" assert result.resolved_url == "https://www.bilibili.com/video/BV1GJ411x7Qw" @patch("kb_workflow.pipeline.link_parser.requests.head") def test_shortlink_resolution_uses_allow_redirects(self, mock_head): """短链解析应该使用 allow_redirects=True""" from kb_workflow.pipeline.link_parser import LinkParser mock_response = MagicMock() mock_response.status_code = 200 mock_response.url = "https://www.bilibili.com/video/BV1GJ411x7Qw" mock_head.return_value = mock_response parser = LinkParser() parser.parse("https://b23.tv/abc123") mock_head.assert_called_once() call_kwargs = mock_head.call_args[1] assert call_kwargs.get("allow_redirects") is True class TestLinkParserUnknownURL: """Tests for unknown URL handling""" def test_parse_unknown_url_returns_none(self): """Test 6: 无法识别的URL返回None(不抛异常)""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("https://www.youtube.com/watch?v=dQw4w9WgXcQ") assert result is None def test_parse_invalid_url_returns_none(self): """无效URL返回None""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("not a valid url") assert result is None def test_parse_empty_string_returns_none(self): """空字符串返回None""" from kb_workflow.pipeline.link_parser import LinkParser parser = LinkParser() result = parser.parse("") assert result is None class TestParsedLink: """Tests for ParsedLink dataclass""" def test_parsed_link_has_all_required_fields(self): """ParsedLink 应包含所有必需字段""" from kb_workflow.pipeline.link_parser import ParsedLink link = ParsedLink( platform="bilibili", content_type="video", content_id="BV1GJ411x7Qw", original_url="https://www.bilibili.com/video/BV1GJ411x7Qw", resolved_url="https://www.bilibili.com/video/BV1GJ411x7Qw" ) assert link.platform == "bilibili" assert link.content_type == "video" assert link.content_id == "BV1GJ411x7Qw" assert link.original_url == "https://www.bilibili.com/video/BV1GJ411x7Qw" assert link.resolved_url == "https://www.bilibili.com/video/BV1GJ411x7Qw" def test_parsed_link_resolved_url_defaults_to_original(self): """ParsedLink 的 resolved_url 默认等于 original_url""" from kb_workflow.pipeline.link_parser import ParsedLink link = ParsedLink( platform="bilibili", content_type="video", content_id="BV1GJ411x7Qw", original_url="https://www.bilibili.com/video/BV1GJ411x7Qw" ) assert link.resolved_url == link.original_url