PlanOpticon

planopticon / tests / test_rendering.py
Blame History Raw 256 lines
1
"""Tests for rendering and export utilities."""
2
3
from unittest.mock import patch
4
5
from video_processor.models import (
6
ActionItem,
7
DiagramResult,
8
DiagramType,
9
KeyPoint,
10
ProcessingStats,
11
VideoManifest,
12
VideoMetadata,
13
)
14
from video_processor.utils.rendering import render_mermaid, reproduce_chart
15
16
17
class TestRenderMermaid:
18
def test_writes_mermaid_source(self, tmp_path):
19
code = "graph LR\n A-->B"
20
result = render_mermaid(code, tmp_path, "test_diagram")
21
assert "mermaid" in result
22
assert result["mermaid"].exists()
23
assert result["mermaid"].read_text() == code
24
25
def test_source_file_named_correctly(self, tmp_path):
26
result = render_mermaid("graph TD\n X-->Y", tmp_path, "my_chart")
27
assert result["mermaid"].name == "my_chart.mermaid"
28
29
@patch("video_processor.utils.rendering.mmd", create=True)
30
def test_svg_png_on_import_error(self, mock_mmd, tmp_path):
31
"""When mermaid-py is not installed, only source is written."""
32
# Simulate import error by using the real code path
33
# (mermaid-py may or may not be installed in test env)
34
result = render_mermaid("graph LR\n A-->B", tmp_path, "test")
35
# At minimum, mermaid source should always be written
36
assert "mermaid" in result
37
assert result["mermaid"].exists()
38
39
def test_creates_output_dir(self, tmp_path):
40
nested = tmp_path / "a" / "b"
41
result = render_mermaid("graph LR\n A-->B", nested, "test")
42
assert nested.exists()
43
assert result["mermaid"].exists()
44
45
46
class TestReproduceChart:
47
def test_bar_chart(self, tmp_path):
48
data = {
49
"labels": ["A", "B", "C"],
50
"values": [10, 20, 30],
51
"chart_type": "bar",
52
}
53
result = reproduce_chart(data, tmp_path, "test")
54
assert "svg" in result
55
assert "png" in result
56
assert result["svg"].exists()
57
assert result["png"].exists()
58
assert result["svg"].suffix == ".svg"
59
assert result["png"].suffix == ".png"
60
61
def test_line_chart(self, tmp_path):
62
data = {
63
"labels": ["Jan", "Feb", "Mar"],
64
"values": [5, 15, 10],
65
"chart_type": "line",
66
}
67
result = reproduce_chart(data, tmp_path, "line_test")
68
assert "svg" in result
69
assert result["svg"].exists()
70
71
def test_pie_chart(self, tmp_path):
72
data = {
73
"labels": ["Dogs", "Cats"],
74
"values": [60, 40],
75
"chart_type": "pie",
76
}
77
result = reproduce_chart(data, tmp_path, "pie_test")
78
assert "svg" in result
79
80
def test_scatter_chart(self, tmp_path):
81
data = {
82
"labels": ["X1", "X2", "X3"],
83
"values": [1, 4, 9],
84
"chart_type": "scatter",
85
}
86
result = reproduce_chart(data, tmp_path, "scatter_test")
87
assert "svg" in result
88
89
def test_empty_data_returns_empty(self, tmp_path):
90
data = {"labels": [], "values": [], "chart_type": "bar"}
91
result = reproduce_chart(data, tmp_path, "empty")
92
assert result == {}
93
94
def test_missing_values_returns_empty(self, tmp_path):
95
data = {"labels": ["A", "B"]}
96
result = reproduce_chart(data, tmp_path, "no_vals")
97
assert result == {}
98
99
def test_creates_output_dir(self, tmp_path):
100
nested = tmp_path / "charts" / "output"
101
data = {"labels": ["A"], "values": [1], "chart_type": "bar"}
102
reproduce_chart(data, nested, "test")
103
assert nested.exists()
104
105
106
class TestExportAllFormats:
107
def _make_manifest(self) -> VideoManifest:
108
return VideoManifest(
109
video=VideoMetadata(title="Test Video"),
110
stats=ProcessingStats(frames_extracted=5, diagrams_detected=1),
111
analysis_md="results/analysis.md",
112
key_points=[KeyPoint(point="Important finding")],
113
action_items=[ActionItem(action="Follow up", assignee="Alice")],
114
diagrams=[
115
DiagramResult(
116
frame_index=0,
117
diagram_type=DiagramType.flowchart,
118
confidence=0.9,
119
description="Login flow",
120
mermaid="graph LR\n Login-->Dashboard",
121
image_path="diagrams/diagram_0.jpg",
122
),
123
],
124
)
125
126
def test_export_renders_mermaid(self, tmp_path):
127
from video_processor.utils.export import export_all_formats
128
129
manifest = self._make_manifest()
130
131
# Create required dirs and files
132
(tmp_path / "results").mkdir()
133
(tmp_path / "results" / "analysis.md").write_text("# Test\nContent")
134
(tmp_path / "diagrams").mkdir()
135
(tmp_path / "diagrams" / "diagram_0.jpg").write_bytes(b"\xff\xd8\xff")
136
137
result = export_all_formats(tmp_path, manifest)
138
139
# Mermaid source should be written
140
assert (tmp_path / "diagrams" / "diagram_0.mermaid").exists()
141
# Manifest should be updated
142
assert result.diagrams[0].mermaid_path is not None
143
144
def test_export_generates_html(self, tmp_path):
145
from video_processor.utils.export import export_all_formats
146
147
manifest = self._make_manifest()
148
(tmp_path / "results").mkdir()
149
(tmp_path / "results" / "analysis.md").write_text("# Test")
150
(tmp_path / "diagrams").mkdir()
151
152
result = export_all_formats(tmp_path, manifest)
153
assert result.analysis_html is not None
154
html_path = tmp_path / result.analysis_html
155
assert html_path.exists()
156
html_content = html_path.read_text()
157
assert "Test Video" in html_content
158
assert "mermaid" in html_content.lower()
159
160
def test_export_with_chart_data(self, tmp_path):
161
from video_processor.utils.export import export_all_formats
162
163
manifest = VideoManifest(
164
video=VideoMetadata(title="Chart Test"),
165
diagrams=[
166
DiagramResult(
167
frame_index=0,
168
diagram_type=DiagramType.chart,
169
confidence=0.9,
170
chart_data={
171
"labels": ["Q1", "Q2", "Q3"],
172
"values": [100, 200, 150],
173
"chart_type": "bar",
174
},
175
),
176
],
177
)
178
(tmp_path / "results").mkdir()
179
(tmp_path / "diagrams").mkdir()
180
181
export_all_formats(tmp_path, manifest)
182
# Chart should be reproduced
183
chart_svg = tmp_path / "diagrams" / "diagram_0_chart.svg"
184
assert chart_svg.exists()
185
186
187
class TestGenerateHtmlReport:
188
def test_html_contains_title(self, tmp_path):
189
from video_processor.utils.export import generate_html_report
190
191
manifest = VideoManifest(
192
video=VideoMetadata(title="My Meeting"),
193
analysis_md="results/analysis.md",
194
)
195
(tmp_path / "results").mkdir()
196
(tmp_path / "results" / "analysis.md").write_text("# My Meeting\nNotes here.")
197
198
path = generate_html_report(manifest, tmp_path)
199
assert path is not None
200
content = path.read_text()
201
assert "My Meeting" in content
202
203
def test_html_includes_key_points(self, tmp_path):
204
from video_processor.utils.export import generate_html_report
205
206
manifest = VideoManifest(
207
video=VideoMetadata(title="Test"),
208
key_points=[
209
KeyPoint(point="First point", details="Detail 1"),
210
KeyPoint(point="Second point"),
211
],
212
)
213
(tmp_path / "results").mkdir()
214
215
path = generate_html_report(manifest, tmp_path)
216
content = path.read_text()
217
assert "First point" in content
218
assert "Detail 1" in content
219
assert "Second point" in content
220
221
def test_html_includes_action_items(self, tmp_path):
222
from video_processor.utils.export import generate_html_report
223
224
manifest = VideoManifest(
225
video=VideoMetadata(title="Test"),
226
action_items=[
227
ActionItem(action="Do the thing", assignee="Bob", deadline="Friday"),
228
],
229
)
230
(tmp_path / "results").mkdir()
231
232
path = generate_html_report(manifest, tmp_path)
233
content = path.read_text()
234
assert "Do the thing" in content
235
assert "Bob" in content
236
assert "Friday" in content
237
238
def test_html_includes_mermaid_js(self, tmp_path):
239
from video_processor.utils.export import generate_html_report
240
241
manifest = VideoManifest(
242
video=VideoMetadata(title="Test"),
243
diagrams=[
244
DiagramResult(
245
frame_index=0,
246
mermaid="graph LR\n A-->B",
247
)
248
],
249
)
250
(tmp_path / "results").mkdir()
251
252
path = generate_html_report(manifest, tmp_path)
253
content = path.read_text()
254
assert "mermaid" in content
255
assert "A-->B" in content
256

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button