test: add comprehensive pytest test suite
Add complete test infrastructure for yaml2pptx project with 245+ tests covering unit, integration, and end-to-end scenarios. Test structure: - Unit tests: elements, template system, validators, loaders, utils - Integration tests: presentation and rendering flows - E2E tests: CLI commands (convert, check, preview) Key features: - PptxFileValidator for Level 2 PPTX validation (file structure, element count, content matching, position tolerance) - Comprehensive fixtures for test data consistency - Mock-based testing for external dependencies - Test images generated with PIL/Pillow - Boundary case coverage for edge scenarios Dependencies added: - pytest, pytest-cov, pytest-mock - pillow (for test image generation) Documentation updated: - README.md: test running instructions - README_DEV.md: test development guide Co-authored-by: OpenSpec change: add-comprehensive-tests
This commit is contained in:
135
tests/unit/test_validators/test_resource.py
Normal file
135
tests/unit/test_validators/test_resource.py
Normal file
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
资源验证器单元测试
|
||||
|
||||
测试 ResourceValidator 的图片和模板文件验证功能
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from validators.resource import ResourceValidator
|
||||
|
||||
|
||||
class TestResourceValidator:
|
||||
"""ResourceValidator 测试类"""
|
||||
|
||||
def test_init(self, temp_dir):
|
||||
"""测试初始化"""
|
||||
validator = ResourceValidator(yaml_dir=temp_dir)
|
||||
assert validator.yaml_dir == temp_dir
|
||||
assert validator.template_dir is None
|
||||
|
||||
def test_init_with_template_dir(self, temp_dir):
|
||||
"""测试带模板目录初始化"""
|
||||
template_dir = temp_dir / "templates"
|
||||
validator = ResourceValidator(
|
||||
yaml_dir=temp_dir,
|
||||
template_dir=template_dir
|
||||
)
|
||||
assert validator.template_dir == template_dir
|
||||
|
||||
|
||||
class TestValidateImage:
|
||||
"""validate_image 方法测试"""
|
||||
|
||||
def test_existing_image(self, temp_dir, sample_image):
|
||||
"""测试存在的图片文件"""
|
||||
validator = ResourceValidator(yaml_dir=temp_dir)
|
||||
elem = type('Element', (), {'src': sample_image.name})()
|
||||
issues = validator.validate_image(elem, 1, 1)
|
||||
assert len(issues) == 0
|
||||
|
||||
def test_nonexistent_image(self, temp_dir):
|
||||
"""测试不存在的图片文件"""
|
||||
validator = ResourceValidator(yaml_dir=temp_dir)
|
||||
elem = type('Element', (), {'src': 'nonexistent.png'})()
|
||||
issues = validator.validate_image(elem, 1, 1)
|
||||
assert len(issues) == 1
|
||||
assert issues[0].level == "ERROR"
|
||||
assert issues[0].code == "IMAGE_FILE_NOT_FOUND"
|
||||
|
||||
def test_image_with_absolute_path(self, temp_dir, sample_image):
|
||||
"""测试绝对路径图片"""
|
||||
validator = ResourceValidator(yaml_dir=temp_dir)
|
||||
elem = type('Element', (), {'src': str(sample_image)})()
|
||||
issues = validator.validate_image(elem, 1, 1)
|
||||
assert len(issues) == 0
|
||||
|
||||
def test_image_without_src_attribute(self, temp_dir):
|
||||
"""测试没有 src 属性的元素"""
|
||||
validator = ResourceValidator(yaml_dir=temp_dir)
|
||||
elem = type('Element', (), {})() # 没有 src 属性
|
||||
issues = validator.validate_image(elem, 1, 1)
|
||||
assert len(issues) == 0
|
||||
|
||||
def test_image_with_empty_src(self, temp_dir):
|
||||
"""测试空 src 字符串"""
|
||||
validator = ResourceValidator(yaml_dir=temp_dir)
|
||||
elem = type('Element', (), {'src': ''})()
|
||||
issues = validator.validate_image(elem, 1, 1)
|
||||
assert len(issues) == 0
|
||||
|
||||
|
||||
class TestValidateTemplate:
|
||||
"""validate_template 方法测试"""
|
||||
|
||||
def test_slide_without_template(self, temp_dir):
|
||||
"""测试不使用模板的幻灯片"""
|
||||
validator = ResourceValidator(yaml_dir=temp_dir)
|
||||
slide_data = {} # 没有 template 字段
|
||||
issues = validator.validate_template(slide_data, 1)
|
||||
assert len(issues) == 0
|
||||
|
||||
def test_template_with_dir_not_specified(self, temp_dir):
|
||||
"""测试使用模板但未指定模板目录"""
|
||||
validator = ResourceValidator(yaml_dir=temp_dir, template_dir=None)
|
||||
slide_data = {'template': 'title-slide'}
|
||||
issues = validator.validate_template(slide_data, 1)
|
||||
assert len(issues) == 1
|
||||
assert issues[0].level == "ERROR"
|
||||
assert issues[0].code == "TEMPLATE_DIR_NOT_SPECIFIED"
|
||||
|
||||
def test_nonexistent_template_file(self, temp_dir):
|
||||
"""测试不存在的模板文件"""
|
||||
template_dir = temp_dir / "templates"
|
||||
template_dir.mkdir()
|
||||
validator = ResourceValidator(yaml_dir=temp_dir, template_dir=template_dir)
|
||||
slide_data = {'template': 'nonexistent'}
|
||||
issues = validator.validate_template(slide_data, 1)
|
||||
assert len(issues) == 1
|
||||
assert issues[0].level == "ERROR"
|
||||
assert issues[0].code == "TEMPLATE_FILE_NOT_FOUND"
|
||||
|
||||
def test_valid_template_file(self, sample_template):
|
||||
"""测试有效的模板文件"""
|
||||
validator = ResourceValidator(
|
||||
yaml_dir=sample_template.parent,
|
||||
template_dir=sample_template
|
||||
)
|
||||
slide_data = {'template': 'title-slide'}
|
||||
issues = validator.validate_template(slide_data, 1)
|
||||
assert len(issues) == 0
|
||||
|
||||
def test_template_with_yaml_extension(self, temp_dir):
|
||||
"""测试带 .yaml 扩展名的模板"""
|
||||
template_dir = temp_dir / "templates"
|
||||
template_dir.mkdir()
|
||||
(template_dir / "test.yaml").write_text("vars: []\nelements: []")
|
||||
|
||||
validator = ResourceValidator(yaml_dir=temp_dir, template_dir=template_dir)
|
||||
slide_data = {'template': 'test.yaml'}
|
||||
issues = validator.validate_template(slide_data, 1)
|
||||
assert len(issues) == 0
|
||||
|
||||
def test_invalid_template_structure(self, temp_dir):
|
||||
"""测试无效的模板结构"""
|
||||
template_dir = temp_dir / "templates"
|
||||
template_dir.mkdir()
|
||||
# 创建缺少 elements 字段的无效模板
|
||||
(template_dir / "invalid.yaml").write_text("vars: []")
|
||||
|
||||
validator = ResourceValidator(yaml_dir=temp_dir, template_dir=template_dir)
|
||||
slide_data = {'template': 'invalid'}
|
||||
issues = validator.validate_template(slide_data, 1)
|
||||
assert len(issues) == 1
|
||||
assert issues[0].level == "ERROR"
|
||||
assert issues[0].code == "TEMPLATE_STRUCTURE_ERROR"
|
||||
Reference in New Issue
Block a user