PlanOpticon

planopticon / tests / test_output_formatter.py
Source Blame History 275 lines
0981a08… noreply 1 """Tests for video_processor.cli.output_formatter.OutputFormatter."""
0981a08… noreply 2
0981a08… noreply 3 from pathlib import Path
0981a08… noreply 4
0981a08… noreply 5 import pytest
0981a08… noreply 6
0981a08… noreply 7 from video_processor.cli.output_formatter import OutputFormatter
0981a08… noreply 8
0981a08… noreply 9
0981a08… noreply 10 @pytest.fixture()
0981a08… noreply 11 def tmp_dir(tmp_path):
0981a08… noreply 12 """Return a fresh temp directory that is cleaned up automatically."""
0981a08… noreply 13 return tmp_path
0981a08… noreply 14
0981a08… noreply 15
0981a08… noreply 16 @pytest.fixture()
0981a08… noreply 17 def formatter(tmp_dir):
0981a08… noreply 18 """Return an OutputFormatter pointed at a temp output directory."""
0981a08… noreply 19 return OutputFormatter(tmp_dir / "output")
0981a08… noreply 20
0981a08… noreply 21
0981a08… noreply 22 # --- Constructor ---
0981a08… noreply 23
0981a08… noreply 24
0981a08… noreply 25 def test_constructor_creates_output_dir(tmp_dir):
0981a08… noreply 26 out = tmp_dir / "new_output"
0981a08… noreply 27 assert not out.exists()
0981a08… noreply 28 OutputFormatter(out)
0981a08… noreply 29 assert out.is_dir()
0981a08… noreply 30
0981a08… noreply 31
0981a08… noreply 32 def test_constructor_accepts_string(tmp_dir):
0981a08… noreply 33 fmt = OutputFormatter(str(tmp_dir / "str_output"))
0981a08… noreply 34 assert fmt.output_dir.is_dir()
0981a08… noreply 35
0981a08… noreply 36
0981a08… noreply 37 # --- organize_outputs ---
0981a08… noreply 38
0981a08… noreply 39
0981a08… noreply 40 def _create_file(path: Path, content: str = "test") -> Path:
0981a08… noreply 41 path.parent.mkdir(parents=True, exist_ok=True)
0981a08… noreply 42 path.write_text(content)
0981a08… noreply 43 return path
0981a08… noreply 44
0981a08… noreply 45
0981a08… noreply 46 def test_organize_outputs_basic(formatter, tmp_dir):
0981a08… noreply 47 md = _create_file(tmp_dir / "analysis.md", "# Title")
0981a08… noreply 48 kg = _create_file(tmp_dir / "kg.json", "{}")
0981a08… noreply 49
0981a08… noreply 50 result = formatter.organize_outputs(
0981a08… noreply 51 markdown_path=md,
0981a08… noreply 52 knowledge_graph_path=kg,
0981a08… noreply 53 diagrams=[],
0981a08… noreply 54 )
0981a08… noreply 55
0981a08… noreply 56 assert "markdown" in result
0981a08… noreply 57 assert "knowledge_graph" in result
0981a08… noreply 58 assert Path(result["markdown"]).exists()
0981a08… noreply 59 assert Path(result["knowledge_graph"]).exists()
0981a08… noreply 60 assert result["diagram_images"] == []
0981a08… noreply 61 assert result["frames"] == []
0981a08… noreply 62 assert result["transcript"] is None
0981a08… noreply 63
0981a08… noreply 64
0981a08… noreply 65 def test_organize_outputs_with_transcript(formatter, tmp_dir):
0981a08… noreply 66 md = _create_file(tmp_dir / "analysis.md")
0981a08… noreply 67 kg = _create_file(tmp_dir / "kg.json")
0981a08… noreply 68 transcript = _create_file(tmp_dir / "transcript.txt", "Hello world")
0981a08… noreply 69
0981a08… noreply 70 result = formatter.organize_outputs(
0981a08… noreply 71 markdown_path=md,
0981a08… noreply 72 knowledge_graph_path=kg,
0981a08… noreply 73 diagrams=[],
0981a08… noreply 74 transcript_path=transcript,
0981a08… noreply 75 )
0981a08… noreply 76
0981a08… noreply 77 assert result["transcript"] is not None
0981a08… noreply 78 assert Path(result["transcript"]).exists()
0981a08… noreply 79
0981a08… noreply 80
0981a08… noreply 81 def test_organize_outputs_with_diagrams(formatter, tmp_dir):
0981a08… noreply 82 md = _create_file(tmp_dir / "analysis.md")
0981a08… noreply 83 kg = _create_file(tmp_dir / "kg.json")
0981a08… noreply 84 img = _create_file(tmp_dir / "diagram1.png", "fake-png")
0981a08… noreply 85
0981a08… noreply 86 result = formatter.organize_outputs(
0981a08… noreply 87 markdown_path=md,
0981a08… noreply 88 knowledge_graph_path=kg,
0981a08… noreply 89 diagrams=[{"image_path": str(img)}],
0981a08… noreply 90 )
0981a08… noreply 91
0981a08… noreply 92 assert len(result["diagram_images"]) == 1
0981a08… noreply 93 assert Path(result["diagram_images"][0]).exists()
0981a08… noreply 94
0981a08… noreply 95
0981a08… noreply 96 def test_organize_outputs_skips_missing_diagram(formatter, tmp_dir):
0981a08… noreply 97 md = _create_file(tmp_dir / "analysis.md")
0981a08… noreply 98 kg = _create_file(tmp_dir / "kg.json")
0981a08… noreply 99
0981a08… noreply 100 result = formatter.organize_outputs(
0981a08… noreply 101 markdown_path=md,
0981a08… noreply 102 knowledge_graph_path=kg,
0981a08… noreply 103 diagrams=[{"image_path": "/nonexistent/diagram.png"}],
0981a08… noreply 104 )
0981a08… noreply 105
0981a08… noreply 106 assert result["diagram_images"] == []
0981a08… noreply 107
0981a08… noreply 108
0981a08… noreply 109 def test_organize_outputs_diagram_without_image_path(formatter, tmp_dir):
0981a08… noreply 110 md = _create_file(tmp_dir / "analysis.md")
0981a08… noreply 111 kg = _create_file(tmp_dir / "kg.json")
0981a08… noreply 112
0981a08… noreply 113 result = formatter.organize_outputs(
0981a08… noreply 114 markdown_path=md,
0981a08… noreply 115 knowledge_graph_path=kg,
0981a08… noreply 116 diagrams=[{"description": "A diagram"}],
0981a08… noreply 117 )
0981a08… noreply 118
0981a08… noreply 119 assert result["diagram_images"] == []
0981a08… noreply 120
0981a08… noreply 121
0981a08… noreply 122 def test_organize_outputs_with_frames(formatter, tmp_dir):
0981a08… noreply 123 md = _create_file(tmp_dir / "analysis.md")
0981a08… noreply 124 kg = _create_file(tmp_dir / "kg.json")
0981a08… noreply 125 frames_dir = tmp_dir / "frames"
0981a08… noreply 126 frames_dir.mkdir()
0981a08… noreply 127 for i in range(5):
0981a08… noreply 128 _create_file(frames_dir / f"frame_{i:03d}.jpg", f"frame{i}")
0981a08… noreply 129
0981a08… noreply 130 result = formatter.organize_outputs(
0981a08… noreply 131 markdown_path=md,
0981a08… noreply 132 knowledge_graph_path=kg,
0981a08… noreply 133 diagrams=[],
0981a08… noreply 134 frames_dir=frames_dir,
0981a08… noreply 135 )
0981a08… noreply 136
0981a08… noreply 137 assert len(result["frames"]) == 5
0981a08… noreply 138
0981a08… noreply 139
0981a08… noreply 140 def test_organize_outputs_limits_frames_to_10(formatter, tmp_dir):
0981a08… noreply 141 md = _create_file(tmp_dir / "analysis.md")
0981a08… noreply 142 kg = _create_file(tmp_dir / "kg.json")
0981a08… noreply 143 frames_dir = tmp_dir / "frames"
0981a08… noreply 144 frames_dir.mkdir()
0981a08… noreply 145 for i in range(25):
0981a08… noreply 146 _create_file(frames_dir / f"frame_{i:03d}.jpg", f"frame{i}")
0981a08… noreply 147
0981a08… noreply 148 result = formatter.organize_outputs(
0981a08… noreply 149 markdown_path=md,
0981a08… noreply 150 knowledge_graph_path=kg,
0981a08… noreply 151 diagrams=[],
0981a08… noreply 152 frames_dir=frames_dir,
0981a08… noreply 153 )
0981a08… noreply 154
0981a08… noreply 155 assert len(result["frames"]) <= 10
0981a08… noreply 156
0981a08… noreply 157
0981a08… noreply 158 def test_organize_outputs_missing_frames_dir(formatter, tmp_dir):
0981a08… noreply 159 md = _create_file(tmp_dir / "analysis.md")
0981a08… noreply 160 kg = _create_file(tmp_dir / "kg.json")
0981a08… noreply 161
0981a08… noreply 162 result = formatter.organize_outputs(
0981a08… noreply 163 markdown_path=md,
0981a08… noreply 164 knowledge_graph_path=kg,
0981a08… noreply 165 diagrams=[],
0981a08… noreply 166 frames_dir=tmp_dir / "nonexistent_frames",
0981a08… noreply 167 )
0981a08… noreply 168
0981a08… noreply 169 assert result["frames"] == []
0981a08… noreply 170
0981a08… noreply 171
0981a08… noreply 172 # --- create_html_index ---
0981a08… noreply 173
0981a08… noreply 174
0981a08… noreply 175 def test_create_html_index_returns_path(formatter, tmp_dir):
0981a08… noreply 176 outputs = {
0981a08… noreply 177 "markdown": str(formatter.output_dir / "markdown" / "analysis.md"),
0981a08… noreply 178 "knowledge_graph": str(formatter.output_dir / "data" / "kg.json"),
0981a08… noreply 179 "diagram_images": [],
0981a08… noreply 180 "frames": [],
0981a08… noreply 181 "transcript": None,
0981a08… noreply 182 }
0981a08… noreply 183 # Create the referenced files so relative_to works
0981a08… noreply 184 for key in ("markdown", "knowledge_graph"):
0981a08… noreply 185 _create_file(Path(outputs[key]))
0981a08… noreply 186
0981a08… noreply 187 index = formatter.create_html_index(outputs)
0981a08… noreply 188 assert index.exists()
0981a08… noreply 189 assert index.name == "index.html"
0981a08… noreply 190
0981a08… noreply 191
0981a08… noreply 192 def test_create_html_index_contains_analysis_link(formatter, tmp_dir):
0981a08… noreply 193 md_path = formatter.output_dir / "markdown" / "analysis.md"
0981a08… noreply 194 _create_file(md_path)
0981a08… noreply 195 outputs = {
0981a08… noreply 196 "markdown": str(md_path),
0981a08… noreply 197 "knowledge_graph": None,
0981a08… noreply 198 "diagram_images": [],
0981a08… noreply 199 "frames": [],
0981a08… noreply 200 "transcript": None,
0981a08… noreply 201 }
0981a08… noreply 202
0981a08… noreply 203 index = formatter.create_html_index(outputs)
0981a08… noreply 204 content = index.read_text()
0981a08… noreply 205 assert "Analysis Report" in content
0981a08… noreply 206 assert "analysis.md" in content
0981a08… noreply 207
0981a08… noreply 208
0981a08… noreply 209 def test_create_html_index_with_diagrams(formatter, tmp_dir):
0981a08… noreply 210 img_path = formatter.output_dir / "diagrams" / "d1.png"
0981a08… noreply 211 _create_file(img_path)
0981a08… noreply 212 outputs = {
0981a08… noreply 213 "markdown": None,
0981a08… noreply 214 "knowledge_graph": None,
0981a08… noreply 215 "diagram_images": [str(img_path)],
0981a08… noreply 216 "frames": [],
0981a08… noreply 217 "transcript": None,
0981a08… noreply 218 }
0981a08… noreply 219
0981a08… noreply 220 index = formatter.create_html_index(outputs)
0981a08… noreply 221 content = index.read_text()
0981a08… noreply 222 assert "Diagrams" in content
0981a08… noreply 223 assert "d1.png" in content
0981a08… noreply 224
0981a08… noreply 225
0981a08… noreply 226 def test_create_html_index_with_frames(formatter, tmp_dir):
0981a08… noreply 227 frame_path = formatter.output_dir / "frames" / "frame_001.jpg"
0981a08… noreply 228 _create_file(frame_path)
0981a08… noreply 229 outputs = {
0981a08… noreply 230 "markdown": None,
0981a08… noreply 231 "knowledge_graph": None,
0981a08… noreply 232 "diagram_images": [],
0981a08… noreply 233 "frames": [str(frame_path)],
0981a08… noreply 234 "transcript": None,
0981a08… noreply 235 }
0981a08… noreply 236
0981a08… noreply 237 index = formatter.create_html_index(outputs)
0981a08… noreply 238 content = index.read_text()
0981a08… noreply 239 assert "Key Frames" in content
0981a08… noreply 240 assert "frame_001.jpg" in content
0981a08… noreply 241
0981a08… noreply 242
0981a08… noreply 243 def test_create_html_index_with_data_files(formatter, tmp_dir):
0981a08… noreply 244 kg_path = formatter.output_dir / "data" / "kg.json"
0981a08… noreply 245 transcript_path = formatter.output_dir / "data" / "transcript.txt"
0981a08… noreply 246 _create_file(kg_path)
0981a08… noreply 247 _create_file(transcript_path)
0981a08… noreply 248 outputs = {
0981a08… noreply 249 "markdown": None,
0981a08… noreply 250 "knowledge_graph": str(kg_path),
0981a08… noreply 251 "diagram_images": [],
0981a08… noreply 252 "frames": [],
0981a08… noreply 253 "transcript": str(transcript_path),
0981a08… noreply 254 }
0981a08… noreply 255
0981a08… noreply 256 index = formatter.create_html_index(outputs)
0981a08… noreply 257 content = index.read_text()
0981a08… noreply 258 assert "Data Files" in content
0981a08… noreply 259 assert "kg.json" in content
0981a08… noreply 260 assert "transcript.txt" in content
0981a08… noreply 261
0981a08… noreply 262
0981a08… noreply 263 def test_create_html_index_empty_outputs(formatter):
0981a08… noreply 264 outputs = {
0981a08… noreply 265 "markdown": None,
0981a08… noreply 266 "knowledge_graph": None,
0981a08… noreply 267 "diagram_images": [],
0981a08… noreply 268 "frames": [],
0981a08… noreply 269 "transcript": None,
0981a08… noreply 270 }
0981a08… noreply 271
0981a08… noreply 272 index = formatter.create_html_index(outputs)
0981a08… noreply 273 content = index.read_text()
0981a08… noreply 274 assert "PlanOpticon Analysis Results" in content
0981a08… noreply 275 assert "<!DOCTYPE html>" in content

Keyboard Shortcuts

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