""" Convert 命令端到端测试 测试 yaml2pptx.py convert 命令的完整功能 """ import pytest import subprocess import sys from pathlib import Path from pptx import Presentation class TestConvertCmd: """convert 命令测试类""" def run_convert(self, *args): """辅助函数:运行 convert 命令""" cmd = ["uv", "run", "python", "yaml2pptx.py", "convert"] cmd.extend(args) result = subprocess.run( cmd, capture_output=True, text=True, cwd=Path(__file__).parent.parent.parent ) return result def test_basic_conversion(self, sample_yaml, temp_dir): """测试基本转换""" output = temp_dir / "output.pptx" result = self.run_convert(str(sample_yaml), str(output)) assert result.returncode == 0 assert output.exists() assert output.stat().st_size > 0 def test_auto_output_filename(self, sample_yaml, temp_dir): """测试自动生成输出文件名""" # sample_yaml 位于 temp_dir 中,转换时输出也会在 temp_dir # 但因为 cwd 是项目根目录,所以输出文件的路径需要计算 # 实际上,由于 sample_yaml 使用 tempfile,输出会在 temp_dir 中 result = subprocess.run( [ "uv", "run", "python", "yaml2pptx.py", "convert", str(sample_yaml), ], capture_output=True, text=True, cwd=Path(__file__).parent.parent.parent, ) assert result.returncode == 0, f"Command failed: {result.stderr}" # 应该生成与输入同名的 .pptx 文件(在 temp_dir 中) expected_output = temp_dir / "test.pptx" assert expected_output.exists(), ( f"Expected {expected_output} to exist, but didn't" ) def test_conversion_with_template(self, temp_dir, sample_template): """测试使用模板转换""" yaml_content = f""" metadata: size: "16:9" slides: - template: title-slide vars: title: "Template Test" """ yaml_path = temp_dir / "test.yaml" yaml_path.write_text(yaml_content) output = temp_dir / "output.pptx" result = self.run_convert( str(yaml_path), str(output), "--template", str(sample_template) ) assert result.returncode == 0 assert output.exists() def test_skip_validation(self, sample_yaml, temp_dir): """测试跳过验证""" output = temp_dir / "output.pptx" result = self.run_convert(str(sample_yaml), str(output), "--skip-validation") assert result.returncode == 0 assert output.exists() def test_force_overwrite(self, sample_yaml, temp_dir): """测试强制覆盖""" output = temp_dir / "output.pptx" # 先创建一个存在的文件 output.write_text("existing") # 使用 --force 应该覆盖 result = self.run_convert(str(sample_yaml), str(output), "--force") assert result.returncode == 0 # 文件应该是有效的 PPTX,不是原来的文本 assert output.stat().st_size > 1000 def test_existing_file_without_force(self, sample_yaml, temp_dir): """测试文件已存在且不使用 --force""" output = temp_dir / "output.pptx" # 先创建一个存在的文件 output.write_text("existing") # 不使用 --force 应该失败或提示 result = self.run_convert(str(sample_yaml), str(output)) # 程序应该拒绝覆盖 assert result.returncode != 0 or "已存在" in result.stderr def test_invalid_input_file(self, temp_dir): """测试无效输入文件""" nonexistent = temp_dir / "nonexistent.yaml" output = temp_dir / "output.pptx" result = self.run_convert(str(nonexistent), str(output)) assert result.returncode != 0 def test_conversion_with_all_element_types(self, temp_dir, sample_image): """测试转换包含所有元素类型的 YAML""" fixtures_yaml = ( Path(__file__).parent.parent / "fixtures" / "yaml_samples" / "full_features.yaml" ) if not fixtures_yaml.exists(): pytest.skip("full_features.yaml not found") output = temp_dir / "output.pptx" result = self.run_convert(str(fixtures_yaml), str(output)) assert result.returncode == 0 assert output.exists() # 验证生成的 PPTX prs = Presentation(str(output)) assert len(prs.slides) >= 1 def test_conversion_preserves_chinese_content(self, temp_dir): """测试转换保留中文内容""" yaml_content = """ metadata: size: "16:9" slides: - elements: - type: text box: [1, 1, 8, 1] content: "测试中文内容" font: size: 24 """ yaml_path = temp_dir / "test.yaml" yaml_path.write_text(yaml_content, encoding="utf-8") output = temp_dir / "output.pptx" result = self.run_convert(str(yaml_path), str(output)) assert result.returncode == 0 assert output.exists() # 验证内容 prs = Presentation(str(output)) text_content = prs.slides[0].shapes[0].text_frame.text assert "测试中文内容" in text_content def test_different_slide_sizes(self, temp_dir): """测试不同的幻灯片尺寸""" for size in ["16:9", "4:3"]: yaml_content = f''' metadata: size: "{size}" slides: - elements: - type: text box: [1, 1, 8, 1] content: "Size {size}" font: size: 24 ''' yaml_path = temp_dir / f"test_{size.replace(':', '')}.yaml" yaml_path.write_text(yaml_content) output = temp_dir / f"output_{size.replace(':', '')}.pptx" result = self.run_convert(str(yaml_path), str(output)) assert result.returncode == 0, f"Failed for size {size}" assert output.exists() # 验证尺寸 prs = Presentation(str(output)) if size == "16:9": assert abs(prs.slide_width.inches - 10.0) < 0.01 assert abs(prs.slide_height.inches - 5.625) < 0.01 else: # 4:3 assert abs(prs.slide_width.inches - 10.0) < 0.01 assert abs(prs.slide_height.inches - 7.5) < 0.01 def test_subdirectory_path_resolution(self, temp_dir): """测试子目录中的文件路径解析""" # 创建子目录结构 doc_dir = temp_dir / "docs" template_dir = temp_dir / "templates" doc_dir.mkdir() template_dir.mkdir() # 创建模板库文件 template_content = """ metadata: size: "16:9" templates: test-template: vars: - name: title required: true elements: - type: text box: [1, 1, 8, 1] content: "{title}" """ template_path = template_dir / "templates.yaml" template_path.write_text(template_content) # 创建文档文件 yaml_content = """ metadata: size: "16:9" slides: - template: test-template vars: title: "Test Title" """ yaml_path = doc_dir / "test.yaml" yaml_path.write_text(yaml_content) output_path = temp_dir / "output.pptx" # 使用相对路径运行转换 import os original_cwd = os.getcwd() try: os.chdir(temp_dir) result = subprocess.run( ["uv", "run", "python", str(Path(original_cwd) / "yaml2pptx.py"), "convert", "docs/test.yaml", "output.pptx", "--template", "templates/templates.yaml"], capture_output=True, text=True ) assert result.returncode == 0, f"转换失败: {result.stderr}" assert output_path.exists() # 验证生成的 PPTX prs = Presentation(str(output_path)) assert len(prs.slides) == 1 text_content = prs.slides[0].shapes[0].text_frame.text assert "Test Title" in text_content finally: os.chdir(original_cwd)