1
0
Files
PPTX/tests/conftest.py
lanyuanxiaoyao 98098dc911 feat: 实现模板库metadata和跨域字体引用系统
实现了统一的metadata结构和字体作用域系统,支持文档和模板库之间的单向字体引用。

主要变更:
- 模板库必须包含metadata字段(包括size、fonts、fonts_default)
- 实现文档和模板库的size一致性校验
- 实现字体作用域系统(文档可引用模板库字体,反之不可)
- 实现跨域循环引用检测
- 实现fonts_default级联规则(模板库→文档→系统默认)
- 添加错误代码常量(SIZE_MISMATCH、FONT_NOT_FOUND等)
- 更新文档和开发者指南

测试覆盖:
- 新增33个测试(单元测试20个,集成测试13个)
- 所有457个测试通过

Breaking Changes:
- 模板库文件必须包含metadata字段
- 模板库metadata.size为必填字段
- 文档和模板库的size必须一致

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-05 18:12:05 +08:00

379 lines
7.9 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.
"""
pytest 配置文件 - 共享 fixtures
"""
import sys
from pathlib import Path
from PIL import Image
import pytest
# 添加项目根目录到 sys.path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
# ============= 基础 Fixtures =============
@pytest.fixture
def temp_dir(tmp_path):
"""临时目录 fixture使用 pytest 内置 tmp_path"""
return tmp_path
@pytest.fixture
def project_root_dir():
"""项目根目录"""
return Path(__file__).parent.parent
# ============= YAML 文件 Fixtures =============
MINIMAL_YAML = """metadata:
size: "16:9"
slides:
- background:
color: "#ffffff"
elements:
- type: text
box: [1, 1, 8, 1]
content: "Hello, World!"
font:
size: 44
bold: true
color: "#333333"
align: center
"""
@pytest.fixture
def sample_yaml(temp_dir):
"""创建最小测试 YAML 文件"""
yaml_path = temp_dir / "test.yaml"
yaml_path.write_text(MINIMAL_YAML, encoding="utf-8")
return yaml_path
# ============= 图片 Fixtures =============
@pytest.fixture
def sample_image(temp_dir):
"""创建测试图片文件(使用 Pillow 生成简单的 PNG"""
img_path = temp_dir / "test_image.png"
# 创建一个简单的红色图片
img = Image.new("RGB", (100, 100), color="red")
img.save(img_path, "PNG")
return img_path
# ============= 模板 Fixtures =============
TEMPLATE_YAML = """vars:
- name: title
required: true
- name: subtitle
required: false
default: ""
elements:
- type: text
box: [1, 2, 8, 1]
content: "{title}"
font:
size: 44
bold: true
align: center
- type: text
box: [1, 3.5, 8, 0.5]
content: "{subtitle}"
visible: "{subtitle != ''}"
font:
size: 24
align: center
"""
TEMPLATE_LIBRARY_YAML = """metadata:
size: "16:9"
templates:
title-slide:
vars:
- name: title
required: true
- name: subtitle
required: false
default: ""
elements:
- type: text
box: [1, 2, 8, 1]
content: "{title}"
font:
size: 44
bold: true
align: center
- type: text
box: [1, 3.5, 8, 0.5]
content: "{subtitle}"
visible: "{subtitle != ''}"
font:
size: 24
align: center
"""
@pytest.fixture
def sample_template(temp_dir):
"""创建测试模板库文件"""
template_file = temp_dir / "templates.yaml"
template_file.write_text(TEMPLATE_LIBRARY_YAML, encoding="utf-8")
return template_file
@pytest.fixture
def mock_template_class():
"""Mock Template 类,用于单元测试"""
from unittest.mock import patch
with patch("core.presentation.Template") as mock_class:
yield mock_class
# ============= PPTX 验证 Fixture =============
@pytest.fixture
def pptx_validator():
"""PPTX 文件验证器实例"""
from tests.conftest_pptx import PptxFileValidator
return PptxFileValidator()
# ============= 测试数据目录 Fixture =============
@pytest.fixture
def fixtures_dir():
"""测试数据目录路径"""
return Path(__file__).parent / "fixtures"
# ============= 额外的边界情况 Fixtures =============
@pytest.fixture
def edge_case_yaml_files(fixtures_dir):
"""所有边界情况 YAML 文件的路径"""
edge_cases_dir = fixtures_dir / "yaml_samples" / "edge_cases"
if edge_cases_dir.exists():
return list(edge_cases_dir.glob("*.yaml"))
return []
@pytest.fixture(params=["16:9", "4:3"])
def slide_size(request):
"""参数化的幻灯片尺寸"""
return request.param
@pytest.fixture
def complex_template(temp_dir):
"""创建复杂模板(包含多个变量和条件)"""
template_content = """
templates:
complex-slide:
vars:
- name: title
required: true
- name: subtitle
required: false
default: ""
- name: author
required: false
default: ""
- name: date
required: false
default: ""
elements:
- type: shape
box: [0, 0, 10, 5.625]
shape: rectangle
fill: "#2c3e50"
- type: text
box: [1, 1.5, 8, 1]
content: "{title}"
font:
size: 44
bold: true
color: "#ffffff"
align: center
- type: text
box: [1, 2.8, 8, 0.6]
content: "{subtitle}"
visible: "{subtitle != ''}"
font:
size: 24
color: "#ecf0f1"
align: center
- type: text
box: [1, 4, 8, 0.5]
content: "{author}"
visible: "{author != ''}"
font:
size: 18
color: "#bdc3c7"
align: center
- type: text
box: [1, 4.8, 8, 0.4]
content: "{date}"
visible: "{date != ''}"
font:
size: 14
color: "#95a5a6"
align: center
"""
template_file = temp_dir / "complex_templates.yaml"
template_file.write_text(template_content)
return template_file
@pytest.fixture
def yaml_with_all_elements(temp_dir):
"""创建包含所有元素类型的 YAML"""
yaml_content = """
metadata:
size: "16:9"
slides:
- background:
color: "#ffffff"
elements:
- type: text
box: [1, 1, 3, 0.5]
content: "Text Element"
font:
size: 24
color: "#333333"
align: left
- type: text
box: [1, 1.8, 3, 0.5]
content: "Center Text"
font:
size: 20
color: "#666666"
align: center
- type: text
box: [1, 2.6, 3, 0.5]
content: "Right Text"
font:
size: 18
color: "#999999"
align: right
- type: shape
box: [5, 1, 2, 1]
shape: rectangle
fill: "#4a90e2"
line:
color: "#000000"
width: 1
- type: shape
box: [5, 2.2, 2, 2]
shape: ellipse
fill: "#e24a4a"
line:
color: "#ffffff"
width: 2
- type: shape
box: [5, 4.5, 2, 1]
shape: rounded_rectangle
fill: "#4ae290"
line:
color: "#333333"
width: 1
- type: table
position: [1, 3.5]
col_widths: [2, 2, 2]
data:
- ["Header 1", "Header 2", "Header 3"]
- ["Data 1", "Data 2", "Data 3"]
- ["Data 4", "Data 5", "Data 6"]
style:
font_size: 12
header_bg: "#4a90e2"
header_color: "#ffffff"
"""
yaml_path = temp_dir / "all_elements.yaml"
yaml_path.write_text(yaml_content)
return yaml_path
@pytest.fixture
def invalid_yaml_samples(fixtures_dir):
"""所有无效 YAML 样本的路径"""
invalid_dir = fixtures_dir / "yaml_samples" / "invalid"
if invalid_dir.exists():
return list(invalid_dir.glob("*.yaml"))
return []
@pytest.fixture
def multiple_slides_yaml(temp_dir):
"""创建多张幻灯片的 YAML"""
yaml_content = """
metadata:
size: "16:9"
slides:
# 第一张:标题页
- background:
color: "#4a90e2"
elements:
- type: text
box: [1, 2, 8, 1]
content: "Title Slide"
font:
size: 48
bold: true
color: "#ffffff"
align: center
# 第二张:内容页
- background:
color: "#ffffff"
elements:
- type: text
box: [1, 1, 8, 1]
content: "Content Slide 1"
font:
size: 32
color: "#333333"
# 第三张:内容页
- background:
color: "#ffffff"
elements:
- type: text
box: [1, 1, 8, 1]
content: "Content Slide 2"
font:
size: 32
color: "#333333"
- type: shape
box: [3, 2.5, 4, 2]
shape: rectangle
fill: "#e74c3c"
"""
yaml_path = temp_dir / "multiple_slides.yaml"
yaml_path.write_text(yaml_content)
return yaml_path