from unittest.mock import Mock import pytest from fenrirscreenreader.core.commandManager import CommandManager from fenrirscreenreader.core.settingsManager import SettingsManager def write_script(path): path.write_text("#!/bin/sh\n", encoding="utf-8") path.chmod(0o755) def build_command_environment(local_path, system_path): settings_manager = Mock() settings_manager.get_user_script_path.return_value = str(local_path) settings_manager.get_setting.return_value = str(system_path) valid_keys = { "KEY_A", "KEY_B", "KEY_C", "KEY_D", "KEY_E", "KEY_SHIFT", "KEY_SCRIPT", "KEY_U", "KEY_X", } return { "commands": {"commands": {}}, "commandsIgnore": {"commands": {}}, "bindings": { str([1, sorted(["KEY_C", "KEY_SCRIPT"])]): "EXISTING" }, "rawBindings": {}, "general": {"curr_user": "Username"}, "runtime": { "SettingsManager": settings_manager, "DebugManager": Mock(write_debug_out=Mock()), "InputManager": Mock( is_valid_key=Mock(side_effect=lambda key: key in valid_keys) ), }, } @pytest.mark.unit def test_local_scripts_load_before_non_conflicting_system_scripts(tmp_path): local_path = tmp_path / "local" system_path = tmp_path / "system" local_path.mkdir() system_path.mkdir() write_script(local_path / "local_only__-__KEY_A") write_script(local_path / "same_name__-__KEY_B") write_script(system_path / "same_name__-__KEY_D") write_script(system_path / "system_only__-__KEY_E") env = build_command_environment(local_path, system_path) command_manager = CommandManager() command_manager.initialize = lambda environment: None command_manager.env = env command_manager.load_script_commands() commands = env["commands"]["commands"] assert "LOCAL_ONLY__-__KEY_A" in commands assert "SYSTEM_ONLY__-__KEY_E" in commands assert commands["SAME_NAME__-__KEY_B"].script_path == str( local_path / "same_name__-__KEY_B" ) assert "SAME_NAME__-__KEY_D" not in commands @pytest.mark.unit def test_system_scripts_skip_existing_shortcut_bindings(tmp_path): local_path = tmp_path / "local" system_path = tmp_path / "system" local_path.mkdir() system_path.mkdir() write_script(system_path / "conflicting_key__-__KEY_C") write_script(system_path / "system_only__-__KEY_E") env = build_command_environment(local_path, system_path) command_manager = CommandManager() command_manager.env = env command_manager.load_script_commands() commands = env["commands"]["commands"] assert "CONFLICTING_KEY__-__KEY_C" not in commands assert "SYSTEM_ONLY__-__KEY_E" in commands @pytest.mark.unit def test_same_directory_script_variants_load_multiple_shortcuts(tmp_path): local_path = tmp_path / "local" system_path = tmp_path / "system" local_path.mkdir() system_path.mkdir() write_script(system_path / "musicplayer__-__KEY_SHIFT__+__KEY_U.sh") write_script(system_path / "musicplayer__-__KEY_SHIFT__+__KEY_X.sh") env = build_command_environment(local_path, system_path) command_manager = CommandManager() command_manager.env = env command_manager.load_script_commands() commands = env["commands"]["commands"] assert "MUSICPLAYER__-__KEY_SHIFT__+__KEY_U" in commands assert "MUSICPLAYER__-__KEY_SHIFT__+__KEY_X" in commands assert ( env["bindings"][str([1, sorted(["KEY_SCRIPT", "KEY_SHIFT", "KEY_U"])])] == "MUSICPLAYER__-__KEY_SHIFT__+__KEY_U" ) assert ( env["bindings"][str([1, sorted(["KEY_SCRIPT", "KEY_SHIFT", "KEY_X"])])] == "MUSICPLAYER__-__KEY_SHIFT__+__KEY_X" ) @pytest.mark.unit def test_sound_theme_resolution_prefers_local_soundpacks(tmp_path): manager = SettingsManager() local_root = tmp_path / "local" / "fenrir" system_root = tmp_path / "system" / "sounds" / "fenrir" local_theme = local_root / "sounds" / "default" system_theme = system_root / "default" local_theme.mkdir(parents=True) system_theme.mkdir(parents=True) (local_theme / "soundicons.conf").write_text( "Accept=Accept.wav\n", encoding="utf-8" ) (system_theme / "soundicons.conf").write_text( "Accept=SystemAccept.wav\n", encoding="utf-8" ) manager.user_resource_root = str(local_root) manager.system_sound_roots = [str(system_root)] assert manager.resolve_sound_theme_path("default") == str(local_theme) @pytest.mark.unit def test_sound_theme_resolution_accepts_absolute_theme_path(tmp_path): manager = SettingsManager() theme_path = tmp_path / "custom" theme_path.mkdir() (theme_path / "soundicons.conf").write_text( "Accept=Accept.wav\n", encoding="utf-8" ) assert manager.resolve_sound_theme_path(str(theme_path)) == str(theme_path)