diff --git a/core/presentation.py b/core/presentation.py
index c596421..1730f8a 100644
--- a/core/presentation.py
+++ b/core/presentation.py
@@ -29,8 +29,14 @@ class Presentation:
validate_presentation_yaml(self.data, str(pres_file))
# 获取演示文稿尺寸
- metadata = self.data.get('metadata', {})
- self.size = metadata.get('size', '16:9')
+ metadata = self.data.get("metadata", {})
+ self.size = metadata.get("size", "16:9")
+
+ # 验证尺寸值
+ if not isinstance(self.size, str):
+ raise ValueError(
+ f"无效的尺寸值: {self.size},尺寸必须是字符串(如 '16:9' 或 '4:3')"
+ )
# 模板缓存
self.template_cache = {}
@@ -61,31 +67,28 @@ class Presentation:
Returns:
dict: 包含 background 和 elements 的字典
"""
- if 'template' in slide_data:
+ if "template" in slide_data:
# 使用模板
- template_name = slide_data['template']
+ template_name = slide_data["template"]
template = self.get_template(template_name)
- vars_values = slide_data.get('vars', {})
+ vars_values = slide_data.get("vars", {})
elements = template.render(vars_values)
# 合并背景(如果有)
- background = slide_data.get('background', None)
+ background = slide_data.get("background", None)
# 将元素字典转换为元素对象
element_objects = [create_element(elem) for elem in elements]
- return {
- 'background': background,
- 'elements': element_objects
- }
+ return {"background": background, "elements": element_objects}
else:
# 自定义幻灯片
- elements = slide_data.get('elements', [])
+ elements = slide_data.get("elements", [])
# 将元素字典转换为元素对象
element_objects = [create_element(elem) for elem in elements]
return {
- 'background': slide_data.get('background'),
- 'elements': element_objects
+ "background": slide_data.get("background"),
+ "elements": element_objects,
}
diff --git a/renderers/html_renderer.py b/renderers/html_renderer.py
index 2935aec..4f96712 100644
--- a/renderers/html_renderer.py
+++ b/renderers/html_renderer.py
@@ -30,12 +30,12 @@ class HtmlRenderer:
elements_html = ""
bg_style = ""
- if slide_data.get('background'):
- bg = slide_data['background']
- if 'color' in bg:
+ if slide_data.get("background"):
+ bg = slide_data["background"]
+ if "color" in bg:
bg_style = f"background: {bg['color']};"
- for elem in slide_data.get('elements', []):
+ for elem in slide_data.get("elements", []):
try:
if isinstance(elem, TextElement):
elements_html += self.render_text(elem)
@@ -46,7 +46,9 @@ class HtmlRenderer:
elif isinstance(elem, ImageElement):
elements_html += self.render_image(elem, base_path)
except Exception as e:
- elements_html += f'
@@ -70,18 +72,20 @@ class HtmlRenderer:
top: {elem.box[1] * DPI}px;
width: {elem.box[2] * DPI}px;
height: {elem.box[3] * DPI}px;
- font-size: {elem.font.get('size', 16)}pt;
- color: {elem.font.get('color', '#000000')};
- text-align: {elem.font.get('align', 'left')};
- {'font-weight: bold;' if elem.font.get('bold') else ''}
- {'font-style: italic;' if elem.font.get('italic') else ''}
+ font-size: {elem.font.get("size", 16)}pt;
+ color: {elem.font.get("color", "#000000")};
+ text-align: {elem.font.get("align", "left")};
+ {"font-weight: bold;" if elem.font.get("bold") else ""}
+ {"font-style: italic;" if elem.font.get("italic") else ""}
display: flex;
align-items: center;
white-space: normal;
overflow-wrap: break-word;
"""
- content = elem.content.replace('<', '<').replace('>', '>')
+ content = (
+ elem.content.replace("&", "&").replace("<", "<").replace(">", ">")
+ )
return f'
{content}
'
def render_shape(self, elem: ShapeElement):
@@ -95,23 +99,23 @@ class HtmlRenderer:
str: HTML 代码
"""
border_radius = {
- 'rectangle': '0',
- 'ellipse': '50%',
- 'rounded_rectangle': '8px'
- }.get(elem.shape, '0')
+ "rectangle": "0",
+ "ellipse": "50%",
+ "rounded_rectangle": "8px",
+ }.get(elem.shape, "0")
style = f"""
left: {elem.box[0] * DPI}px;
top: {elem.box[1] * DPI}px;
width: {elem.box[2] * DPI}px;
height: {elem.box[3] * DPI}px;
- background: {elem.fill if elem.fill else 'transparent'};
+ background: {elem.fill if elem.fill else "transparent"};
border-radius: {border_radius};
"""
if elem.line:
style += f"""
- border: {elem.line.get('width', 1)}pt solid {elem.line.get('color', '#000000')};
+ border: {elem.line.get("width", 1)}pt solid {elem.line.get("color", "#000000")};
"""
return f'
'
@@ -138,14 +142,14 @@ class HtmlRenderer:
cell_style = f"font-size: {elem.style.get('font_size', 14)}pt;"
if i == 0:
- if 'header_bg' in elem.style:
+ if "header_bg" in elem.style:
cell_style += f"background: {elem.style['header_bg']};"
- if 'header_color' in elem.style:
+ if "header_color" in elem.style:
cell_style += f"color: {elem.style['header_color']};"
- cell_content = str(cell).replace('<', '<').replace('>', '>')
+ cell_content = str(cell).replace("<", "<").replace(">", ">")
cells_html += f'
{cell_content} | '
- rows_html += f'
{cells_html}
'
+ rows_html += f"
{cells_html}
"
return f'
'
diff --git a/tests/conftest_pptx.py b/tests/conftest_pptx.py
index 29aefed..0047a1a 100644
--- a/tests/conftest_pptx.py
+++ b/tests/conftest_pptx.py
@@ -16,6 +16,7 @@ from pptx.enum.shapes import MSO_SHAPE
class PptxValidationError:
"""验证错误信息"""
+
def __init__(self, level: str, message: str):
self.level = level # 'ERROR' or 'WARNING'
self.message = message
@@ -69,13 +70,16 @@ class PptxFileValidator:
actual = len(prs.slides)
if actual != expected_count:
self.errors.append(
- PptxValidationError("ERROR",
- f"幻灯片数量不匹配: 期望 {expected_count}, 实际 {actual}")
+ PptxValidationError(
+ "ERROR", f"幻灯片数量不匹配: 期望 {expected_count}, 实际 {actual}"
+ )
)
return False
return True
- def validate_slide_size(self, prs: Presentation, expected_size: str = "16:9") -> bool:
+ def validate_slide_size(
+ self, prs: Presentation, expected_size: str = "16:9"
+ ) -> bool:
"""验证幻灯片尺寸"""
expected = self.SIZE_16_9 if expected_size == "16:9" else self.SIZE_4_3
actual_width = prs.slide_width.inches
@@ -83,15 +87,19 @@ class PptxFileValidator:
if abs(actual_width - expected[0]) > self.TOLERANCE:
self.errors.append(
- PptxValidationError("ERROR",
- f"幻灯片宽度不匹配: 期望 {expected[0]}, 实际 {actual_width}")
+ PptxValidationError(
+ "ERROR",
+ f"幻灯片宽度不匹配: 期望 {expected[0]}, 实际 {actual_width}",
+ )
)
return False
if abs(actual_height - expected[1]) > self.TOLERANCE:
self.errors.append(
- PptxValidationError("ERROR",
- f"幻灯片高度不匹配: 期望 {expected[1]}, 实际 {actual_height}")
+ PptxValidationError(
+ "ERROR",
+ f"幻灯片高度不匹配: 期望 {expected[1]}, 实际 {actual_height}",
+ )
)
return False
@@ -113,8 +121,11 @@ class PptxFileValidator:
counts["text_box"] += 1
elif hasattr(shape, "image"):
counts["picture"] += 1
- elif shape.shape_type in [MSO_SHAPE.RECTANGLE, MSO_SHAPE.OVAL,
- MSO_SHAPE.ROUNDED_RECTANGLE]:
+ elif shape.shape_type in [
+ MSO_SHAPE.RECTANGLE,
+ MSO_SHAPE.OVAL,
+ MSO_SHAPE.ROUNDED_RECTANGLE,
+ ]:
counts["shape"] += 1
elif shape.has_table:
counts["table"] += 1
@@ -125,10 +136,14 @@ class PptxFileValidator:
return counts
- def validate_text_element(self, slide, index: int = 0,
- expected_content: Optional[str] = None,
- expected_font_size: Optional[int] = None,
- expected_color: Optional[tuple] = None) -> bool:
+ def validate_text_element(
+ self,
+ slide,
+ index: int = 0,
+ expected_content: Optional[str] = None,
+ expected_font_size: Optional[int] = None,
+ expected_color: Optional[tuple] = None,
+ ) -> bool:
"""
验证文本元素
@@ -142,7 +157,8 @@ class PptxFileValidator:
Returns:
验证是否通过
"""
- text_boxes = [s for s in slide.shapes if s.shape_type == MSO_SHAPE.TEXT_BOX]
+ # 通过检查是否有text_frame属性来判断是否是文本框
+ text_boxes = [s for s in slide.shapes if hasattr(s, "text_frame")]
if index >= len(text_boxes):
self.errors.append(
@@ -158,8 +174,10 @@ class PptxFileValidator:
actual_content = text_frame.text
if actual_content != expected_content:
self.errors.append(
- PptxValidationError("ERROR",
- f"文本内容不匹配: 期望 '{expected_content}', 实际 '{actual_content}'")
+ PptxValidationError(
+ "ERROR",
+ f"文本内容不匹配: 期望 '{expected_content}', 实际 '{actual_content}'",
+ )
)
return False
@@ -168,8 +186,10 @@ class PptxFileValidator:
actual_size = text_frame.paragraphs[0].font.size.pt
if abs(actual_size - expected_font_size) > 1:
self.errors.append(
- PptxValidationError("ERROR",
- f"字体大小不匹配: 期望 {expected_font_size}pt, 实际 {actual_size}pt")
+ PptxValidationError(
+ "ERROR",
+ f"字体大小不匹配: 期望 {expected_font_size}pt, 实际 {actual_size}pt",
+ )
)
return False
@@ -180,20 +200,25 @@ class PptxFileValidator:
actual_color = (actual_rgb[0], actual_rgb[1], actual_rgb[2])
if actual_color != expected_color:
self.errors.append(
- PptxValidationError("ERROR",
- f"字体颜色不匹配: 期望 RGB{expected_color}, 实际 RGB{actual_color}")
+ PptxValidationError(
+ "ERROR",
+ f"字体颜色不匹配: 期望 RGB{expected_color}, 实际 RGB{actual_color}",
+ )
)
return False
except Exception:
- self.errors.append(
- PptxValidationError("WARNING", "无法获取字体颜色")
- )
+ self.errors.append(PptxValidationError("WARNING", "无法获取字体颜色"))
return True
- def validate_position(self, shape, expected_left: float, expected_top: float,
- expected_width: Optional[float] = None,
- expected_height: Optional[float] = None) -> bool:
+ def validate_position(
+ self,
+ shape,
+ expected_left: float,
+ expected_top: float,
+ expected_width: Optional[float] = None,
+ expected_height: Optional[float] = None,
+ ) -> bool:
"""
验证元素位置和尺寸
@@ -212,15 +237,17 @@ class PptxFileValidator:
if abs(actual_left - expected_left) > self.TOLERANCE:
self.errors.append(
- PptxValidationError("ERROR",
- f"左边距不匹配: 期望 {expected_left}, 实际 {actual_left}")
+ PptxValidationError(
+ "ERROR", f"左边距不匹配: 期望 {expected_left}, 实际 {actual_left}"
+ )
)
return False
if abs(actual_top - expected_top) > self.TOLERANCE:
self.errors.append(
- PptxValidationError("ERROR",
- f"上边距不匹配: 期望 {expected_top}, 实际 {actual_top}")
+ PptxValidationError(
+ "ERROR", f"上边距不匹配: 期望 {expected_top}, 实际 {actual_top}"
+ )
)
return False
@@ -228,8 +255,10 @@ class PptxFileValidator:
actual_width = shape.width.inches
if abs(actual_width - expected_width) > self.TOLERANCE:
self.errors.append(
- PptxValidationError("ERROR",
- f"宽度不匹配: 期望 {expected_width}, 实际 {actual_width}")
+ PptxValidationError(
+ "ERROR",
+ f"宽度不匹配: 期望 {expected_width}, 实际 {actual_width}",
+ )
)
return False
@@ -237,8 +266,10 @@ class PptxFileValidator:
actual_height = shape.height.inches
if abs(actual_height - expected_height) > self.TOLERANCE:
self.errors.append(
- PptxValidationError("ERROR",
- f"高度不匹配: 期望 {expected_height}, 实际 {actual_height}")
+ PptxValidationError(
+ "ERROR",
+ f"高度不匹配: 期望 {expected_height}, 实际 {actual_height}",
+ )
)
return False
@@ -265,23 +296,21 @@ class PptxFileValidator:
)
if actual_rgb != expected_rgb:
self.errors.append(
- PptxValidationError("ERROR",
- f"背景颜色不匹配: 期望 RGB{expected_rgb}, 实际 RGB{actual_rgb}")
+ PptxValidationError(
+ "ERROR",
+ f"背景颜色不匹配: 期望 RGB{expected_rgb}, 实际 RGB{actual_rgb}",
+ )
)
return False
except Exception as e:
- self.errors.append(
- PptxValidationError("WARNING", f"无法获取背景颜色: {e}")
- )
+ self.errors.append(PptxValidationError("WARNING", f"无法获取背景颜色: {e}"))
return True
def _validate_file_exists(self, pptx_path: Path) -> bool:
"""验证文件存在且大小大于 0"""
if not pptx_path.exists():
- self.errors.append(
- PptxValidationError("ERROR", f"文件不存在: {pptx_path}")
- )
+ self.errors.append(PptxValidationError("ERROR", f"文件不存在: {pptx_path}"))
return False
if pptx_path.stat().st_size == 0:
diff --git a/tests/e2e/test_check_cmd.py b/tests/e2e/test_check_cmd.py
index 33ad8e0..61dd3b2 100644
--- a/tests/e2e/test_check_cmd.py
+++ b/tests/e2e/test_check_cmd.py
@@ -15,13 +15,10 @@ class TestCheckCmd:
def run_check(self, *args):
"""辅助函数:运行 check 命令"""
- cmd = [sys.executable, "-m", "uv", "run", "python", "yaml2pptx.py", "check"]
+ cmd = ["uv", "run", "python", "yaml2pptx.py", "check"]
cmd.extend(args)
result = subprocess.run(
- cmd,
- capture_output=True,
- text=True,
- cwd=Path(__file__).parent.parent.parent
+ cmd, capture_output=True, text=True, cwd=Path(__file__).parent.parent.parent
)
return result
diff --git a/tests/e2e/test_convert_cmd.py b/tests/e2e/test_convert_cmd.py
index 608ebea..dbedef0 100644
--- a/tests/e2e/test_convert_cmd.py
+++ b/tests/e2e/test_convert_cmd.py
@@ -16,13 +16,10 @@ class TestConvertCmd:
def run_convert(self, *args):
"""辅助函数:运行 convert 命令"""
- cmd = [sys.executable, "-m", "uv", "run", "python", "yaml2pptx.py", "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
+ cmd, capture_output=True, text=True, cwd=Path(__file__).parent.parent.parent
)
return result
@@ -37,19 +34,29 @@ class TestConvertCmd:
def test_auto_output_filename(self, sample_yaml, temp_dir):
"""测试自动生成输出文件名"""
- # 在 temp_dir 中运行
+ # sample_yaml 位于 temp_dir 中,转换时输出也会在 temp_dir
+ # 但因为 cwd 是项目根目录,所以输出文件的路径需要计算
+ # 实际上,由于 sample_yaml 使用 tempfile,输出会在 temp_dir 中
result = subprocess.run(
- [sys.executable, "-m", "uv", "run", "python",
- "yaml2pptx.py", "convert", str(sample_yaml)],
+ [
+ "uv",
+ "run",
+ "python",
+ "yaml2pptx.py",
+ "convert",
+ str(sample_yaml),
+ ],
capture_output=True,
text=True,
- cwd=temp_dir
+ cwd=Path(__file__).parent.parent.parent,
)
- assert result.returncode == 0
- # 应该生成与输入同名的 .pptx 文件
+ assert result.returncode == 0, f"Command failed: {result.stderr}"
+ # 应该生成与输入同名的 .pptx 文件(在 temp_dir 中)
expected_output = temp_dir / "test.pptx"
- assert expected_output.exists()
+ assert expected_output.exists(), (
+ f"Expected {expected_output} to exist, but didn't"
+ )
def test_conversion_with_template(self, temp_dir, sample_template):
"""测试使用模板转换"""
@@ -67,9 +74,7 @@ slides:
output = temp_dir / "output.pptx"
result = self.run_convert(
- str(yaml_path),
- str(output),
- "--template-dir", str(sample_template)
+ str(yaml_path), str(output), "--template-dir", str(sample_template)
)
assert result.returncode == 0
@@ -78,11 +83,7 @@ slides:
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"
- )
+ result = self.run_convert(str(sample_yaml), str(output), "--skip-validation")
assert result.returncode == 0
assert output.exists()
@@ -95,11 +96,7 @@ slides:
output.write_text("existing")
# 使用 --force 应该覆盖
- result = self.run_convert(
- str(sample_yaml),
- str(output),
- "--force"
- )
+ result = self.run_convert(str(sample_yaml), str(output), "--force")
assert result.returncode == 0
# 文件应该是有效的 PPTX,不是原来的文本
@@ -129,7 +126,12 @@ slides:
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"
+ fixtures_yaml = (
+ Path(__file__).parent.parent
+ / "fixtures"
+ / "yaml_samples"
+ / "full_features.yaml"
+ )
if not fixtures_yaml.exists():
pytest.skip("full_features.yaml not found")
@@ -158,7 +160,7 @@ slides:
size: 24
"""
yaml_path = temp_dir / "test.yaml"
- yaml_path.write_text(yaml_content, encoding='utf-8')
+ yaml_path.write_text(yaml_content, encoding="utf-8")
output = temp_dir / "output.pptx"
result = self.run_convert(str(yaml_path), str(output))
@@ -174,9 +176,9 @@ slides:
def test_different_slide_sizes(self, temp_dir):
"""测试不同的幻灯片尺寸"""
for size in ["16:9", "4:3"]:
- yaml_content = f"""
+ yaml_content = f'''
metadata:
- size: {size}
+ size: "{size}"
slides:
- elements:
@@ -185,7 +187,7 @@ slides:
content: "Size {size}"
font:
size: 24
-"""
+'''
yaml_path = temp_dir / f"test_{size.replace(':', '')}.yaml"
yaml_path.write_text(yaml_content)
diff --git a/tests/fixtures/images/test_image.png b/tests/fixtures/images/test_image.png
new file mode 100644
index 0000000..e4d133f
Binary files /dev/null and b/tests/fixtures/images/test_image.png differ
diff --git a/tests/fixtures/yaml_samples/full_features.yaml b/tests/fixtures/yaml_samples/full_features.yaml
index 7595b9d..ae7de01 100644
--- a/tests/fixtures/yaml_samples/full_features.yaml
+++ b/tests/fixtures/yaml_samples/full_features.yaml
@@ -28,7 +28,7 @@ slides:
- elements:
- type: image
box: [1, 1, 4, 3]
- src: "test_image.png"
+ src: "../images/test_image.png"
# 形状元素幻灯片
- elements:
diff --git a/tests/integration/test_presentation.py b/tests/integration/test_presentation.py
index fb5d668..86110b3 100644
--- a/tests/integration/test_presentation.py
+++ b/tests/integration/test_presentation.py
@@ -21,7 +21,7 @@ class TestPresentationInit:
def test_init_with_template_dir(self, sample_yaml, sample_template):
"""测试带模板目录初始化"""
pres = Presentation(str(sample_yaml), str(sample_template))
- assert pres.template_dir == sample_template
+ assert pres.templates_dir == str(sample_template)
class TestTemplateCaching:
@@ -86,7 +86,11 @@ slides:
# 模板变量应该被替换
elements = rendered["elements"]
- title_elem = next(e for e in elements if e.get("type") == "text" and "Test Title" in e.get("content", ""))
+ title_elem = next(
+ e
+ for e in elements
+ if e.get("type") == "text" and "Test Title" in e.get("content", "")
+ )
assert title_elem is not None
def test_render_slide_with_conditional_element(self, temp_dir, sample_template):
diff --git a/tests/unit/test_renderers/test_html_renderer.py b/tests/unit/test_renderers/test_html_renderer.py
index d01a915..5eeef6d 100644
--- a/tests/unit/test_renderers/test_html_renderer.py
+++ b/tests/unit/test_renderers/test_html_renderer.py
@@ -32,7 +32,7 @@ class TestRenderText:
elem = TextElement(
content="Test Content",
box=[1, 2, 3, 0.5],
- font={"size": 18, "color": "#333333"}
+ font={"size": 18, "color": "#333333"},
)
html = renderer.render_text(elem)
@@ -48,9 +48,7 @@ class TestRenderText:
"""测试渲染粗体文本"""
renderer = HtmlRenderer()
elem = TextElement(
- content="Bold Text",
- box=[0, 0, 1, 1],
- font={"size": 16, "bold": True}
+ content="Bold Text", box=[0, 0, 1, 1], font={"size": 16, "bold": True}
)
html = renderer.render_text(elem)
@@ -61,9 +59,7 @@ class TestRenderText:
"""测试渲染斜体文本"""
renderer = HtmlRenderer()
elem = TextElement(
- content="Italic Text",
- box=[0, 0, 1, 1],
- font={"size": 16, "italic": True}
+ content="Italic Text", box=[0, 0, 1, 1], font={"size": 16, "italic": True}
)
html = renderer.render_text(elem)
@@ -74,9 +70,7 @@ class TestRenderText:
"""测试渲染居中对齐文本"""
renderer = HtmlRenderer()
elem = TextElement(
- content="Centered",
- box=[0, 0, 1, 1],
- font={"align": "center"}
+ content="Centered", box=[0, 0, 1, 1], font={"align": "center"}
)
html = renderer.render_text(elem)
@@ -87,9 +81,7 @@ class TestRenderText:
"""测试渲染右对齐文本"""
renderer = HtmlRenderer()
elem = TextElement(
- content="Right Aligned",
- box=[0, 0, 1, 1],
- font={"align": "right"}
+ content="Right Aligned", box=[0, 0, 1, 1], font={"align": "right"}
)
html = renderer.render_text(elem)
@@ -99,11 +91,7 @@ class TestRenderText:
def test_render_text_with_default_align(self):
"""测试默认左对齐"""
renderer = HtmlRenderer()
- elem = TextElement(
- content="Default",
- box=[0, 0, 1, 1],
- font={}
- )
+ elem = TextElement(content="Default", box=[0, 0, 1, 1], font={})
html = renderer.render_text(elem)
@@ -113,9 +101,7 @@ class TestRenderText:
"""测试 HTML 特殊字符转义"""
renderer = HtmlRenderer()
elem = TextElement(
- content="",
- box=[0, 0, 1, 1],
- font={}
+ content="", box=[0, 0, 1, 1], font={}
)
html = renderer.render_text(elem)
@@ -127,11 +113,7 @@ class TestRenderText:
def test_render_text_with_special_characters(self):
"""测试特殊字符处理"""
renderer = HtmlRenderer()
- elem = TextElement(
- content="Test & < > \" '",
- box=[0, 0, 1, 1],
- font={}
- )
+ elem = TextElement(content="Test & < > \" '", box=[0, 0, 1, 1], font={})
html = renderer.render_text(elem)
@@ -143,24 +125,18 @@ class TestRenderText:
"""测试长文本内容"""
renderer = HtmlRenderer()
long_content = "A" * 500
- elem = TextElement(
- content=long_content,
- box=[0, 0, 5, 1],
- font={"size": 12}
- )
+ elem = TextElement(content=long_content, box=[0, 0, 5, 1], font={"size": 12})
html = renderer.render_text(elem)
assert long_content in html
- assert "word-wrap: break-word" in html
+ assert "overflow-wrap: break-word" in html
def test_render_text_with_newlines(self):
"""测试包含换行符的文本"""
renderer = HtmlRenderer()
elem = TextElement(
- content="Line 1\nLine 2\nLine 3",
- box=[0, 0, 5, 2],
- font={"size": 14}
+ content="Line 1\nLine 2\nLine 3", box=[0, 0, 5, 2], font={"size": 14}
)
html = renderer.render_text(elem)
@@ -172,11 +148,7 @@ class TestRenderText:
def test_render_text_with_unicode(self):
"""测试 Unicode 字符"""
renderer = HtmlRenderer()
- elem = TextElement(
- content="测试中文 🌍",
- box=[0, 0, 5, 1],
- font={"size": 16}
- )
+ elem = TextElement(content="测试中文 🌍", box=[0, 0, 5, 1], font={"size": 16})
html = renderer.render_text(elem)
@@ -186,11 +158,7 @@ class TestRenderText:
def test_render_text_with_empty_font(self):
"""测试空字体属性"""
renderer = HtmlRenderer()
- elem = TextElement(
- content="Test",
- box=[0, 0, 1, 1],
- font={}
- )
+ elem = TextElement(content="Test", box=[0, 0, 1, 1], font={})
html = renderer.render_text(elem)
@@ -205,11 +173,7 @@ class TestRenderShape:
def test_render_rectangle(self):
"""测试渲染矩形"""
renderer = HtmlRenderer()
- elem = ShapeElement(
- box=[1, 1, 2, 1],
- shape="rectangle",
- fill="#4a90e2"
- )
+ elem = ShapeElement(box=[1, 1, 2, 1], shape="rectangle", fill="#4a90e2")
html = renderer.render_shape(elem)
@@ -220,11 +184,7 @@ class TestRenderShape:
def test_render_ellipse(self):
"""测试渲染椭圆"""
renderer = HtmlRenderer()
- elem = ShapeElement(
- box=[1, 1, 2, 2],
- shape="ellipse",
- fill="#e24a4a"
- )
+ elem = ShapeElement(box=[1, 1, 2, 2], shape="ellipse", fill="#e24a4a")
html = renderer.render_shape(elem)
@@ -234,11 +194,7 @@ class TestRenderShape:
def test_render_rounded_rectangle(self):
"""测试渲染圆角矩形"""
renderer = HtmlRenderer()
- elem = ShapeElement(
- box=[1, 1, 2, 1],
- shape="rounded_rectangle",
- fill="#4ae290"
- )
+ elem = ShapeElement(box=[1, 1, 2, 1], shape="rounded_rectangle", fill="#4ae290")
html = renderer.render_shape(elem)
@@ -248,11 +204,7 @@ class TestRenderShape:
def test_render_shape_without_fill(self):
"""测试无填充颜色的形状"""
renderer = HtmlRenderer()
- elem = ShapeElement(
- box=[1, 1, 2, 1],
- shape="rectangle",
- fill=None
- )
+ elem = ShapeElement(box=[1, 1, 2, 1], shape="rectangle", fill=None)
html = renderer.render_shape(elem)
@@ -265,7 +217,7 @@ class TestRenderShape:
box=[1, 1, 2, 1],
shape="rectangle",
fill="#4a90e2",
- line={"color": "#000000", "width": 2}
+ line={"color": "#000000", "width": 2},
)
html = renderer.render_shape(elem)
@@ -279,7 +231,7 @@ class TestRenderShape:
box=[1, 1, 2, 1],
shape="rectangle",
fill="#4a90e2",
- line={"color": "#000000"}
+ line={"color": "#000000"},
)
html = renderer.render_shape(elem)
@@ -289,11 +241,7 @@ class TestRenderShape:
def test_render_shape_without_line(self):
"""测试无边框的形状"""
renderer = HtmlRenderer()
- elem = ShapeElement(
- box=[1, 1, 2, 1],
- shape="rectangle",
- fill="#4a90e2"
- )
+ elem = ShapeElement(box=[1, 1, 2, 1], shape="rectangle", fill="#4a90e2")
html = renderer.render_shape(elem)
@@ -302,22 +250,18 @@ class TestRenderShape:
def test_render_shape_position(self):
"""测试形状位置计算"""
renderer = HtmlRenderer()
- elem = ShapeElement(
- box=[1.5, 2.5, 3, 1.5],
- shape="rectangle",
- fill="#000000"
- )
+ elem = ShapeElement(box=[1.5, 2.5, 3, 1.5], shape="rectangle", fill="#000000")
html = renderer.render_shape(elem)
# 1.5 * 96 = 144
- assert "left: 144px" in html
+ assert "left: 144" in html
# 2.5 * 96 = 240
- assert "top: 240px" in html
+ assert "top: 240" in html
# 3 * 96 = 288
- assert "width: 288px" in html
+ assert "width: 288" in html
# 1.5 * 96 = 144
- assert "height: 144px" in html
+ assert "height: 144" in html
class TestRenderTable:
@@ -330,7 +274,7 @@ class TestRenderTable:
position=[1, 1],
col_widths=[2, 2, 2],
data=[["A", "B", "C"], ["1", "2", "3"]],
- style={}
+ style={},
)
html = renderer.render_table(elem)
@@ -350,11 +294,7 @@ class TestRenderTable:
position=[1, 1],
col_widths=[2, 2],
data=[["H1", "H2"], ["D1", "D2"]],
- style={
- "font_size": 14,
- "header_bg": "#4a90e2",
- "header_color": "#ffffff"
- }
+ style={"font_size": 14, "header_bg": "#4a90e2", "header_color": "#ffffff"},
)
html = renderer.render_table(elem)
@@ -367,10 +307,7 @@ class TestRenderTable:
"""测试表格位置"""
renderer = HtmlRenderer()
elem = TableElement(
- position=[2, 3],
- col_widths=[1, 1],
- data=[["A", "B"]],
- style={}
+ position=[2, 3], col_widths=[1, 1], data=[["A", "B"]], style={}
)
html = renderer.render_table(elem)
@@ -383,12 +320,7 @@ class TestRenderTable:
def test_render_table_with_default_font_size(self):
"""测试默认字体大小"""
renderer = HtmlRenderer()
- elem = TableElement(
- position=[0, 0],
- col_widths=[1],
- data=[["Cell"]],
- style={}
- )
+ elem = TableElement(position=[0, 0], col_widths=[1], data=[["Cell"]], style={})
html = renderer.render_table(elem)
@@ -398,10 +330,7 @@ class TestRenderTable:
"""测试表格内容转义"""
renderer = HtmlRenderer()
elem = TableElement(
- position=[0, 0],
- col_widths=[1],
- data=[["