geo/backend/tests/test_services/test_platform_rules.py

222 lines
9.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""平台规则引擎单元测试"""
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=3tags=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 "<h2>" 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):
"""微信格式:**加粗** 转为 <strong>"""
content = "这是**重要内容**需要加粗"
result = formatter.format_for_platform(content, "wechat")
assert "<strong>重要内容</strong>" in result