PlanOpticon

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

Keyboard Shortcuts

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