@@ -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 ()
0 commit comments