"""平台规则引擎单元测试""" import pytest # --------------------------------------------------------------------------- # PlatformRuleEngine 测试 # --------------------------------------------------------------------------- class TestPlatformRuleEngine: @pytest.fixture def engine(self): from app.services.distribution.platform_rules import PlatformRuleEngine return PlatformRuleEngine() def test_get_platforms_returns_all(self, engine): """返回所有平台""" platforms = engine.get_platforms() assert len(platforms) >= 6 ids = {p["id"] for p in platforms} # 验证包含核心平台 assert "wechat" in ids assert "zhihu" in ids assert "xiaohongshu" in ids def test_get_platforms_fields(self, engine): """每个平台包含必要字段""" platforms = engine.get_platforms() required_fields = {"id", "name", "max_title_length", "max_content_length", "min_content_length"} for p in platforms: assert required_fields.issubset(p.keys()), f"Platform {p.get('id')} missing fields: {required_fields - p.keys()}" def test_validate_title_too_long(self, engine): """标题超长返回 high severity issue""" # 微信公众号标题上限 22 字 title = "这个标题非常非常非常非常非常非常非常长超过了微信的限制" content = "这是正文内容,字数足够满足最低要求。" * 30 result = engine.validate_content(content, title, "wechat") assert result["is_valid"] is False issues = result["issues"] high_issues = [i for i in issues if i["severity"] == "high"] assert any("标题" in i["message"] for i in high_issues) def test_validate_content_too_short(self, engine): """内容过短返回 medium severity issue""" title = "正常标题" content = "短内容" # 远少于 300 字最低要求 result = engine.validate_content(content, title, "wechat") issues = result["issues"] assert any("内容长度" in i["message"] for i in issues) def test_validate_valid_content(self, engine): """合规内容 score >= 90""" title = "合规标题测试" # 长度在 22 字以内 content = "这是符合要求的内容。" * 50 # 足够长度,无违规 result = engine.validate_content(content, title, "wechat") assert result["score"] >= 90 def test_validate_unknown_platform(self, engine): """未知平台返回 is_valid=False""" result = engine.validate_content("content", "title", "unknown_platform_xyz") assert result["is_valid"] is False assert result["score"] == 0 def test_validate_wechat_external_link(self, engine): """微信正文包含外部链接返回 high severity issue""" title = "标题" content = "正文内容 " * 50 + " 点击 https://example.com/test 查看" result = engine.validate_content(content, title, "wechat") issues = result["issues"] assert any("外部链接" in i["message"] for i in issues) def test_validate_wechat_consecutive_symbols_in_title(self, engine): """微信标题含连续特殊符号返回 medium issue""" title = "惊喜!!!三连" content = "正文内容,满足最低字数要求。" * 30 result = engine.validate_content(content, title, "wechat") issues = result["issues"] assert any("连续特殊符号" in i["message"] for i in issues) def test_get_optimization_tips_returns_list(self, engine): """get_optimization_tips 返回非空列表""" tips = engine.get_optimization_tips("wechat") assert isinstance(tips, list) assert len(tips) > 0 def test_get_optimization_tips_unknown_platform(self, engine): """未知平台返回空列表""" tips = engine.get_optimization_tips("unknown_xyz") assert tips == [] # --- 标签验证测试 --- def test_validate_tags_within_range(self, engine): """标签数量在范围内验证通过""" title = "合规标题测试" content = "这是符合要求的内容。" * 50 result = engine.validate_content(content, title, "wechat", tags=["标签1", "标签2", "标签3"]) tag_issues = [i for i in result["issues"] if i.get("category") == "tag_count"] assert len(tag_issues) == 0 def test_validate_tags_below_minimum(self, engine): """标签数量低于最低要求返回 medium issue""" title = "合规标题测试" content = "这是符合要求的内容。" * 50 result = engine.validate_content(content, title, "wechat", tags=[]) tag_issues = [i for i in result["issues"] if i.get("category") == "tag_count"] assert len(tag_issues) > 0 assert tag_issues[0]["severity"] == "medium" assert "低于最低要求" in tag_issues[0]["message"] def test_validate_tags_exceed_maximum(self, engine): """标签数量超过限制返回 high issue""" title = "合规标题测试" content = "这是符合要求的内容。" * 50 # 微信 max_tags=10,传入 15 个 many_tags = [f"标签{i}" for i in range(15)] result = engine.validate_content(content, title, "wechat", tags=many_tags) tag_issues = [i for i in result["issues"] if i.get("category") == "tag_count"] assert len(tag_issues) > 0 assert tag_issues[0]["severity"] == "high" assert "超过限制" in tag_issues[0]["message"] def test_validate_tags_as_comma_separated_string(self, engine): """标签为逗号分隔字符串时正确解析""" title = "合规标题测试" content = "这是符合要求的内容。" * 50 result = engine.validate_content(content, title, "wechat", tags="标签1,标签2,标签3") tag_issues = [i for i in result["issues"] if i.get("category") == "tag_count"] assert len(tag_issues) == 0 def test_validate_no_tags_treated_as_zero(self, engine): """无标签时视为 0 个标签,低于 min_tags 时触发 issue""" title = "合规标题测试" content = "这是符合要求的内容。" * 50 result = engine.validate_content(content, title, "wechat", tags=None) tag_issues = [i for i in result["issues"] if i.get("category") == "tag_count"] # 微信 min_tags=3,tags=None 时 tag_count=0 < 3,触发 medium issue assert len(tag_issues) > 0 assert tag_issues[0]["severity"] == "medium" # --------------------------------------------------------------------------- # ContentFormatter 测试 # --------------------------------------------------------------------------- class TestContentFormatter: @pytest.fixture def formatter(self): from app.services.distribution.formatter import ContentFormatter return ContentFormatter() def test_formatter_xiaohongshu_strips_markdown(self, formatter): """小红书格式:移除 Markdown 标记""" md_content = "# 标题\n\n**加粗内容**\n\n[链接文本](http://example.com)" result = formatter.format_for_platform(md_content, "xiaohongshu") assert "**" not in result assert "#" not in result or result.strip().startswith("#") is False assert "http://example.com" not in result def test_formatter_wechat_removes_links(self, formatter): """微信格式:去除非公众号外链,保留链接文本""" content = "请访问 [示例网站](https://external-site.com/page) 了解详情" result = formatter.format_for_platform(content, "wechat") # 外部链接被移除,但文本保留 assert "https://external-site.com" not in result assert "示例网站" in result def test_formatter_wechat_converts_headers(self, formatter): """微信格式:Markdown 标题转 HTML""" content = "## 二级标题\n\n正文内容" result = formatter.format_for_platform(content, "wechat") assert "

