PlanOpticon

planopticon / tests / test_models.py
Source Blame History 262 lines
b2df90e… leo 1 """Tests for pydantic data models."""
b2df90e… leo 2
b2df90e… leo 3 from video_processor.models import (
b2df90e… leo 4 ActionItem,
b2df90e… leo 5 BatchManifest,
b2df90e… leo 6 BatchVideoEntry,
b2df90e… leo 7 DiagramResult,
b2df90e… leo 8 DiagramType,
b2df90e… leo 9 Entity,
b2df90e… leo 10 KeyPoint,
b2df90e… leo 11 KnowledgeGraphData,
b2df90e… leo 12 OutputFormat,
b2df90e… leo 13 ProcessingStats,
b2df90e… leo 14 Relationship,
b2df90e… leo 15 ScreenCapture,
b2df90e… leo 16 TranscriptSegment,
b2df90e… leo 17 VideoManifest,
b2df90e… leo 18 VideoMetadata,
b2df90e… leo 19 )
b2df90e… leo 20
b2df90e… leo 21
b2df90e… leo 22 class TestEnums:
b2df90e… leo 23 def test_diagram_type_values(self):
b2df90e… leo 24 assert DiagramType.flowchart == "flowchart"
b2df90e… leo 25 assert DiagramType.unknown == "unknown"
b2df90e… leo 26 assert len(DiagramType) == 9
b2df90e… leo 27
b2df90e… leo 28 def test_output_format_values(self):
b2df90e… leo 29 assert OutputFormat.markdown == "markdown"
b2df90e… leo 30 assert OutputFormat.pdf == "pdf"
c461c78… noreply 31 assert len(OutputFormat) == 7
b2df90e… leo 32
b2df90e… leo 33
b2df90e… leo 34 class TestTranscriptSegment:
b2df90e… leo 35 def test_basic(self):
b2df90e… leo 36 seg = TranscriptSegment(start=0.0, end=5.0, text="Hello world")
b2df90e… leo 37 assert seg.start == 0.0
b2df90e… leo 38 assert seg.speaker is None
b2df90e… leo 39
b2df90e… leo 40 def test_round_trip(self):
b2df90e… leo 41 seg = TranscriptSegment(start=1.0, end=2.0, text="Hi", speaker="Alice", confidence=0.95)
b2df90e… leo 42 restored = TranscriptSegment.model_validate_json(seg.model_dump_json())
b2df90e… leo 43 assert restored == seg
b2df90e… leo 44
b2df90e… leo 45
b2df90e… leo 46 class TestActionItem:
b2df90e… leo 47 def test_minimal(self):
b2df90e… leo 48 item = ActionItem(action="Fix the bug")
b2df90e… leo 49 assert item.assignee is None
b2df90e… leo 50 assert item.priority is None
b2df90e… leo 51
b2df90e… leo 52 def test_full(self):
b2df90e… leo 53 item = ActionItem(
b2df90e… leo 54 action="Deploy to prod",
b2df90e… leo 55 assignee="Bob",
b2df90e… leo 56 deadline="Friday",
b2df90e… leo 57 priority="high",
b2df90e… leo 58 context="After QA passes",
b2df90e… leo 59 source="transcript",
b2df90e… leo 60 )
b2df90e… leo 61 restored = ActionItem.model_validate_json(item.model_dump_json())
b2df90e… leo 62 assert restored == item
b2df90e… leo 63
b2df90e… leo 64
b2df90e… leo 65 class TestKeyPoint:
b2df90e… leo 66 def test_with_related_diagrams(self):
829e24a… leo 67 kp = KeyPoint(
829e24a… leo 68 point="System uses microservices", topic="Architecture", related_diagrams=[0, 2]
829e24a… leo 69 )
b2df90e… leo 70 assert kp.related_diagrams == [0, 2]
b2df90e… leo 71
b2df90e… leo 72 def test_round_trip(self):
b2df90e… leo 73 kp = KeyPoint(point="Test", details="Detail", timestamp=42.0, source="diagram")
b2df90e… leo 74 restored = KeyPoint.model_validate_json(kp.model_dump_json())
b2df90e… leo 75 assert restored == kp
b2df90e… leo 76
b2df90e… leo 77
b2df90e… leo 78 class TestDiagramResult:
b2df90e… leo 79 def test_defaults(self):
b2df90e… leo 80 dr = DiagramResult(frame_index=0)
b2df90e… leo 81 assert dr.diagram_type == DiagramType.unknown
b2df90e… leo 82 assert dr.confidence == 0.0
b2df90e… leo 83 assert dr.chart_data is None
b2df90e… leo 84 assert dr.elements == []
b2df90e… leo 85
b2df90e… leo 86 def test_chart_data(self):
b2df90e… leo 87 dr = DiagramResult(
b2df90e… leo 88 frame_index=5,
b2df90e… leo 89 diagram_type=DiagramType.chart,
b2df90e… leo 90 confidence=0.9,
b2df90e… leo 91 chart_data={"labels": ["A", "B"], "values": [10, 20], "chart_type": "bar"},
b2df90e… leo 92 )
b2df90e… leo 93 restored = DiagramResult.model_validate_json(dr.model_dump_json())
b2df90e… leo 94 assert restored.chart_data["chart_type"] == "bar"
b2df90e… leo 95
b2df90e… leo 96 def test_full_round_trip(self):
b2df90e… leo 97 dr = DiagramResult(
b2df90e… leo 98 frame_index=3,
b2df90e… leo 99 timestamp=15.5,
b2df90e… leo 100 diagram_type=DiagramType.flowchart,
b2df90e… leo 101 confidence=0.85,
b2df90e… leo 102 description="Login flow",
b2df90e… leo 103 text_content="Start -> Auth -> Dashboard",
b2df90e… leo 104 elements=["Start", "Auth", "Dashboard"],
b2df90e… leo 105 relationships=["Start->Auth", "Auth->Dashboard"],
b2df90e… leo 106 mermaid="graph LR\n A-->B-->C",
b2df90e… leo 107 image_path="diagrams/diagram_3.jpg",
b2df90e… leo 108 svg_path="diagrams/diagram_3.svg",
b2df90e… leo 109 png_path="diagrams/diagram_3.png",
b2df90e… leo 110 mermaid_path="diagrams/diagram_3.mermaid",
b2df90e… leo 111 )
b2df90e… leo 112 restored = DiagramResult.model_validate_json(dr.model_dump_json())
b2df90e… leo 113 assert restored == dr
b2df90e… leo 114
b2df90e… leo 115
b2df90e… leo 116 class TestScreenCapture:
b2df90e… leo 117 def test_basic(self):
b2df90e… leo 118 sc = ScreenCapture(frame_index=10, caption="Architecture overview slide", confidence=0.5)
b2df90e… leo 119 assert sc.image_path is None
2a1b11a… noreply 120 assert sc.content_type is None
2a1b11a… noreply 121 assert sc.text_content is None
2a1b11a… noreply 122 assert sc.entities == []
2a1b11a… noreply 123 assert sc.topics == []
2a1b11a… noreply 124
2a1b11a… noreply 125 def test_with_extraction(self):
2a1b11a… noreply 126 sc = ScreenCapture(
2a1b11a… noreply 127 frame_index=5,
2a1b11a… noreply 128 caption="Code editor showing Python",
2a1b11a… noreply 129 confidence=0.5,
2a1b11a… noreply 130 content_type="code",
2a1b11a… noreply 131 text_content="def main():\n print('hello')",
2a1b11a… noreply 132 entities=["Python", "main function"],
2a1b11a… noreply 133 topics=["programming"],
2a1b11a… noreply 134 )
2a1b11a… noreply 135 assert sc.content_type == "code"
2a1b11a… noreply 136 assert "Python" in sc.entities
2a1b11a… noreply 137 assert sc.text_content is not None
b2df90e… leo 138
b2df90e… leo 139 def test_round_trip(self):
b2df90e… leo 140 sc = ScreenCapture(
829e24a… leo 141 frame_index=7,
829e24a… leo 142 timestamp=30.0,
829e24a… leo 143 caption="Timeline",
829e24a… leo 144 image_path="captures/capture_0.jpg",
829e24a… leo 145 confidence=0.45,
2a1b11a… noreply 146 content_type="slide",
2a1b11a… noreply 147 text_content="Q4 Roadmap",
2a1b11a… noreply 148 entities=["Roadmap"],
2a1b11a… noreply 149 topics=["planning"],
b2df90e… leo 150 )
b2df90e… leo 151 restored = ScreenCapture.model_validate_json(sc.model_dump_json())
b2df90e… leo 152 assert restored == sc
b2df90e… leo 153
b2df90e… leo 154
b2df90e… leo 155 class TestEntity:
b2df90e… leo 156 def test_defaults(self):
b2df90e… leo 157 e = Entity(name="Python")
b2df90e… leo 158 assert e.type == "concept"
b2df90e… leo 159 assert e.descriptions == []
b2df90e… leo 160 assert e.occurrences == []
b2df90e… leo 161
b2df90e… leo 162 def test_round_trip(self):
b2df90e… leo 163 e = Entity(
b2df90e… leo 164 name="Alice",
b2df90e… leo 165 type="person",
b2df90e… leo 166 descriptions=["Team lead", "Engineer"],
b2df90e… leo 167 source="both",
b2df90e… leo 168 occurrences=[{"source": "transcript", "timestamp": 5.0, "text": "Alice said..."}],
b2df90e… leo 169 )
b2df90e… leo 170 restored = Entity.model_validate_json(e.model_dump_json())
b2df90e… leo 171 assert restored == e
b2df90e… leo 172
b2df90e… leo 173
b2df90e… leo 174 class TestKnowledgeGraphData:
b2df90e… leo 175 def test_empty(self):
b2df90e… leo 176 kg = KnowledgeGraphData()
b2df90e… leo 177 assert kg.nodes == []
b2df90e… leo 178 assert kg.relationships == []
b2df90e… leo 179
b2df90e… leo 180 def test_round_trip(self):
b2df90e… leo 181 kg = KnowledgeGraphData(
b2df90e… leo 182 nodes=[Entity(name="A"), Entity(name="B")],
b2df90e… leo 183 relationships=[Relationship(source="A", target="B", type="depends_on")],
b2df90e… leo 184 )
b2df90e… leo 185 restored = KnowledgeGraphData.model_validate_json(kg.model_dump_json())
b2df90e… leo 186 assert len(restored.nodes) == 2
b2df90e… leo 187 assert restored.relationships[0].type == "depends_on"
b2df90e… leo 188
b2df90e… leo 189
b2df90e… leo 190 class TestVideoManifest:
b2df90e… leo 191 def test_minimal(self):
b2df90e… leo 192 m = VideoManifest(video=VideoMetadata(title="Test Video"))
b2df90e… leo 193 assert m.version == "1.0"
b2df90e… leo 194 assert m.diagrams == []
b2df90e… leo 195 assert m.screen_captures == []
b2df90e… leo 196 assert m.stats.frames_extracted == 0
b2df90e… leo 197
b2df90e… leo 198 def test_full_round_trip(self):
b2df90e… leo 199 m = VideoManifest(
829e24a… leo 200 video=VideoMetadata(
829e24a… leo 201 title="Meeting", source_path="/tmp/video.mp4", duration_seconds=3600.0
829e24a… leo 202 ),
b2df90e… leo 203 stats=ProcessingStats(
b2df90e… leo 204 frames_extracted=50,
b2df90e… leo 205 diagrams_detected=3,
b2df90e… leo 206 screen_captures=2,
b2df90e… leo 207 models_used={"vision": "gpt-4o", "chat": "claude-sonnet-4-5"},
b2df90e… leo 208 ),
b2df90e… leo 209 transcript_json="transcript/transcript.json",
b2df90e… leo 210 analysis_md="results/analysis.md",
b2df90e… leo 211 key_points=[KeyPoint(point="Important thing")],
b2df90e… leo 212 action_items=[ActionItem(action="Do the thing")],
b2df90e… leo 213 diagrams=[DiagramResult(frame_index=0, confidence=0.9)],
b2df90e… leo 214 screen_captures=[ScreenCapture(frame_index=5, caption="Slide")],
b2df90e… leo 215 frame_paths=["frames/frame_0000.jpg", "frames/frame_0001.jpg"],
b2df90e… leo 216 )
b2df90e… leo 217 json_str = m.model_dump_json()
b2df90e… leo 218 restored = VideoManifest.model_validate_json(json_str)
b2df90e… leo 219 assert restored.video.title == "Meeting"
b2df90e… leo 220 assert len(restored.diagrams) == 1
b2df90e… leo 221 assert len(restored.screen_captures) == 1
b2df90e… leo 222 assert restored.stats.models_used["vision"] == "gpt-4o"
b2df90e… leo 223
b2df90e… leo 224
b2df90e… leo 225 class TestBatchManifest:
b2df90e… leo 226 def test_minimal(self):
b2df90e… leo 227 m = BatchManifest()
b2df90e… leo 228 assert m.total_videos == 0
b2df90e… leo 229 assert m.videos == []
b2df90e… leo 230
b2df90e… leo 231 def test_full_round_trip(self):
b2df90e… leo 232 m = BatchManifest(
b2df90e… leo 233 title="Weekly Meetings",
b2df90e… leo 234 total_videos=3,
b2df90e… leo 235 completed_videos=2,
b2df90e… leo 236 failed_videos=1,
b2df90e… leo 237 total_diagrams=5,
b2df90e… leo 238 total_action_items=10,
b2df90e… leo 239 total_key_points=15,
b2df90e… leo 240 videos=[
b2df90e… leo 241 BatchVideoEntry(
b2df90e… leo 242 video_name="meeting_1",
b2df90e… leo 243 manifest_path="videos/meeting_1/manifest.json",
b2df90e… leo 244 status="completed",
b2df90e… leo 245 diagrams_count=3,
b2df90e… leo 246 action_items_count=5,
b2df90e… leo 247 ),
b2df90e… leo 248 BatchVideoEntry(
b2df90e… leo 249 video_name="meeting_2",
b2df90e… leo 250 manifest_path="videos/meeting_2/manifest.json",
b2df90e… leo 251 status="failed",
b2df90e… leo 252 error="Audio extraction failed",
b2df90e… leo 253 ),
b2df90e… leo 254 ],
b2df90e… leo 255 batch_summary_md="batch_summary.md",
b2df90e… leo 256 merged_knowledge_graph_json="knowledge_graph.json",
b2df90e… leo 257 )
b2df90e… leo 258 json_str = m.model_dump_json()
b2df90e… leo 259 restored = BatchManifest.model_validate_json(json_str)
b2df90e… leo 260 assert restored.total_videos == 3
b2df90e… leo 261 assert restored.videos[1].status == "failed"
b2df90e… leo 262 assert restored.videos[1].error == "Audio extraction failed"

Keyboard Shortcuts

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