Skip to content

Commit 7786bab

Browse files
committed
Expand recording context test coverage
Adds focused tests around processor recording context handling in `DLCLiveMainWindow`, including file metadata propagation, stop-time context refresh, and optional processor hooks. It also introduces a regression test for `BaseProcessorSocket.save()` to ensure explicit relative filenames still write under the legacy `data/` directory. UI label testing for unknown camera IDs was relaxed to assert the neutral text is present rather than requiring an exact string.
1 parent 2e77bf8 commit 7786bab

2 files changed

Lines changed: 115 additions & 5 deletions

File tree

‎tests/custom_processors/test_processor_rec_context.py‎

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,27 @@ def main_window_cls():
212212
return mod.DLCLiveMainWindow
213213

214214

215-
def make_window_shell(main_window_cls, processor=None, run_dir=None):
215+
class DummyRecordingManager:
216+
def __init__(self, run_dir=None, file_context=None):
217+
self.run_dir = run_dir
218+
self.file_context = dict(file_context or {})
219+
220+
def get_recording_file_context(self):
221+
context = dict(self.file_context)
222+
if self.run_dir is not None:
223+
context.setdefault("run_dir", self.run_dir)
224+
return context
225+
226+
227+
def make_window_shell(main_window_cls, processor=None, run_dir=None, file_context=None):
216228
"""Create a DLCLiveMainWindow shell without running QMainWindow.__init__."""
217229
win = main_window_cls.__new__(main_window_cls)
218230
win._dlc = SimpleNamespace(_processor=processor, _dlc=None)
219-
win._rec_manager = SimpleNamespace(run_dir=run_dir)
231+
win._rec_manager = DummyRecordingManager(run_dir=run_dir, file_context=file_context)
220232
win.session_name_edit = DummyLineEdit("MouseA")
221233
win.filename_edit = DummyLineEdit("MouseA_2026-07-10_1.avi")
234+
win._processor_recording_context = None
235+
win._processor_recording_started_notified = False
222236
return win
223237

224238

@@ -253,7 +267,8 @@ def test_main_window_notify_processor_recording_started_calls_hook(main_window_c
253267
processor = HookProcessor()
254268
win = make_window_shell(main_window_cls, processor=processor, run_dir=tmp_path)
255269

256-
win._notify_processor_recording_started(tmp_path)
270+
context = win._build_processor_recording_context(tmp_path)
271+
win._notify_processor_recording_started(context)
257272

258273
assert len(processor.started_contexts) == 1
259274
context = processor.started_contexts[0]
@@ -287,6 +302,101 @@ class NoHooks:
287302
win = make_window_shell(main_window_cls, processor=NoHooks(), run_dir=tmp_path)
288303

289304
# Optional hooks/save absence should not crash.
290-
win._notify_processor_recording_started(tmp_path)
305+
ctx = win._build_processor_recording_context(tmp_path)
306+
win._notify_processor_recording_started(ctx)
291307
win._notify_processor_recording_stopped()
292308
win._save_processor_data_if_available()
309+
310+
311+
def test_main_window_build_context_includes_recording_files(
312+
main_window_cls,
313+
tmp_path,
314+
):
315+
video_file = tmp_path / "camera_0.mp4"
316+
timestamp_file = tmp_path / "camera_0.json"
317+
318+
win = make_window_shell(
319+
main_window_cls,
320+
run_dir=tmp_path,
321+
file_context={
322+
"video_files": {
323+
"camera-0": video_file,
324+
},
325+
"timestamp_json_files": {
326+
"camera-0": timestamp_file,
327+
},
328+
},
329+
)
330+
331+
context = win._build_processor_recording_context(tmp_path)
332+
333+
assert context["video_files"] == {
334+
"camera-0": video_file,
335+
}
336+
assert context["timestamp_json_files"] == {
337+
"camera-0": timestamp_file,
338+
}
339+
340+
341+
def test_processor_stop_context_uses_finalized_file_context(
342+
main_window_cls,
343+
tmp_path,
344+
):
345+
processor = HookProcessor()
346+
initial_video = tmp_path / "initial.mp4"
347+
final_video = tmp_path / "final.mp4"
348+
349+
win = make_window_shell(
350+
main_window_cls,
351+
processor=processor,
352+
run_dir=tmp_path,
353+
file_context={
354+
"video_files": {
355+
"camera-0": initial_video,
356+
},
357+
},
358+
)
359+
win._processor_recording_context = win._build_processor_recording_context(tmp_path)
360+
361+
# Simulate RecordingManager updating its context during stop_all().
362+
win._rec_manager.file_context = {
363+
"video_files": {
364+
"camera-0": final_video,
365+
},
366+
}
367+
368+
win._notify_processor_recording_stopped()
369+
370+
assert len(processor.stopped_contexts) == 1
371+
assert processor.stopped_contexts[0]["video_files"] == {
372+
"camera-0": final_video,
373+
}
374+
375+
376+
def test_base_processor_explicit_relative_file_uses_legacy_data_dir(
377+
socket_mod,
378+
tmp_path,
379+
monkeypatch,
380+
):
381+
BaseProcessorSocket = socket_mod.BaseProcessorSocket
382+
proc = BaseProcessorSocket(
383+
bind=("127.0.0.1", 0),
384+
save_original=False,
385+
)
386+
387+
monkeypatch.chdir(tmp_path)
388+
389+
try:
390+
ret = proc.save("session_dlc_processor_data.pkl")
391+
392+
expected = tmp_path / "data" / "session_dlc_processor_data.pkl"
393+
394+
assert ret == 1
395+
assert expected.exists()
396+
397+
with expected.open("rb") as handle:
398+
payload = pickle.load(handle)
399+
400+
assert "start_time" in payload
401+
finally:
402+
proc.stop()

‎tests/gui/main_window/test_ui.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@ def test_label_for_cam_id_uses_runtime_display_id_fallback(self, window):
4949

5050
assert w._label_for_cam_id("runtime:id") == "Runtime Camera"
5151

52-
def test_label_for_cam_id_unknown_is_neutral(self, window):
52+
def test_label_for_cam_id_unknown(self, window):
5353
assert "Unknown camera" in window._label_for_cam_id("missing:id")

0 commit comments

Comments
 (0)