主要变更: - 将 templates_dir 参数改为 template_file,支持单个模板库 YAML 文件 - 添加模板库 YAML 验证功能 - 为模板添加 base_dir 支持,正确解析相对路径资源 - 内联模板与外部模板同名时改为警告(内联优先) - 移除模板缓存机制,直接使用模板库字典 - 更新所有相关测试以适配新的模板加载方式 此重构简化了模板管理,使模板资源的路径解析更加清晰明确。
376 lines
7.9 KiB
Python
376 lines
7.9 KiB
Python
"""
|
||
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 = """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
|