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>
This commit is contained in:
@@ -252,52 +252,6 @@ templates:
|
||||
assert len(result["elements"]) == 1
|
||||
assert result["elements"][0].content == "Test"
|
||||
|
||||
def test_backward_compat_template_only(self, temp_dir, sample_template):
|
||||
"""测试向后兼容:纯模板模式"""
|
||||
yaml_content = """
|
||||
slides:
|
||||
- elements: []
|
||||
templates:
|
||||
test-template:
|
||||
vars:
|
||||
- name: title
|
||||
elements:
|
||||
- type: text
|
||||
content: "{title}"
|
||||
box: [0, 0, 1, 1]
|
||||
font: {}
|
||||
"""
|
||||
yaml_path = temp_dir / "test.yaml"
|
||||
yaml_path.write_text(yaml_content)
|
||||
|
||||
pres = Presentation(str(yaml_path))
|
||||
|
||||
slide_data = {
|
||||
"template": "test-template",
|
||||
"vars": {"title": "Test"}
|
||||
}
|
||||
|
||||
result = pres.render_slide(slide_data)
|
||||
|
||||
# 应该只有模板元素
|
||||
assert len(result["elements"]) == 1
|
||||
assert result["elements"][0].content == "Test"
|
||||
|
||||
def test_backward_compat_custom_only(self, sample_yaml):
|
||||
"""测试向后兼容:纯自定义元素模式"""
|
||||
pres = Presentation(str(sample_yaml))
|
||||
|
||||
slide_data = {
|
||||
"elements": [
|
||||
{"type": "text", "content": "Custom", "box": [0, 0, 1, 1], "font": {}}
|
||||
]
|
||||
}
|
||||
|
||||
result = pres.render_slide(slide_data)
|
||||
|
||||
# 应该只有自定义元素
|
||||
assert len(result["elements"]) == 1
|
||||
assert result["elements"][0].content == "Custom"
|
||||
|
||||
def test_hybrid_mode_with_inline_template(self, temp_dir):
|
||||
"""测试内联模板与自定义元素混合使用"""
|
||||
@@ -485,3 +439,140 @@ class TestSlideDescription:
|
||||
assert len(result["elements"]) == 1
|
||||
assert result["elements"][0].content == "Test Content"
|
||||
|
||||
|
||||
class TestSizeConsistency:
|
||||
"""Size 一致性校验测试类"""
|
||||
|
||||
def test_size_consistency_16_9(self, temp_dir):
|
||||
"""测试文档和模板库 size 都是 16:9 时正常加载"""
|
||||
# 创建文档
|
||||
doc_content = """
|
||||
metadata:
|
||||
size: "16:9"
|
||||
slides:
|
||||
- elements: []
|
||||
"""
|
||||
doc_path = temp_dir / "doc.yaml"
|
||||
doc_path.write_text(doc_content)
|
||||
|
||||
# 创建模板库
|
||||
template_content = """
|
||||
metadata:
|
||||
size: "16:9"
|
||||
templates:
|
||||
test:
|
||||
elements: []
|
||||
"""
|
||||
template_path = temp_dir / "templates.yaml"
|
||||
template_path.write_text(template_content)
|
||||
|
||||
# 应该正常加载
|
||||
pres = Presentation(str(doc_path), str(template_path))
|
||||
assert pres.size == "16:9"
|
||||
|
||||
def test_size_consistency_4_3(self, temp_dir):
|
||||
"""测试文档和模板库 size 都是 4:3 时正常加载"""
|
||||
# 创建文档
|
||||
doc_content = """
|
||||
metadata:
|
||||
size: "4:3"
|
||||
slides:
|
||||
- elements: []
|
||||
"""
|
||||
doc_path = temp_dir / "doc.yaml"
|
||||
doc_path.write_text(doc_content)
|
||||
|
||||
# 创建模板库
|
||||
template_content = """
|
||||
metadata:
|
||||
size: "4:3"
|
||||
templates:
|
||||
test:
|
||||
elements: []
|
||||
"""
|
||||
template_path = temp_dir / "templates.yaml"
|
||||
template_path.write_text(template_content)
|
||||
|
||||
# 应该正常加载
|
||||
pres = Presentation(str(doc_path), str(template_path))
|
||||
assert pres.size == "4:3"
|
||||
|
||||
def test_size_mismatch_error(self, temp_dir):
|
||||
"""测试文档和模板库 size 不一致时抛出错误"""
|
||||
# 创建文档
|
||||
doc_content = """
|
||||
metadata:
|
||||
size: "16:9"
|
||||
slides:
|
||||
- elements: []
|
||||
"""
|
||||
doc_path = temp_dir / "doc.yaml"
|
||||
doc_path.write_text(doc_content)
|
||||
|
||||
# 创建模板库
|
||||
template_content = """
|
||||
metadata:
|
||||
size: "4:3"
|
||||
templates:
|
||||
test:
|
||||
elements: []
|
||||
"""
|
||||
template_path = temp_dir / "templates.yaml"
|
||||
template_path.write_text(template_content)
|
||||
|
||||
# 应该抛出错误
|
||||
with pytest.raises(YAMLError, match="文档尺寸.*与模板库尺寸.*不一致"):
|
||||
Presentation(str(doc_path), str(template_path))
|
||||
|
||||
def test_template_library_missing_metadata(self, temp_dir):
|
||||
"""测试模板库缺少 metadata 时抛出错误"""
|
||||
# 创建文档
|
||||
doc_content = """
|
||||
metadata:
|
||||
size: "16:9"
|
||||
slides:
|
||||
- elements: []
|
||||
"""
|
||||
doc_path = temp_dir / "doc.yaml"
|
||||
doc_path.write_text(doc_content)
|
||||
|
||||
# 创建模板库(缺少 metadata)
|
||||
template_content = """
|
||||
templates:
|
||||
test:
|
||||
elements: []
|
||||
"""
|
||||
template_path = temp_dir / "templates.yaml"
|
||||
template_path.write_text(template_content)
|
||||
|
||||
# 应该抛出错误
|
||||
with pytest.raises(YAMLError, match="模板库必须包含 metadata 字段"):
|
||||
Presentation(str(doc_path), str(template_path))
|
||||
|
||||
def test_template_library_missing_size(self, temp_dir):
|
||||
"""测试模板库 metadata 缺少 size 时抛出错误"""
|
||||
# 创建文档
|
||||
doc_content = """
|
||||
metadata:
|
||||
size: "16:9"
|
||||
slides:
|
||||
- elements: []
|
||||
"""
|
||||
doc_path = temp_dir / "doc.yaml"
|
||||
doc_path.write_text(doc_content)
|
||||
|
||||
# 创建模板库(metadata 缺少 size)
|
||||
template_content = """
|
||||
metadata:
|
||||
description: "测试模板库"
|
||||
templates:
|
||||
test:
|
||||
elements: []
|
||||
"""
|
||||
template_path = temp_dir / "templates.yaml"
|
||||
template_path.write_text(template_content)
|
||||
|
||||
# 应该抛出错误
|
||||
with pytest.raises(YAMLError, match="metadata 缺少必填字段 'size'"):
|
||||
Presentation(str(doc_path), str(template_path))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user