|
12 | 12 | Slide text, notes, and layout come from the core PPTX converter. |
13 | 13 | """ |
14 | 14 |
|
| 15 | +import io |
15 | 16 | import sys |
16 | 17 | from pathlib import Path |
17 | 18 | from typing import Any |
18 | 19 |
|
19 | 20 | import pytest |
| 21 | +from pptx import Presentation |
| 22 | +from pptx.chart.data import CategoryChartData |
| 23 | +from pptx.enum.chart import XL_CHART_TYPE |
| 24 | +from pptx.util import Inches |
20 | 25 |
|
21 | 26 | sys.path.insert(0, str(Path(__file__).parent.parent / "src")) |
22 | 27 |
|
@@ -138,54 +143,45 @@ def test_pptx_no_ocr_service_no_tags() -> None: |
138 | 143 | assert "[End OCR]*" not in md |
139 | 144 |
|
140 | 145 |
|
141 | | -def test_pptx_ocr_chart_no_title_text_frame() -> None: |
142 | | - from unittest.mock import MagicMock |
143 | | - from markitdown_ocr._pptx_converter_with_ocr import PptxConverterWithOCR |
144 | | - |
145 | | - # python-pptx's ChartTitle.text_frame is destructive -- it creates a text |
146 | | - # frame if one isn't already present, so it never returns None. |
147 | | - # has_text_frame is the property that actually reflects presence/absence. |
148 | | - mock_chart = MagicMock() |
149 | | - mock_chart.has_title = True |
150 | | - mock_chart.chart_title.has_text_frame = False |
151 | | - |
152 | | - mock_category = MagicMock() |
153 | | - mock_category.label = "Cat 1" |
154 | | - mock_chart.plots = [MagicMock(categories=[mock_category])] |
155 | | - |
156 | | - mock_series = MagicMock() |
157 | | - mock_series.name = "Series 1" |
158 | | - mock_series.values = [10.0] |
159 | | - mock_chart.series = [mock_series] |
160 | | - |
| 146 | +def _chart_presentation(title: str | None) -> io.BytesIO: |
| 147 | + # Modify an in-memory copy of an existing deck; keep its fixture intact. |
| 148 | + presentation = Presentation(TEST_DATA_DIR / "pptx_image_middle.pptx") |
| 149 | + slide = presentation.slides.add_slide(presentation.slide_layouts[6]) |
| 150 | + data = CategoryChartData() |
| 151 | + data.categories = ["Cat 1"] |
| 152 | + data.add_series("Series 1", [10.0]) |
| 153 | + chart = slide.shapes.add_chart( |
| 154 | + XL_CHART_TYPE.COLUMN_CLUSTERED, |
| 155 | + Inches(1), |
| 156 | + Inches(1), |
| 157 | + Inches(5), |
| 158 | + Inches(3), |
| 159 | + data, |
| 160 | + ).chart |
| 161 | + chart.has_title = True |
| 162 | + if title is not None: |
| 163 | + chart.chart_title.text_frame.text = title |
| 164 | + assert chart.chart_title.has_text_frame is (title is not None) |
| 165 | + stream = io.BytesIO() |
| 166 | + presentation.save(stream) |
| 167 | + stream.seek(0) |
| 168 | + return stream |
| 169 | + |
| 170 | + |
| 171 | +@pytest.mark.parametrize("title", [None, "Revenue"]) |
| 172 | +def test_pptx_ocr_chart_title_text_frame(title: str | None) -> None: |
| 173 | + stream = _chart_presentation(title) |
| 174 | + # Reload the serialized package so the real parser reads title XML. |
| 175 | + chart = Presentation(stream).slides[-1].shapes[-1].chart |
161 | 176 | converter = PptxConverterWithOCR() |
162 | | - result = converter._convert_chart_to_markdown(mock_chart) |
163 | | - |
164 | | - assert "### Chart" in result |
| 177 | + result = converter._convert_chart_to_markdown(chart) |
| 178 | + heading = "### Chart" if title is None else "### Chart: Revenue" |
| 179 | + assert result.strip().splitlines()[0] == heading |
165 | 180 | assert "Cat 1" in result |
166 | 181 | assert "Series 1" in result |
167 | | - assert ":" not in result |
168 | | - |
169 | | - |
170 | | -def test_pptx_ocr_chart_with_title_text_frame() -> None: |
171 | | - from unittest.mock import MagicMock |
172 | | - from markitdown_ocr._pptx_converter_with_ocr import PptxConverterWithOCR |
173 | | - |
174 | | - mock_chart = MagicMock() |
175 | | - mock_chart.has_title = True |
176 | | - mock_chart.chart_title.has_text_frame = True |
177 | | - mock_chart.chart_title.text_frame.text = "Revenue" |
178 | | - |
179 | | - mock_category = MagicMock() |
180 | | - mock_category.label = "Cat 1" |
181 | | - mock_chart.plots = [MagicMock(categories=[mock_category])] |
182 | | - |
183 | | - mock_series = MagicMock() |
184 | | - mock_series.name = "Series 1" |
185 | | - mock_series.values = [10.0] |
186 | | - mock_chart.series = [mock_series] |
187 | | - |
188 | | - converter = PptxConverterWithOCR() |
189 | | - result = converter._convert_chart_to_markdown(mock_chart) |
190 | | - |
191 | | - assert "### Chart: Revenue" in result |
| 182 | + assert "10.0" in result |
| 183 | + # Accessing a title without a text frame must not create one. |
| 184 | + assert chart.chart_title.has_text_frame is (title is not None) |
| 185 | + stream.seek(0) |
| 186 | + markdown = converter.convert(stream, StreamInfo(extension=".pptx")).markdown |
| 187 | + assert result.strip() in markdown |
0 commit comments