import importlib.util from pathlib import Path from unittest.mock import Mock import pytest from fenrirscreenreader.utils import char_utils COMMANDS_DIR = ( Path(__file__).resolve().parents[2] / "src" / "fenrirscreenreader" / "commands" / "commands" ) def load_command(name): spec = importlib.util.spec_from_file_location( f"fenrir_{name}", COMMANDS_DIR / f"{name}.py" ) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module.command() def build_environment(cursor): settings_manager = Mock() settings_manager.get_setting_as_bool.return_value = True output_manager = Mock() cursor_manager = Mock() cursor_manager.enter_review_mode_curr_text_cursor.return_value = None cursor_manager.get_review_or_text_cursor.return_value = cursor return { "punctuation": {"PUNCTDICT": {" ": "space"}}, "screen": { "newCursorReview": cursor.copy(), "new_cursor": cursor.copy(), "new_content_text": "abc\ndef", }, "runtime": { "AttributeManager": Mock(has_attributes=Mock(return_value=False)), "CursorManager": cursor_manager, "OutputManager": output_manager, "SettingsManager": settings_manager, "TableManager": Mock(is_table_mode=Mock(return_value=False)), }, } def run_command(name, cursor): env = build_environment(cursor) command = load_command(name) command.initialize(env) command.run() return env["runtime"]["OutputManager"] def boundary_call(output_manager): return output_manager.present_text.call_args_list[-1] @pytest.mark.unit def test_previous_line_uses_start_of_screen_sound_at_top(): output_manager = run_command("review_prev_line", {"x": 0, "y": 0}) call = boundary_call(output_manager) assert call.args[0] == "start of screen" assert call.kwargs["sound_icon"] == "StartOfScreen" @pytest.mark.unit def test_next_line_uses_end_of_screen_sound_at_bottom(): output_manager = run_command("review_next_line", {"x": 0, "y": 1}) call = boundary_call(output_manager) assert call.args[0] == "end of screen" assert call.kwargs["sound_icon"] == "EndOfScreen" @pytest.mark.unit def test_previous_character_uses_start_of_screen_sound_at_top_left(): output_manager = run_command("review_prev_char", {"x": 0, "y": 0}) call = boundary_call(output_manager) assert call.args[0] == "start of screen" assert call.kwargs["sound_icon"] == "StartOfScreen" @pytest.mark.unit def test_next_character_uses_end_of_screen_sound_at_bottom_right(): output_manager = run_command("review_next_char", {"x": 2, "y": 1}) call = boundary_call(output_manager) assert call.args[0] == "end of screen" assert call.kwargs["sound_icon"] == "EndOfScreen" @pytest.mark.unit def test_vertical_character_navigation_reports_boundaries_only_at_edges(): assert char_utils.get_up_char(0, 1, "abc\ndef") == ( 0, 0, "a", False, ) assert char_utils.get_up_char(0, 0, "abc\ndef") == ( 0, 0, "", True, ) assert char_utils.get_down_char(0, 0, "abc\ndef") == ( 0, 1, "d", False, ) assert char_utils.get_down_char(0, 1, "abc\ndef") == ( 0, 1, "", True, )