import importlib.util from pathlib import Path from unittest.mock import Mock import pytest def _load_progress_module(): module_path = ( Path(__file__).resolve().parents[2] / "src" / "fenrirscreenreader" / "commands" / "onScreenUpdate" / "65000-progress_detector.py" ) spec = importlib.util.spec_from_file_location( "fenrir_progress_detector", module_path ) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module @pytest.mark.unit def test_progress_detector_skips_typing_delta(): progress_module = _load_progress_module() command = progress_module.command() command.env = { "commandBuffer": {"progress_monitoring": True}, "runtime": {"DebugManager": Mock(write_debug_out=Mock())}, "screen": {"new_delta": "x", "new_delta_is_typing": True}, } command.is_current_line_prompt = Mock(return_value=False) command.is_real_progress_update = Mock(return_value=True) command.detect_progress = Mock() command.run() command.is_real_progress_update.assert_not_called() command.detect_progress.assert_not_called() @pytest.mark.unit def test_progress_detector_allows_long_tqdm_transfer_delta(): progress_module = _load_progress_module() command = progress_module.command() sample = ( "88%|" "████████████████████████████████████████████████████████████████" "████████████████████████████████████████████████████████████████" "████████████████████████████████████████████████████████████████" "█████████████████████████▊ " "| 843M/954M [00:54<00:07, 15.2MB/s]" ) command.env = { "commandBuffer": {"progress_monitoring": True}, "runtime": { "DebugManager": Mock(write_debug_out=Mock()), "ScreenManager": Mock(is_screen_change=Mock(return_value=False)), "CursorManager": Mock(is_cursor_vertical_move=Mock(return_value=False)), }, "screen": { "new_delta": sample, "new_content_text": sample, "old_cursor": {"x": 0, "y": 0}, "new_cursor": {"x": 0, "y": 0}, }, } assert len(sample) > 200 assert command.is_real_progress_update() @pytest.mark.unit def test_progress_detector_beeps_for_long_tqdm_transfer_delta(): progress_module = _load_progress_module() command = progress_module.command() sample = ( "90%|" "████████████████████████████████████████████████████████████████" "████████████████████████████████████████████████████████████████" "████████████████████████████████████████████████████████████████" "█████████████████████████████████████▍ " "| 856M/954M [00:56<00:14, 6.78MB/s]" ) command.env = { "commandBuffer": { "progress_monitoring": True, "lastProgressValue": -1, "lastProgressTime": 0, }, "runtime": { "DebugManager": Mock(write_debug_out=Mock()), "ScreenManager": Mock(is_screen_change=Mock(return_value=False)), "CursorManager": Mock(is_cursor_vertical_move=Mock(return_value=False)), }, "screen": { "new_delta": sample, "new_delta_is_typing": False, "new_content_text": sample, "old_cursor": {"x": 0, "y": 0}, "new_cursor": {"x": 0, "y": 0}, }, } command.play_progress_tone = Mock() command.run() command.play_progress_tone.assert_called_once_with(90.0) assert command.env["commandBuffer"]["lastProgressValue"] == 90.0 @pytest.mark.unit def test_progress_detector_beeps_for_interruptible_status_without_ellipsis(): progress_module = _load_progress_module() command = progress_module.command() sample = "◦ Files: (1m 04s • esc to interrupt)" command.env = { "commandBuffer": { "progress_monitoring": True, "lastProgressValue": -1, "lastProgressTime": 0, }, "runtime": { "DebugManager": Mock(write_debug_out=Mock()), "ScreenManager": Mock(is_screen_change=Mock(return_value=False)), "CursorManager": Mock(is_cursor_vertical_move=Mock(return_value=False)), }, "screen": { "new_delta": sample, "new_delta_is_typing": False, "new_content_text": sample, "old_cursor": {"x": 0, "y": 0}, "new_cursor": {"x": 0, "y": 0}, }, } command.play_activity_beep = Mock() command.run() command.play_activity_beep.assert_called_once_with()