""" Presentation 类单元测试 测试 Presentation 类的初始化、模板缓存和渲染方法 """ import pytest from pathlib import Path from unittest.mock import patch, Mock from core.presentation import Presentation from loaders.yaml_loader import YAMLError class TestPresentationInit: """Presentation 初始化测试类""" def test_init_with_valid_yaml(self, sample_yaml): """测试使用有效 YAML 初始化""" pres = Presentation(str(sample_yaml)) assert pres.data is not None assert "slides" in pres.data assert pres.pres_file == sample_yaml def test_init_with_templates_dir(self, sample_yaml, sample_template): """测试带模板目录初始化""" pres = Presentation(str(sample_yaml), str(sample_template)) assert pres.templates_dir == sample_template assert isinstance(pres.template_cache, dict) def test_init_without_templates_dir(self, sample_yaml): """测试不带模板目录初始化""" pres = Presentation(str(sample_yaml)) assert pres.templates_dir is None assert isinstance(pres.template_cache, dict) @patch('core.presentation.load_yaml_file') @patch('core.presentation.validate_presentation_yaml') def test_init_loads_yaml(self, mock_validate, mock_load, temp_dir): """测试初始化时加载 YAML""" mock_data = {"slides": [{"elements": []}]} mock_load.return_value = mock_data yaml_path = temp_dir / "test.yaml" pres = Presentation(str(yaml_path)) mock_load.assert_called_once_with(str(yaml_path)) mock_validate.assert_called_once() def test_init_with_invalid_yaml(self, temp_dir): """测试使用无效 YAML 初始化""" invalid_yaml = temp_dir / "invalid.yaml" invalid_yaml.write_text("invalid: [unclosed") with pytest.raises(Exception): Presentation(str(invalid_yaml)) class TestPresentationSize: """Presentation size 属性测试类""" def test_size_16_9(self, temp_dir): """测试 16:9 尺寸""" yaml_content = """ metadata: size: "16:9" slides: - elements: [] """ yaml_path = temp_dir / "test.yaml" yaml_path.write_text(yaml_content) pres = Presentation(str(yaml_path)) assert pres.size == "16:9" def test_size_4_3(self, temp_dir): """测试 4:3 尺寸""" yaml_content = """ metadata: size: "4:3" slides: - elements: [] """ yaml_path = temp_dir / "test.yaml" yaml_path.write_text(yaml_content) pres = Presentation(str(yaml_path)) assert pres.size == "4:3" def test_size_default(self, temp_dir): """测试默认尺寸""" yaml_content = """ slides: - elements: [] """ yaml_path = temp_dir / "test.yaml" yaml_path.write_text(yaml_content) pres = Presentation(str(yaml_path)) assert pres.size == "16:9" # 默认值 def test_size_without_metadata(self, temp_dir): """测试无 metadata 时的默认尺寸""" yaml_content = """ slides: - elements: [] """ yaml_path = temp_dir / "test.yaml" yaml_path.write_text(yaml_content) pres = Presentation(str(yaml_path)) assert pres.size == "16:9" class TestGetTemplate: """get_template 方法测试类""" @patch('core.presentation.Template') def test_get_template_caches_template(self, mock_template_class, sample_template): """测试模板被缓存""" mock_template = Mock() mock_template_class.return_value = mock_template # 创建一个使用模板的 YAML yaml_content = """ slides: - elements: [] """ yaml_path = sample_template / "test.yaml" yaml_path.write_text(yaml_content) pres = Presentation(str(yaml_path), str(sample_template)) # 第一次获取 template1 = pres.get_template("test_template") # 第二次获取 template2 = pres.get_template("test_template") # 应该是同一个实例 assert template1 is template2 @patch('core.presentation.Template') def test_get_template_creates_new_template(self, mock_template_class, sample_template): """测试创建新模板""" mock_template = Mock() mock_template_class.return_value = mock_template yaml_content = """ slides: - elements: [] """ yaml_path = sample_template / "test.yaml" yaml_path.write_text(yaml_content) pres = Presentation(str(yaml_path), str(sample_template)) # 获取模板 template = pres.get_template("new_template") # 应该创建模板 mock_template_class.assert_called_once() assert template == mock_template def test_get_template_without_templates_dir(self, sample_yaml): """测试无模板目录时获取模板""" pres = Presentation(str(sample_yaml)) # 应该在调用 Template 时失败,而不是 get_template with patch('core.presentation.Template') as mock_template_class: mock_template_class.side_effect = YAMLError("No template dir") with pytest.raises(YAMLError): pres.get_template("test") class TestRenderSlide: """render_slide 方法测试类""" def test_render_slide_without_template(self, sample_yaml): """测试渲染不使用模板的幻灯片""" pres = Presentation(str(sample_yaml)) slide_data = { "elements": [ {"type": "text", "content": "Test", "box": [0, 0, 1, 1], "font": {}} ] } result = pres.render_slide(slide_data) assert "elements" in result assert len(result["elements"]) == 1 assert result["elements"][0].content == "Test" @patch('core.presentation.Template') def test_render_slide_with_template(self, mock_template_class, temp_dir, sample_template): """测试渲染使用模板的幻灯片""" mock_template = Mock() mock_template.render.return_value = [ {"type": "text", "content": "Template Title", "box": [0, 0, 1, 1], "font": {}} ] mock_template_class.return_value = mock_template yaml_content = """ slides: - elements: [] """ yaml_path = temp_dir / "test.yaml" yaml_path.write_text(yaml_content) pres = Presentation(str(yaml_path), str(sample_template)) slide_data = { "template": "title-slide", "vars": {"title": "My Title"} } result = pres.render_slide(slide_data) # 模板应该被渲染 mock_template.render.assert_called_once_with({"title": "My Title"}) assert "elements" in result def test_render_slide_with_background(self, sample_yaml): """测试渲染带背景的幻灯片""" pres = Presentation(str(sample_yaml)) slide_data = { "background": {"color": "#ffffff"}, "elements": [] } result = pres.render_slide(slide_data) assert result["background"] == {"color": "#ffffff"} def test_render_slide_without_background(self, sample_yaml): """测试渲染无背景的幻灯片""" pres = Presentation(str(sample_yaml)) slide_data = { "elements": [] } result = pres.render_slide(slide_data) assert result["background"] is None @patch('core.presentation.create_element') def test_render_slide_converts_dict_to_objects(self, mock_create_element, sample_yaml): """测试字典转换为元素对象""" mock_elem = Mock() mock_create_element.return_value = mock_elem pres = Presentation(str(sample_yaml)) slide_data = { "elements": [ {"type": "text", "content": "Test", "box": [0, 0, 1, 1], "font": {}} ] } result = pres.render_slide(slide_data) # create_element 应该被调用 mock_create_element.assert_called() assert result["elements"][0] == mock_elem def test_render_slide_with_template_merges_background(self, mock_template_class, temp_dir, sample_template): """测试使用模板时合并背景""" mock_template = Mock() mock_template.render.return_value = [ {"type": "text", "content": "Title", "box": [0, 0, 1, 1], "font": {}} ] mock_template_class.return_value = mock_template yaml_content = """ slides: - elements: [] """ yaml_path = temp_dir / "test.yaml" yaml_path.write_text(yaml_content) pres = Presentation(str(yaml_path), str(sample_template)) slide_data = { "template": "test", "vars": {}, "background": {"color": "#ff0000"} } result = pres.render_slide(slide_data) # 背景应该被保留 assert result["background"] == {"color": "#ff0000"} def test_render_slide_empty_elements_list(self, sample_yaml): """测试空元素列表""" pres = Presentation(str(sample_yaml)) slide_data = { "elements": [] } result = pres.render_slide(slide_data) assert result["elements"] == [] @patch('core.presentation.create_element') def test_render_slide_with_multiple_elements(self, mock_create_element, sample_yaml): """测试多个元素""" mock_elem1 = Mock() mock_elem2 = Mock() mock_create_element.side_effect = [mock_elem1, mock_elem2] pres = Presentation(str(sample_yaml)) slide_data = { "elements": [ {"type": "text", "content": "T1", "box": [0, 0, 1, 1], "font": {}}, {"type": "text", "content": "T2", "box": [1, 1, 1, 1], "font": {}} ] } result = pres.render_slide(slide_data) assert len(result["elements"]) == 2