" in result assert "二级标题" in result def test_formatter_zhihu_keeps_markdown(self, formatter): """知乎格式:保留 Markdown 结构""" content = "## 知乎标题\n\n**加粗内容**\n\n`代码示例`" result = formatter.format_for_platform(content, "zhihu") # 知乎支持 Markdown,应保留 assert "**加粗内容**" in result def test_formatter_default_strips_markdown(self, formatter): """默认格式:清理 Markdown 为纯文本""" content = "# 标题\n\n**加粗**\n\n[链接](http://test.com)" result = formatter.format_for_platform(content, "unknown_platform") assert "#" not in result.split("\n")[0] # 标题标记被移除 assert "**" not in result assert "http://test.com" not in result def test_formatter_xiaohongshu_tags_moved_to_end(self, formatter): """小红书格式:话题标签移到文末""" content = "正文内容 #话题1 更多内容 #话题2" result = formatter.format_for_platform(content, "xiaohongshu") lines = result.strip().split("\n") last_line = lines[-1] # 最后一行包含标签 assert "#话题1" in last_line or "#话题2" in last_line def test_formatter_wechat_bold_to_strong(self, formatter): """微信格式:**加粗** 转为 """ content = "这是**重要内容**需要加粗" result = formatter.format_for_platform(content, "wechat") assert "重要内容" in result