baodan/tests/ppt_template_asset_test.py

126 lines
3.9 KiB
Python

from pathlib import Path
import sys
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "api"))
pytest.importorskip("pptx")
from insurance.ppt.template_asset_service import (
parse_template_pptx,
resolve_template_asset,
)
@pytest.mark.parametrize(
("asset_id", "expected_slides"),
[
("builtin://single_savings.pptx", 20),
("builtin://multi_savings_comparison.pptx", 17),
("builtin://savings_iul_comprehensive.pptx", 18),
],
)
def test_builtin_ppt_templates_are_parseable(asset_id, expected_slides):
path = resolve_template_asset(asset_id)
assert path
assert Path(path).is_file()
parsed = parse_template_pptx(path)
assert parsed["slideCount"] == expected_slides
assert parsed["slidesConfig"][0]["pageType"] == "cover"
assert parsed["slidesConfig"][-1]["pageType"] == "closing"
def test_template_asset_resolver_blocks_parent_traversal():
with pytest.raises(ValueError, match="路径非法"):
resolve_template_asset("builtin://../outside.pptx")
@pytest.mark.parametrize(
("asset_id", "expect_picture"),
[
("builtin://single_savings.pptx", False),
("builtin://multi_savings_comparison.pptx", False),
("builtin://savings_iul_comprehensive.pptx", True),
],
)
def test_renderer_uses_builtin_template_frames_without_sample_copy(
tmp_path, asset_id, expect_picture
):
from insurance.ppt.scripts.fast_pptx_renderer import render_deck
from pptx import Presentation
source_path = resolve_template_asset(asset_id)
output_path = tmp_path / f"{Path(source_path).stem}-rendered.pptx"
result = render_deck({
"products": [{
"kind": "savings",
"productName": "测试储蓄计划",
"insured": {"age": 35},
"policy": {
"currency": "USD",
"annualPremium": 50000,
"payYears": 5,
},
"benefitRows": [],
"withdrawalRows": [],
}],
"company": {},
"scenarioSlides": [
{"pageType": "cover", "title": "测试模板"},
{"pageType": "closing", "title": "下一步"},
],
"templateConfig": {
"sourceTemplatePath": source_path,
"slidesConfig": [
{"pageType": "cover", "sourceSlide": 1},
{"pageType": "closing", "sourceSlide": 2},
],
},
}, str(output_path), "deepblue")
assert result["ok"] is True
assert result["slides"] == 2
assert result["rendererMode"] == "clone-edit-v2"
assert result["templateFrameMap"] == [1, 2]
assert output_path.is_file()
presentation = Presentation(str(output_path))
all_text = "\n".join(
shape.text
for slide in presentation.slides
for shape in slide.shapes
if getattr(shape, "has_text_frame", False)
)
assert "测试模板" in all_text
assert "US$500,000" not in all_text
pictures = sum(
1
for slide in presentation.slides
for shape in slide.shapes
if shape.shape_type == 13
)
assert (pictures > 0) is expect_picture
def test_renderer_rejects_uploaded_template_with_too_few_frames(tmp_path):
from insurance.ppt.scripts.fast_pptx_renderer import render_deck
source_path = resolve_template_asset("builtin://single_savings.pptx")
output_path = tmp_path / "too-many-slides.pptx"
scenario_slides = [
{"pageType": "guidance", "title": f"{index}"}
for index in range(21)
]
with pytest.raises(ValueError, match="只有 20 页"):
render_deck({
"products": [{"kind": "savings"}],
"company": {},
"scenarioSlides": scenario_slides,
"templateConfig": {
"sourceTemplatePath": source_path,
"slidesConfig": [{"pageType": "guidance"}] * 20,
},
}, str(output_path), "deepblue")