Files
group_fqcd_jr/tests/unit/service/test_promotion_layout_planner.py
T

120 lines
4.1 KiB
Python

import pytest
from app.service.promotion_layout_planner import PromotionLayoutPlanner
def _draft() -> dict[str, object]:
return {
"style_code": "balanced_allocation",
"title": "测试材料",
"chapters": [
{"title": "产品基本信息", "body": "产品内容"},
{"title": "风险揭示", "body": "风险内容"},
],
}
def test_default_plan_uses_content_sensitive_layouts() -> None:
plan = PromotionLayoutPlanner.default_plan(_draft(), has_photo=True, has_chart=False)
assert plan["cover_layout"] == "cover_left_photo_right"
assert plan["page_plans"][1]["layout"] == "full_width_disclosure"
assert plan["design_profile"]["manager_layout"] == "profile_feature"
def test_strategy_heavy_material_uses_asymmetric_design_profile() -> None:
draft = {
**_draft(),
"chapters": [
{
"title": "投资范围、策略与限制",
"body": "投资策略说明" * 20,
}
],
}
plan = PromotionLayoutPlanner.default_plan(draft, has_photo=True, has_chart=True)
assert plan["design_profile"]["design_tone"] == "institutional_tech"
assert plan["design_profile"]["content_structure"] == "strategy_right_emphasis"
assert plan["design_profile"]["column_ratio"] == "40_60"
def test_low_density_chapter_uses_visual_focus_layout() -> None:
draft = {
**_draft(),
"chapters": [{"title": "投资观点", "body": "长期配置。"}],
}
plan = PromotionLayoutPlanner.default_plan(draft, has_photo=False, has_chart=False)
assert plan["page_plans"][0]["content_density"] == "low"
assert plan["page_plans"][0]["layout"] == "visual_focus"
def test_content_density_respects_existing_chart_signal() -> None:
chapter = {"title": "业绩", "body": "简要说明", "chart_index": 0}
assert PromotionLayoutPlanner.content_density(chapter) == "medium"
def test_validate_rejects_unknown_layout_and_keeps_fallback() -> None:
fallback = PromotionLayoutPlanner.default_plan(_draft(), has_photo=False, has_chart=False)
invalid = {
**fallback,
"page_plans": [
{"chapter_title": "产品基本信息", "layout": "free_coordinates"},
{"chapter_title": "风险揭示", "layout": "full_width_disclosure"},
],
}
result = PromotionLayoutPlanner._validate(invalid, _draft(), fallback)
assert result == fallback
def test_validate_preserves_chapter_titles_and_only_accepts_complete_plan() -> None:
fallback = PromotionLayoutPlanner.default_plan(_draft(), has_photo=False, has_chart=False)
value = {
"cover_layout": "cover_visual_right",
"poster_layout": "poster_balanced",
"background_theme": "geometric_grid",
"design_profile": {
"design_tone": "quiet_data",
"content_structure": "balanced_split",
"column_ratio": "50_50",
"manager_layout": "profile_compact",
"performance_layout": "metrics_first",
"background_role": "soft_paper",
},
"page_plans": [
{"chapter_title": "风险揭示", "layout": "full_width_disclosure"},
{"chapter_title": "产品基本信息", "layout": "two_columns"},
],
}
result = PromotionLayoutPlanner._validate(value, _draft(), fallback)
assert [item["chapter_title"] for item in result["page_plans"]] == [
"产品基本信息",
"风险揭示",
]
assert result["page_plans"][0]["layout"] == "two_columns"
@pytest.mark.asyncio
async def test_plan_falls_back_when_model_fails(monkeypatch: pytest.MonkeyPatch) -> None:
async def fail_resolve(*, agent_type: str, task_type: str) -> list[object]:
raise RuntimeError("模型不可用")
monkeypatch.setattr(
"app.service.promotion_layout_planner.DatabaseModelEndpointResolver.resolve",
fail_resolve,
)
result = await PromotionLayoutPlanner().plan(_draft(), has_photo=False, has_chart=False)
assert result == PromotionLayoutPlanner.default_plan(
_draft(), has_photo=False, has_chart=False
)