feat: 实现幻灯片备注功能,将description写入PPT备注页
- 添加 PptxGenerator._set_notes() 方法设置备注 - 在 add_slide() 中调用 _set_notes() 处理 description - 仅幻灯片级别的 description 写入备注,不继承模板 - 添加备注功能测试用例(8个测试) - 更新 README.md 和 README_DEV.md 文档 - 新建 pptx-slide-notes spec - 更新 page-description spec 允许写入备注 - 归档 add-slide-notes 变更
This commit is contained in:
@@ -540,3 +540,158 @@ class TestRenderBackground:
|
||||
|
||||
# 不应该崩溃
|
||||
gen._render_background(mock_slide, None)
|
||||
|
||||
|
||||
class TestSetNotes:
|
||||
"""_set_notes 方法测试类"""
|
||||
|
||||
@patch("renderers.pptx_renderer.PptxPresentation")
|
||||
def test_set_notes_with_text(self, mock_prs_class):
|
||||
"""测试设置备注文本"""
|
||||
mock_slide = Mock()
|
||||
mock_notes_slide = Mock()
|
||||
mock_text_frame = Mock()
|
||||
mock_notes_slide.notes_text_frame = mock_text_frame
|
||||
mock_slide.notes_slide = mock_notes_slide
|
||||
mock_prs_class.return_value = Mock()
|
||||
mock_prs_class.return_value.slide_layouts = [None] * 7 + [Mock()]
|
||||
mock_prs_class.return_value.slides.add_slide.return_value = mock_slide
|
||||
|
||||
gen = PptxGenerator()
|
||||
|
||||
gen._set_notes(mock_slide, "这是演讲备注内容")
|
||||
|
||||
# 验证备注被设置
|
||||
mock_text_frame.text = "这是演讲备注内容"
|
||||
|
||||
@patch("renderers.pptx_renderer.PptxPresentation")
|
||||
def test_set_notes_with_none(self, mock_prs_class):
|
||||
"""测试设置 None 不设置备注"""
|
||||
mock_slide = Mock(spec=[]) # 使用 spec=[] 禁止自动创建属性
|
||||
mock_prs_class.return_value = Mock()
|
||||
mock_prs_class.return_value.slide_layouts = [None] * 7 + [Mock()]
|
||||
mock_prs_class.return_value.slides.add_slide.return_value = mock_slide
|
||||
|
||||
gen = PptxGenerator()
|
||||
|
||||
# 不应该崩溃,不应该访问 notes_slide
|
||||
gen._set_notes(mock_slide, None)
|
||||
# 使用 spec=[] 后,访问不存在的属性会抛出 AttributeError
|
||||
# 如果没有抛出异常,说明 notes_slide 没有被访问
|
||||
|
||||
@patch("renderers.pptx_renderer.PptxPresentation")
|
||||
def test_set_notes_with_empty_string(self, mock_prs_class):
|
||||
"""测试设置空字符串"""
|
||||
mock_slide = Mock()
|
||||
mock_notes_slide = Mock()
|
||||
mock_text_frame = Mock()
|
||||
mock_notes_slide.notes_text_frame = mock_text_frame
|
||||
mock_slide.notes_slide = mock_notes_slide
|
||||
mock_prs_class.return_value = Mock()
|
||||
mock_prs_class.return_value.slide_layouts = [None] * 7 + [Mock()]
|
||||
mock_prs_class.return_value.slides.add_slide.return_value = mock_slide
|
||||
|
||||
gen = PptxGenerator()
|
||||
|
||||
gen._set_notes(mock_slide, "")
|
||||
|
||||
# 验证空字符串也被设置
|
||||
mock_text_frame.text = ""
|
||||
|
||||
@patch("renderers.pptx_renderer.PptxPresentation")
|
||||
def test_set_notes_with_multiline_text(self, mock_prs_class):
|
||||
"""测试设置多行文本"""
|
||||
mock_slide = Mock()
|
||||
mock_notes_slide = Mock()
|
||||
mock_text_frame = Mock()
|
||||
mock_notes_slide.notes_text_frame = mock_text_frame
|
||||
mock_slide.notes_slide = mock_notes_slide
|
||||
mock_prs_class.return_value = Mock()
|
||||
mock_prs_class.return_value.slide_layouts = [None] * 7 + [Mock()]
|
||||
mock_prs_class.return_value.slides.add_slide.return_value = mock_slide
|
||||
|
||||
gen = PptxGenerator()
|
||||
|
||||
multiline_text = "第一行备注\n第二行备注\n第三行备注"
|
||||
gen._set_notes(mock_slide, multiline_text)
|
||||
|
||||
# 验证多行文本被设置
|
||||
mock_text_frame.text = multiline_text
|
||||
|
||||
@patch("renderers.pptx_renderer.PptxPresentation")
|
||||
def test_set_notes_with_chinese_text(self, mock_prs_class):
|
||||
"""测试设置中文备注"""
|
||||
mock_slide = Mock()
|
||||
mock_notes_slide = Mock()
|
||||
mock_text_frame = Mock()
|
||||
mock_notes_slide.notes_text_frame = mock_text_frame
|
||||
mock_slide.notes_slide = mock_notes_slide
|
||||
mock_prs_class.return_value = Mock()
|
||||
mock_prs_class.return_value.slide_layouts = [None] * 7 + [Mock()]
|
||||
mock_prs_class.return_value.slides.add_slide.return_value = mock_slide
|
||||
|
||||
gen = PptxGenerator()
|
||||
|
||||
chinese_text = "这是中文演讲备注内容,用于演示时参考"
|
||||
gen._set_notes(mock_slide, chinese_text)
|
||||
|
||||
# 验证中文文本被设置
|
||||
mock_text_frame.text = chinese_text
|
||||
|
||||
|
||||
class TestAddSlideWithNotes:
|
||||
"""add_slide 方法备注功能测试类"""
|
||||
|
||||
@patch("renderers.pptx_renderer.PptxPresentation")
|
||||
def test_add_slide_with_description_sets_notes(self, mock_prs_class):
|
||||
"""测试幻灯片包含 description 时设置备注"""
|
||||
mock_slide = Mock()
|
||||
mock_notes_slide = Mock()
|
||||
mock_text_frame = Mock()
|
||||
mock_notes_slide.notes_text_frame = mock_text_frame
|
||||
mock_slide.notes_slide = mock_notes_slide
|
||||
mock_prs = Mock()
|
||||
mock_prs.slide_layouts = [None] * 6 + [Mock()] + [None]
|
||||
mock_prs.slides.add_slide.return_value = mock_slide
|
||||
mock_prs_class.return_value = mock_prs
|
||||
|
||||
gen = PptxGenerator()
|
||||
slide_data = {"background": None, "elements": [], "description": "这是幻灯片的演讲说明"}
|
||||
|
||||
gen.add_slide(slide_data)
|
||||
|
||||
# 验证备注被设置
|
||||
mock_text_frame.text = "这是幻灯片的演讲说明"
|
||||
|
||||
@patch("renderers.pptx_renderer.PptxPresentation")
|
||||
def test_add_slide_without_description_no_notes(self, mock_prs_class):
|
||||
"""测试幻灯片不包含 description 时不设置备注"""
|
||||
mock_slide = Mock(spec=[]) # 禁止自动创建属性
|
||||
mock_prs = Mock()
|
||||
mock_prs.slide_layouts = [None] * 6 + [Mock()] + [None]
|
||||
mock_prs.slides.add_slide.return_value = mock_slide
|
||||
mock_prs_class.return_value = mock_prs
|
||||
|
||||
gen = PptxGenerator()
|
||||
slide_data = {"background": None, "elements": []}
|
||||
|
||||
gen.add_slide(slide_data)
|
||||
|
||||
# 不应该访问 notes_slide(使用 spec=[] 会抛出异常如果被访问)
|
||||
|
||||
@patch("renderers.pptx_renderer.PptxPresentation")
|
||||
def test_add_slide_with_template_description_ignored(self, mock_prs_class):
|
||||
"""测试模板的 description 不被用作备注(仅幻灯片自己的 description 有效)"""
|
||||
mock_slide = Mock(spec=[]) # 禁止自动创建属性
|
||||
mock_prs = Mock()
|
||||
mock_prs.slide_layouts = [None] * 6 + [Mock()] + [None]
|
||||
mock_prs.slides.add_slide.return_value = mock_slide
|
||||
mock_prs_class.return_value = mock_prs
|
||||
|
||||
gen = PptxGenerator()
|
||||
# 幻灯片没有 description,则不设置备注(即使模板可能有 description)
|
||||
slide_data = {"background": None, "elements": []}
|
||||
|
||||
gen.add_slide(slide_data)
|
||||
|
||||
# 不应该访问 notes_slide(使用 spec=[] 会抛出异常如果被访问)
|
||||
|
||||
Reference in New Issue
Block a user