3262 lines
121 KiB
Python
3262 lines
121 KiB
Python
# Unit tests for input_event_manager.py methods.
|
|
#
|
|
# Copyright 2025 Igalia, S.L.
|
|
# Author: Joanmarie Diggs <jdiggs@igalia.com>
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library; if not, write to the
|
|
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
|
|
# Boston MA 02110-1301 USA.
|
|
|
|
# pylint: disable=wrong-import-position
|
|
# pylint: disable=import-outside-toplevel
|
|
# pylint: disable=too-many-public-methods
|
|
# pylint: disable=too-many-statements
|
|
# pylint: disable=protected-access
|
|
# pylint: disable=too-many-arguments
|
|
# pylint: disable=too-many-positional-arguments
|
|
# pylint: disable=too-many-locals
|
|
# pylint: disable=too-many-lines
|
|
# pylint: disable=too-many-instance-attributes
|
|
|
|
"""Unit tests for input_event_manager.py methods."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
from unittest.mock import call
|
|
|
|
import pytest
|
|
|
|
if TYPE_CHECKING:
|
|
from unittest.mock import MagicMock
|
|
|
|
from cthulhu_test_context import CthulhuTestContext
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestInputEventManager:
|
|
"""Test InputEventManager class methods."""
|
|
|
|
def _setup_dependencies(self, test_context: CthulhuTestContext) -> dict[str, MagicMock]:
|
|
"""Returns dependencies for input_event_manager module testing."""
|
|
|
|
additional_modules = ["cthulhu.ax_utilities", "gi.repository"]
|
|
essential_modules = test_context.setup_shared_dependencies(additional_modules)
|
|
|
|
debug_mock = essential_modules["cthulhu.debug"]
|
|
debug_mock.LEVEL_INFO = 800
|
|
debug_mock.LEVEL_WARNING = 2
|
|
debug_mock.LEVEL_SEVERE = 3
|
|
debug_mock.debugLevel = 0
|
|
|
|
focus_manager_mock = essential_modules["cthulhu.focus_manager"]
|
|
focus_mgr_instance = test_context.Mock()
|
|
focus_mgr_instance.get_locus_of_focus = test_context.Mock()
|
|
focus_mgr_instance.get_active_window = test_context.Mock()
|
|
focus_mgr_instance.focus_and_window_are_unknown = test_context.Mock(return_value=False)
|
|
focus_mgr_instance.clear_state = test_context.Mock()
|
|
focus_manager_mock.get_manager = test_context.Mock(return_value=focus_mgr_instance)
|
|
|
|
script_manager_mock = essential_modules["cthulhu.script_manager"]
|
|
script_mgr_instance = test_context.Mock()
|
|
script_instance = test_context.Mock()
|
|
script_instance.app = test_context.Mock()
|
|
script_instance.event_cache = {}
|
|
script_instance.listeners = {}
|
|
script_instance.is_activatable_event = test_context.Mock(return_value=True)
|
|
script_instance.force_script_activation = test_context.Mock(return_value=False)
|
|
script_instance.present_if_inactive = False
|
|
script_mgr_instance.get_active_script = test_context.Mock(return_value=script_instance)
|
|
script_mgr_instance.get_script = test_context.Mock(return_value=script_instance)
|
|
script_mgr_instance.set_active_script = test_context.Mock()
|
|
script_mgr_instance.get_default_script = test_context.Mock(return_value=script_instance)
|
|
script_mgr_instance.reclaim_scripts = test_context.Mock()
|
|
script_manager_mock.get_manager = test_context.Mock(return_value=script_mgr_instance)
|
|
|
|
input_event_mock = essential_modules["cthulhu.input_event"]
|
|
|
|
class MockKeyboardEvent:
|
|
"""Mock KeyboardEvent class for testing."""
|
|
|
|
def __init__(self, pressed=True, keycode=65, keysym=97, modifiers=0, text="a"):
|
|
self.process = test_context.Mock()
|
|
self.set_window = test_context.Mock()
|
|
self.set_object = test_context.Mock()
|
|
self.set_script = test_context.Mock()
|
|
self.set_click_count = test_context.Mock()
|
|
self.is_modifier_key = test_context.Mock(return_value=False)
|
|
self.is_pressed_key = test_context.Mock(return_value=True)
|
|
self.get_window = test_context.Mock()
|
|
self.get_object = test_context.Mock()
|
|
self.get_script = test_context.Mock()
|
|
self.get_click_count = test_context.Mock(return_value=1)
|
|
self.is_printable_key = test_context.Mock(return_value=True)
|
|
self.as_single_line_string = test_context.Mock(return_value="KeyboardEvent")
|
|
self.pressed = pressed
|
|
self.keycode = keycode
|
|
self.keysym = keysym
|
|
self.modifiers = modifiers
|
|
self.text = text
|
|
self.id = 1
|
|
self.hw_code = keycode
|
|
self.keyval_name = text
|
|
self.time = 1000
|
|
self.button = None
|
|
|
|
def __eq__(self, other):
|
|
"""Enable equality comparison for duplicate detection."""
|
|
|
|
if not isinstance(other, MockKeyboardEvent):
|
|
return False
|
|
return (
|
|
self.pressed == other.pressed
|
|
and self.keycode == other.keycode
|
|
and self.keysym == other.keysym
|
|
and self.modifiers == other.modifiers
|
|
and self.text == other.text
|
|
)
|
|
|
|
def __hash__(self):
|
|
return hash((self.pressed, self.keycode, self.keysym, self.modifiers, self.text))
|
|
|
|
class MockBrailleEvent:
|
|
"""Mock BrailleEvent class for testing."""
|
|
|
|
def __init__(self, *_args, **_kwargs):
|
|
self.process = test_context.Mock(return_value=True)
|
|
|
|
class MockMouseButtonEvent:
|
|
"""Mock MouseButtonEvent class for testing."""
|
|
|
|
def __init__(self, *_args, **_kwargs):
|
|
self.set_click_count = test_context.Mock()
|
|
self.get_click_count = test_context.Mock(return_value=1)
|
|
self.button = "1"
|
|
self.pressed = True
|
|
self.time = 1000
|
|
|
|
input_event_mock.KeyboardEvent = MockKeyboardEvent
|
|
input_event_mock.BrailleEvent = MockBrailleEvent
|
|
input_event_mock.MouseButtonEvent = MockMouseButtonEvent
|
|
|
|
ax_utilities_mock = essential_modules["cthulhu.ax_utilities"]
|
|
ax_utilities_class = test_context.Mock()
|
|
ax_utilities_class.can_be_active_window = test_context.Mock(return_value=True)
|
|
ax_utilities_class.find_active_window = test_context.Mock(return_value=None)
|
|
ax_utilities_class.is_single_line = test_context.Mock(return_value=False)
|
|
ax_utilities_class.is_widget_controlled_by_line_navigation = test_context.Mock(
|
|
return_value=False,
|
|
)
|
|
ax_utilities_class.has_matching_shortcut = test_context.Mock(return_value=False)
|
|
ax_utilities_class.is_table_header = test_context.Mock(return_value=False)
|
|
ax_utilities_class.is_terminal = test_context.Mock(return_value=False)
|
|
ax_utilities_mock.AXUtilities = ax_utilities_class
|
|
|
|
gi_repo_mock = essential_modules["gi.repository"]
|
|
|
|
atspi_mock = test_context.Mock()
|
|
atspi_mock.get_version = test_context.Mock(return_value=(2, 56, 0))
|
|
atspi_mock.Device = test_context.Mock()
|
|
atspi_mock.Device.new_full = test_context.Mock()
|
|
atspi_mock.Device.new = test_context.Mock()
|
|
atspi_mock.Device.grab_keyboard = test_context.Mock()
|
|
atspi_mock.Device.ungrab_keyboard = test_context.Mock()
|
|
atspi_mock.KeyDefinition = test_context.Mock()
|
|
atspi_mock.ModifierType = test_context.Mock()
|
|
atspi_mock.ModifierType.CONTROL = 2
|
|
atspi_mock.ModifierType.SHIFT = 0
|
|
atspi_mock.ModifierType.ALT = 3
|
|
gi_repo_mock.Atspi = atspi_mock
|
|
|
|
essential_modules["focus_manager_instance"] = focus_mgr_instance
|
|
essential_modules["script_manager_instance"] = script_mgr_instance
|
|
essential_modules["script_instance"] = script_instance
|
|
|
|
essential_modules["ax_utilities_class"] = ax_utilities_class
|
|
essential_modules["atspi"] = atspi_mock
|
|
return essential_modules
|
|
|
|
def _setup_input_event_manager(self, test_context) -> tuple:
|
|
"""Helper method to set up InputEventManager with dependencies."""
|
|
|
|
essential_modules: dict[str, MagicMock] = self._setup_dependencies(test_context)
|
|
|
|
test_context.patch("cthulhu.input_event_manager.debug", new=essential_modules["cthulhu.debug"])
|
|
test_context.patch(
|
|
"cthulhu.input_event_manager.focus_manager",
|
|
new=essential_modules["cthulhu.focus_manager"],
|
|
)
|
|
test_context.patch(
|
|
"cthulhu.input_event_manager.script_manager",
|
|
new=essential_modules["cthulhu.script_manager"],
|
|
)
|
|
test_context.patch(
|
|
"cthulhu.input_event_manager.input_event",
|
|
new=essential_modules["cthulhu.input_event"],
|
|
)
|
|
test_context.patch(
|
|
"cthulhu.input_event_manager.AXUtilities",
|
|
new=essential_modules["ax_utilities_class"],
|
|
)
|
|
test_context.patch("cthulhu.input_event_manager.Atspi", new=essential_modules["atspi"])
|
|
|
|
ax_device_mgr_mock = test_context.Mock()
|
|
essential_modules["ax_device_manager"] = ax_device_mgr_mock
|
|
test_context.patch("cthulhu.input_event_manager.ax_device_manager", new=ax_device_mgr_mock)
|
|
|
|
from cthulhu.input_event_manager import InputEventManager
|
|
|
|
return InputEventManager(), essential_modules
|
|
|
|
def test_init(self, test_context: CthulhuTestContext) -> None:
|
|
"""Test InputEventManager.__init__."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
assert input_event_manager._last_input_event is None
|
|
assert input_event_manager._last_non_modifier_key_event is None
|
|
assert input_event_manager._device is None
|
|
assert not input_event_manager._mapped_keycodes
|
|
assert not input_event_manager._mapped_keysyms
|
|
assert not input_event_manager._grabbed_bindings
|
|
|
|
def test_start_key_watcher(self, test_context) -> None:
|
|
"""Test InputEventManager.start_key_watcher."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_device = test_context.Mock()
|
|
ax_device_mgr = essential_modules["ax_device_manager"]
|
|
ax_device_mgr.get_manager.return_value.get_device.return_value = mock_device
|
|
|
|
input_event_manager.start_key_watcher()
|
|
|
|
ax_device_mgr.get_manager.return_value.get_device.assert_called_once()
|
|
mock_device.add_key_watcher.assert_called_once_with(
|
|
input_event_manager.process_keyboard_event,
|
|
)
|
|
assert input_event_manager._device is mock_device
|
|
|
|
def test_stop_key_watcher(self, test_context: CthulhuTestContext) -> None:
|
|
"""Test InputEventManager.stop_key_watcher."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._device = test_context.Mock()
|
|
input_event_manager.stop_key_watcher()
|
|
assert input_event_manager._device is None
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "disabled",
|
|
"scenario": "disabled",
|
|
"is_enabled": False,
|
|
"is_bound": True,
|
|
"has_grabs": False,
|
|
"has_device": False,
|
|
"expected_result": [],
|
|
"expects_debug_call": False,
|
|
},
|
|
{
|
|
"id": "unbound",
|
|
"scenario": "unbound",
|
|
"is_enabled": True,
|
|
"is_bound": False,
|
|
"has_grabs": False,
|
|
"has_device": False,
|
|
"expected_result": [],
|
|
"expects_debug_call": False,
|
|
},
|
|
{
|
|
"id": "has_grabs",
|
|
"scenario": "has_grabs",
|
|
"is_enabled": True,
|
|
"is_bound": True,
|
|
"has_grabs": True,
|
|
"has_device": False,
|
|
"existing_grab_ids": [333, 444],
|
|
"expected_result": [333, 444],
|
|
"expects_debug_call": True,
|
|
},
|
|
{
|
|
"id": "no_device",
|
|
"scenario": "no_device",
|
|
"is_enabled": True,
|
|
"is_bound": True,
|
|
"has_grabs": False,
|
|
"has_device": False,
|
|
"expected_result": [],
|
|
"expects_debug_call": True,
|
|
},
|
|
{
|
|
"id": "success",
|
|
"scenario": "success",
|
|
"is_enabled": True,
|
|
"is_bound": True,
|
|
"has_grabs": False,
|
|
"has_device": True,
|
|
"expected_result": [111, 222],
|
|
"expects_debug_call": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_add_grabs_for_keybinding_scenarios(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.add_grabs_for_keybinding with various scenarios."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
|
|
mock_binding = test_context.Mock()
|
|
mock_binding.is_enabled.return_value = case["is_enabled"]
|
|
mock_binding.is_bound.return_value = case["is_bound"]
|
|
mock_binding.has_grabs.return_value = case["has_grabs"]
|
|
mock_binding.get_grab_ids.return_value = case.get("existing_grab_ids", [])
|
|
|
|
if case["has_device"]:
|
|
mock_device = test_context.Mock()
|
|
mock_device.add_key_grab.side_effect = [111, 222]
|
|
input_event_manager._device = mock_device
|
|
mock_kd1 = test_context.Mock()
|
|
mock_kd2 = test_context.Mock()
|
|
mock_binding.key_definitions.return_value = [mock_kd1, mock_kd2]
|
|
|
|
result = input_event_manager.add_grabs_for_keybinding(mock_binding, ["Insert", "KP_Insert"])
|
|
|
|
if case["scenario"] == "success":
|
|
assert result == case["expected_result"]
|
|
assert input_event_manager._grabbed_bindings[111] == mock_binding
|
|
assert input_event_manager._grabbed_bindings[222] == mock_binding
|
|
mock_device.add_key_grab.assert_has_calls([call(mock_kd1, None), call(mock_kd2, None)])
|
|
else:
|
|
assert result == case["expected_result"]
|
|
|
|
if case["expects_debug_call"]:
|
|
essential_modules["cthulhu.debug"].print_tokens.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "no_device",
|
|
"scenario": "no_device",
|
|
"has_device": False,
|
|
"grab_ids": [],
|
|
"has_grabbed_bindings": False,
|
|
"expects_debug_tokens": True,
|
|
"expects_debug_message": False,
|
|
"expects_device_calls": False,
|
|
},
|
|
{
|
|
"id": "no_grabs",
|
|
"scenario": "no_grabs",
|
|
"has_device": True,
|
|
"grab_ids": [],
|
|
"has_grabbed_bindings": False,
|
|
"expects_debug_tokens": False,
|
|
"expects_debug_message": False,
|
|
"expects_device_calls": False,
|
|
},
|
|
{
|
|
"id": "success",
|
|
"scenario": "success",
|
|
"has_device": True,
|
|
"grab_ids": [111, 222],
|
|
"has_grabbed_bindings": True,
|
|
"expects_debug_tokens": False,
|
|
"expects_debug_message": False,
|
|
"expects_device_calls": True,
|
|
},
|
|
{
|
|
"id": "missing_grab",
|
|
"scenario": "missing_grab",
|
|
"has_device": True,
|
|
"grab_ids": [999],
|
|
"has_grabbed_bindings": False,
|
|
"expects_debug_tokens": False,
|
|
"expects_debug_message": True,
|
|
"expects_device_calls": True,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_remove_grabs_for_keybinding_scenarios(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.remove_grabs_for_keybinding with various scenarios."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
|
|
if case["has_device"]:
|
|
mock_device = test_context.Mock()
|
|
input_event_manager._device = mock_device
|
|
|
|
if case["has_grabbed_bindings"]:
|
|
input_event_manager._grabbed_bindings = {
|
|
111: test_context.Mock(),
|
|
222: test_context.Mock(),
|
|
}
|
|
|
|
mock_binding = test_context.Mock()
|
|
mock_binding.get_grab_ids.return_value = case["grab_ids"]
|
|
|
|
input_event_manager.remove_grabs_for_keybinding(mock_binding)
|
|
|
|
if case["expects_debug_tokens"]:
|
|
essential_modules["cthulhu.debug"].print_tokens.assert_called()
|
|
|
|
if case["expects_debug_message"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
if case["expects_device_calls"]:
|
|
if case["scenario"] == "success":
|
|
mock_device.remove_key_grab.assert_has_calls([call(111), call(222)])
|
|
assert 111 not in input_event_manager._grabbed_bindings
|
|
assert 222 not in input_event_manager._grabbed_bindings
|
|
elif case["scenario"] == "missing_grab":
|
|
mock_device.remove_key_grab.assert_called_once_with(999)
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "keysym_no_device",
|
|
"has_device": False,
|
|
"input_value": 0x61,
|
|
"expected_result": 0,
|
|
"device_method": None,
|
|
"device_return_value": None,
|
|
"mapped_collection": None,
|
|
},
|
|
{
|
|
"id": "keysym_success",
|
|
"has_device": True,
|
|
"input_value": 0x61,
|
|
"expected_result": 16,
|
|
"device_method": "map_keysym_modifier",
|
|
"device_return_value": 16,
|
|
"mapped_collection": "_mapped_keysyms",
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_map_keysym_to_modifier_scenarios(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.map_keysym_to_modifier with various scenarios."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
if case["has_device"]:
|
|
mock_device = test_context.Mock()
|
|
if case["device_method"]:
|
|
getattr(mock_device, case["device_method"]).return_value = case[
|
|
"device_return_value"
|
|
]
|
|
input_event_manager._device = mock_device
|
|
|
|
result = input_event_manager.map_keysym_to_modifier(case["input_value"])
|
|
|
|
assert result == case["expected_result"]
|
|
|
|
if case["has_device"] and case["device_method"] and case["mapped_collection"]:
|
|
getattr(mock_device, case["device_method"]).assert_called_once_with(case["input_value"])
|
|
collection = getattr(input_event_manager, case["mapped_collection"])
|
|
assert case["input_value"] in collection
|
|
elif not case["has_device"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "no_device",
|
|
"has_device": False,
|
|
"expects_debug_call": True,
|
|
"expects_unmap_calls": False,
|
|
},
|
|
{
|
|
"id": "success",
|
|
"has_device": True,
|
|
"expects_debug_call": False,
|
|
"expects_unmap_calls": True,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_unmap_all_modifiers_scenarios(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager.unmap_all_modifiers scenarios."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._mapped_keycodes = [42, 43]
|
|
input_event_manager._mapped_keysyms = [0x61, 0x62]
|
|
|
|
if case["has_device"]:
|
|
mock_device = test_context.Mock()
|
|
input_event_manager._device = mock_device
|
|
|
|
input_event_manager.unmap_all_modifiers()
|
|
|
|
if case["expects_debug_call"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
if case["expects_unmap_calls"]:
|
|
mock_device.unmap_modifier.assert_has_calls([call(42), call(43)])
|
|
mock_device.unmap_keysym_modifier.assert_has_calls([call(0x61), call(0x62)])
|
|
assert not input_event_manager._mapped_keycodes
|
|
assert not input_event_manager._mapped_keysyms
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "add_no_device",
|
|
"operation": "add",
|
|
"scenario": "no_device",
|
|
"has_device": False,
|
|
"grab_id": None,
|
|
"expected_result": -1,
|
|
"expects_debug_call": True,
|
|
},
|
|
{
|
|
"id": "add_success",
|
|
"operation": "add",
|
|
"scenario": "success",
|
|
"has_device": True,
|
|
"grab_id": 789,
|
|
"expected_result": 789,
|
|
"expects_debug_call": False,
|
|
},
|
|
{
|
|
"id": "remove_no_device",
|
|
"operation": "remove",
|
|
"scenario": "no_device",
|
|
"has_device": False,
|
|
"grab_id": 789,
|
|
"expected_result": None,
|
|
"expects_debug_call": True,
|
|
},
|
|
{
|
|
"id": "remove_success",
|
|
"operation": "remove",
|
|
"scenario": "success",
|
|
"has_device": True,
|
|
"grab_id": 789,
|
|
"expected_result": None,
|
|
"expects_debug_call": True,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_grab_for_modifier_scenarios(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager add/remove_grab_for_modifier scenarios."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
|
|
if case["has_device"]:
|
|
mock_device = test_context.Mock()
|
|
if case["operation"] == "add":
|
|
mock_device.add_key_grab.return_value = case["grab_id"]
|
|
input_event_manager._device = mock_device
|
|
|
|
if case["operation"] == "add":
|
|
result = input_event_manager.add_grab_for_modifier("Shift", 0xFFE1, 50)
|
|
if case["expected_result"] is not None:
|
|
assert result == case["expected_result"]
|
|
if case["has_device"] and case["scenario"] == "success":
|
|
mock_device.add_key_grab.assert_called_once()
|
|
else:
|
|
input_event_manager.remove_grab_for_modifier("Shift", case["grab_id"])
|
|
if case["has_device"] and case["scenario"] == "success":
|
|
mock_device.remove_key_grab.assert_called_once_with(case["grab_id"])
|
|
|
|
if case["expects_debug_call"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "grab_without_reason",
|
|
"operation": "grab",
|
|
"reason": None,
|
|
"expected_reason_text": None,
|
|
},
|
|
{
|
|
"id": "grab_with_reason",
|
|
"operation": "grab",
|
|
"reason": "learn mode",
|
|
"expected_reason_text": "learn mode",
|
|
},
|
|
{
|
|
"id": "ungrab_without_reason",
|
|
"operation": "ungrab",
|
|
"reason": None,
|
|
"expected_reason_text": None,
|
|
},
|
|
{
|
|
"id": "ungrab_with_reason",
|
|
"operation": "ungrab",
|
|
"reason": "exiting learn mode",
|
|
"expected_reason_text": "exiting learn mode",
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_keyboard_grab_scenarios(self, test_context: CthulhuTestContext, case: dict) -> None:
|
|
"""Test InputEventManager keyboard grab/ungrab operations with and without reasons."""
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_device = test_context.Mock()
|
|
input_event_manager._device = mock_device
|
|
|
|
if case["operation"] == "grab":
|
|
if case["reason"]:
|
|
input_event_manager.grab_keyboard(case["reason"])
|
|
else:
|
|
input_event_manager.grab_keyboard()
|
|
essential_modules["atspi"].Device.grab_keyboard.assert_called_once_with(mock_device)
|
|
else:
|
|
if case["reason"]:
|
|
input_event_manager.ungrab_keyboard(case["reason"])
|
|
else:
|
|
input_event_manager.ungrab_keyboard()
|
|
essential_modules["atspi"].Device.ungrab_keyboard.assert_called_once_with(mock_device)
|
|
|
|
if case["expected_reason_text"]:
|
|
debug_calls = essential_modules["cthulhu.debug"].print_message.call_args_list
|
|
assert any(case["expected_reason_text"] in str(call) for call in debug_calls)
|
|
|
|
def test_process_braille_event(self, test_context: CthulhuTestContext) -> None:
|
|
"""Test InputEventManager.process_braille_event."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_event = test_context.Mock()
|
|
result = input_event_manager.process_braille_event(mock_event)
|
|
assert result is True
|
|
assert isinstance(
|
|
input_event_manager._last_input_event,
|
|
essential_modules["cthulhu.input_event"].BrailleEvent,
|
|
)
|
|
assert input_event_manager._last_non_modifier_key_event is None
|
|
|
|
def test_process_mouse_button_event(self, test_context: CthulhuTestContext) -> None:
|
|
"""Test InputEventManager.process_mouse_button_event."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_event = test_context.Mock()
|
|
input_event_manager._determine_mouse_event_click_count = test_context.Mock(return_value=2)
|
|
input_event_manager.process_mouse_button_event(mock_event)
|
|
assert isinstance(
|
|
input_event_manager._last_input_event,
|
|
essential_modules["cthulhu.input_event"].MouseButtonEvent,
|
|
)
|
|
input_event_manager._last_input_event.set_click_count.assert_called_once_with(2)
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "key_press_active_window",
|
|
"pressed": True,
|
|
"keycode": 65,
|
|
"keysym": 97,
|
|
"modifiers": 0,
|
|
"text": "a",
|
|
"window_can_be_active": True,
|
|
"new_window_found": None,
|
|
},
|
|
{
|
|
"id": "key_press_inactive_window_with_alternative",
|
|
"pressed": True,
|
|
"keycode": 65,
|
|
"keysym": 97,
|
|
"modifiers": 0,
|
|
"text": "a",
|
|
"window_can_be_active": False,
|
|
"new_window_found": "mock_window",
|
|
},
|
|
{
|
|
"id": "key_press_inactive_window_no_alternative",
|
|
"pressed": True,
|
|
"keycode": 65,
|
|
"keysym": 97,
|
|
"modifiers": 0,
|
|
"text": "a",
|
|
"window_can_be_active": False,
|
|
"new_window_found": None,
|
|
},
|
|
{
|
|
"id": "key_release",
|
|
"pressed": False,
|
|
"keycode": 65,
|
|
"keysym": 97,
|
|
"modifiers": 0,
|
|
"text": "a",
|
|
"window_can_be_active": True,
|
|
"new_window_found": None,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_process_keyboard_event(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager.process_keyboard_event."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
new_window_found = case["new_window_found"]
|
|
if new_window_found == "mock_window":
|
|
new_window_found = test_context.Mock()
|
|
mock_device = test_context.Mock()
|
|
mock_window = test_context.Mock()
|
|
mock_focus = test_context.Mock()
|
|
mock_script = test_context.Mock()
|
|
mock_focus_manager = essential_modules["cthulhu.focus_manager"]
|
|
mock_focus_manager.get_active_window.return_value = mock_window
|
|
mock_focus_manager.get_locus_of_focus.return_value = mock_focus
|
|
mock_script_manager = essential_modules["cthulhu.script_manager"]
|
|
mock_script_manager.get_active_script.return_value = mock_script
|
|
essential_modules["ax_utilities_class"].can_be_active_window.return_value = case[
|
|
"window_can_be_active"
|
|
]
|
|
essential_modules["ax_utilities_class"].find_active_window.return_value = new_window_found
|
|
input_event_manager._determine_keyboard_event_click_count = test_context.Mock(
|
|
return_value=1,
|
|
)
|
|
result = input_event_manager.process_keyboard_event(
|
|
mock_device,
|
|
case["pressed"],
|
|
case["keycode"],
|
|
case["keysym"],
|
|
case["modifiers"],
|
|
case["text"],
|
|
)
|
|
assert result is True
|
|
assert isinstance(
|
|
input_event_manager._last_input_event,
|
|
essential_modules["cthulhu.input_event"].KeyboardEvent,
|
|
)
|
|
input_event_manager._last_input_event.process.assert_called_once()
|
|
|
|
def test_process_keyboard_event_duplicate(self, test_context: CthulhuTestContext) -> None:
|
|
"""Test InputEventManager.process_keyboard_event with duplicate event."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_device = test_context.Mock()
|
|
keyboard_event_instance = essential_modules["cthulhu.input_event"].KeyboardEvent(
|
|
True,
|
|
65,
|
|
97,
|
|
0,
|
|
"a",
|
|
)
|
|
input_event_manager._last_input_event = keyboard_event_instance
|
|
result = input_event_manager.process_keyboard_event(mock_device, True, 65, 97, 0, "a")
|
|
assert result is False
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "keyboard_true",
|
|
"method_name": "last_event_was_keyboard",
|
|
"event_class_name": "KeyboardEvent",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "keyboard_false",
|
|
"method_name": "last_event_was_keyboard",
|
|
"event_class_name": "MouseButtonEvent",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "mouse_button_true",
|
|
"method_name": "last_event_was_mouse_button",
|
|
"event_class_name": "MouseButtonEvent",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "mouse_button_false",
|
|
"method_name": "last_event_was_mouse_button",
|
|
"event_class_name": "KeyboardEvent",
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_basic_event_types(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager basic event type detection methods."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
|
|
if case["event_class_name"] == "KeyboardEvent":
|
|
event_class = essential_modules["cthulhu.input_event"].KeyboardEvent
|
|
mock_event = event_class()
|
|
elif case["event_class_name"] == "MouseButtonEvent":
|
|
event_class = essential_modules["cthulhu.input_event"].MouseButtonEvent
|
|
mock_event = event_class()
|
|
else:
|
|
mock_event = test_context.Mock()
|
|
|
|
input_event_manager._last_input_event = mock_event
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result is case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "event1_none",
|
|
"event1": None,
|
|
"event2": "mock_event",
|
|
"event1_pressed": None,
|
|
"event2_pressed": None,
|
|
"same_id": None,
|
|
"same_hw_code": None,
|
|
"same_keyval": None,
|
|
"event1_modifier": None,
|
|
"same_modifiers": None,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "event2_none",
|
|
"event1": "mock_event",
|
|
"event2": None,
|
|
"event1_pressed": None,
|
|
"event2_pressed": None,
|
|
"same_id": None,
|
|
"same_hw_code": None,
|
|
"same_keyval": None,
|
|
"event1_modifier": None,
|
|
"same_modifiers": None,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "release_for_press",
|
|
"event1": "mock_event1",
|
|
"event2": "mock_event2",
|
|
"event1_pressed": False,
|
|
"event2_pressed": True,
|
|
"same_id": True,
|
|
"same_hw_code": True,
|
|
"same_keyval": True,
|
|
"event1_modifier": False,
|
|
"same_modifiers": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "both_pressed",
|
|
"event1": "mock_event1",
|
|
"event2": "mock_event2",
|
|
"event1_pressed": True,
|
|
"event2_pressed": True,
|
|
"same_id": True,
|
|
"same_hw_code": True,
|
|
"same_keyval": True,
|
|
"event1_modifier": False,
|
|
"same_modifiers": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "both_released",
|
|
"event1": "mock_event1",
|
|
"event2": "mock_event2",
|
|
"event1_pressed": False,
|
|
"event2_pressed": False,
|
|
"same_id": True,
|
|
"same_hw_code": True,
|
|
"same_keyval": True,
|
|
"event1_modifier": False,
|
|
"same_modifiers": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "different_id",
|
|
"event1": "mock_event1",
|
|
"event2": "mock_event2",
|
|
"event1_pressed": False,
|
|
"event2_pressed": True,
|
|
"same_id": False,
|
|
"same_hw_code": True,
|
|
"same_keyval": True,
|
|
"event1_modifier": False,
|
|
"same_modifiers": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "modifier_key_ignore_modifiers",
|
|
"event1": "mock_event1",
|
|
"event2": "mock_event2",
|
|
"event1_pressed": False,
|
|
"event2_pressed": True,
|
|
"same_id": True,
|
|
"same_hw_code": True,
|
|
"same_keyval": True,
|
|
"event1_modifier": True,
|
|
"same_modifiers": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "modifier_key_different_modifiers",
|
|
"event1": "mock_event1",
|
|
"event2": "mock_event2",
|
|
"event1_pressed": False,
|
|
"event2_pressed": True,
|
|
"same_id": True,
|
|
"same_hw_code": True,
|
|
"same_keyval": True,
|
|
"event1_modifier": True,
|
|
"same_modifiers": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "non_modifier_different_modifiers",
|
|
"event1": "mock_event1",
|
|
"event2": "mock_event2",
|
|
"event1_pressed": False,
|
|
"event2_pressed": True,
|
|
"same_id": True,
|
|
"same_hw_code": True,
|
|
"same_keyval": True,
|
|
"event1_modifier": False,
|
|
"same_modifiers": False,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_is_release_for(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.is_release_for."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
event1 = case["event1"]
|
|
event2 = case["event2"]
|
|
if event1 in ("mock_event", "mock_event1"):
|
|
event1 = test_context.Mock()
|
|
if event2 in ("mock_event", "mock_event2"):
|
|
event2 = test_context.Mock()
|
|
if event1 is not None and event2 is not None:
|
|
keyboard_event_class = essential_modules["cthulhu.input_event"].KeyboardEvent
|
|
event1 = keyboard_event_class()
|
|
event2 = keyboard_event_class()
|
|
event1.is_pressed_key.return_value = case["event1_pressed"]
|
|
event2.is_pressed_key.return_value = case["event2_pressed"]
|
|
event1.id = "test_id" if case["same_id"] else "other_id"
|
|
event2.id = "test_id"
|
|
event1.hw_code = 42 if case["same_hw_code"] else 43
|
|
event2.hw_code = 42
|
|
event1.keyval_name = "a" if case["same_keyval"] else "b"
|
|
event2.keyval_name = "a"
|
|
event1.is_modifier_key.return_value = case["event1_modifier"]
|
|
event1.modifiers = 4 if case["same_modifiers"] else 8
|
|
event2.modifiers = 4
|
|
event1.as_single_line_string.return_value = "event1"
|
|
event2.as_single_line_string.return_value = "event2"
|
|
result = input_event_manager.is_release_for(event1, event2)
|
|
assert result == case["expected_result"]
|
|
|
|
def test_last_event_equals_or_is_release_for_event_no_last_event(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_equals_or_is_release_for_event with no last event."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_event = test_context.Mock()
|
|
result = input_event_manager.last_event_equals_or_is_release_for_event(mock_event)
|
|
assert result is False
|
|
|
|
def test_last_event_equals_or_is_release_for_event_equal(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_equals_or_is_release_for_event with equal events."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_event = test_context.Mock()
|
|
input_event_manager._last_non_modifier_key_event = mock_event
|
|
input_event_manager.last_event_was_keyboard = test_context.Mock(return_value=True)
|
|
result = input_event_manager.last_event_equals_or_is_release_for_event(mock_event)
|
|
assert result is True
|
|
|
|
def test_last_event_equals_or_is_release_for_event_is_release(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_equals_or_is_release_for_event with release event."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_event = test_context.Mock()
|
|
mock_last_event = test_context.Mock()
|
|
input_event_manager._last_non_modifier_key_event = mock_last_event
|
|
input_event_manager.last_event_was_keyboard = test_context.Mock(return_value=True)
|
|
|
|
input_event_manager.is_release_for = test_context.Mock(return_value=True)
|
|
result = input_event_manager.last_event_equals_or_is_release_for_event(mock_event)
|
|
assert result is True
|
|
input_event_manager.is_release_for.assert_called_once_with(mock_last_event, mock_event)
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "no_last_non_modifier",
|
|
"has_last_non_modifier": False,
|
|
"last_event_keyboard": True,
|
|
"expected_key": "",
|
|
"expected_modifiers": 0,
|
|
},
|
|
{
|
|
"id": "last_not_keyboard",
|
|
"has_last_non_modifier": True,
|
|
"last_event_keyboard": False,
|
|
"expected_key": "",
|
|
"expected_modifiers": 0,
|
|
},
|
|
{
|
|
"id": "has_both",
|
|
"has_last_non_modifier": True,
|
|
"last_event_keyboard": True,
|
|
"expected_key": "a",
|
|
"expected_modifiers": 4,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_key_and_modifiers(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager._last_key_and_modifiers."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
if case["has_last_non_modifier"]:
|
|
mock_last_non_modifier = test_context.Mock()
|
|
mock_last_non_modifier.keyval_name = "a"
|
|
input_event_manager._last_non_modifier_key_event = mock_last_non_modifier
|
|
else:
|
|
input_event_manager._last_non_modifier_key_event = None
|
|
if case["last_event_keyboard"]:
|
|
mock_last_event = test_context.Mock()
|
|
mock_last_event.modifiers = 4
|
|
input_event_manager._last_input_event = mock_last_event
|
|
input_event_manager.last_event_was_keyboard = test_context.Mock(
|
|
return_value=case["last_event_keyboard"],
|
|
)
|
|
result = input_event_manager._last_key_and_modifiers()
|
|
assert result == (case["expected_key"], case["expected_modifiers"])
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "command_true",
|
|
"method_name": "last_event_was_command",
|
|
"key_modifiers": ("a", 1 << 2),
|
|
"expected_result": True,
|
|
"expects_debug": True,
|
|
},
|
|
{
|
|
"id": "command_false",
|
|
"method_name": "last_event_was_command",
|
|
"key_modifiers": ("a", 0),
|
|
"expected_result": False,
|
|
"expects_debug": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_command(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager command detection methods."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=case["key_modifiers"],
|
|
)
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result is case["expected_result"]
|
|
|
|
if case["expects_debug"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
else:
|
|
essential_modules["cthulhu.debug"].print_message.assert_not_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "empty_key_string",
|
|
"key_string": "",
|
|
"has_shortcut": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "matching_shortcut",
|
|
"key_string": "f",
|
|
"has_shortcut": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "no_matching_shortcut",
|
|
"key_string": "f",
|
|
"has_shortcut": False,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_shortcut_for(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_shortcut_for."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_obj = test_context.Mock()
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], 0),
|
|
)
|
|
ax_utilities_class = essential_modules["cthulhu.ax_utilities"].AXUtilities
|
|
ax_utilities_class.has_matching_shortcut.return_value = case["has_shortcut"]
|
|
result = input_event_manager.last_event_was_shortcut_for(mock_obj)
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_tokens.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "printable_key_true",
|
|
"is_keyboard": True,
|
|
"is_printable": True,
|
|
"expected_result": True,
|
|
"expects_debug": True,
|
|
},
|
|
{
|
|
"id": "not_keyboard",
|
|
"is_keyboard": False,
|
|
"is_printable": None,
|
|
"expected_result": False,
|
|
"expects_debug": False,
|
|
},
|
|
{
|
|
"id": "not_printable",
|
|
"is_keyboard": True,
|
|
"is_printable": False,
|
|
"expected_result": False,
|
|
"expects_debug": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_printable_key(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_printable_key with various scenarios."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager.last_event_was_keyboard = test_context.Mock(
|
|
return_value=case["is_keyboard"],
|
|
)
|
|
|
|
if case["is_keyboard"] and case["is_printable"] is not None:
|
|
mock_last_event = test_context.Mock()
|
|
mock_last_event.is_printable_key.return_value = case["is_printable"]
|
|
input_event_manager._last_input_event = mock_last_event
|
|
|
|
result = input_event_manager.last_event_was_printable_key()
|
|
assert result is case["expected_result"]
|
|
|
|
if case["expects_debug"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
else:
|
|
essential_modules["cthulhu.debug"].print_message.assert_not_called()
|
|
|
|
def test_last_event_was_caret_navigation(self, test_context: CthulhuTestContext) -> None:
|
|
"""Test InputEventManager.last_event_was_caret_navigation."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager.last_event_was_character_navigation = test_context.Mock(
|
|
return_value=False,
|
|
)
|
|
input_event_manager.last_event_was_word_navigation = test_context.Mock(return_value=True)
|
|
input_event_manager.last_event_was_line_navigation = test_context.Mock(return_value=False)
|
|
input_event_manager.last_event_was_line_boundary_navigation = test_context.Mock(
|
|
return_value=False,
|
|
)
|
|
input_event_manager.last_event_was_file_boundary_navigation = test_context.Mock(
|
|
return_value=False,
|
|
)
|
|
input_event_manager.last_event_was_page_navigation = test_context.Mock(return_value=False)
|
|
result = input_event_manager.last_event_was_caret_navigation()
|
|
assert result is True
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "left_with_shift",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "right_with_shift",
|
|
"key_string": "Right",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "up_with_shift",
|
|
"key_string": "Up",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "down_with_shift",
|
|
"key_string": "Down",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "left_without_shift",
|
|
"key_string": "Left",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "non_arrow_with_shift",
|
|
"key_string": "a",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_caret_selection(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_caret_selection."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_caret_selection()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{"id": "up_without_shift", "key_string": "Up", "modifiers": 0, "expected_result": True},
|
|
{
|
|
"id": "left_without_shift",
|
|
"key_string": "Left",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "down_without_shift",
|
|
"key_string": "Down",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "right_without_shift",
|
|
"key_string": "Right",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "up_with_shift",
|
|
"key_string": "Up",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "non_arrow", "key_string": "a", "modifiers": 0, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_backward_caret_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_backward_caret_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_backward_caret_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "down_without_shift",
|
|
"key_string": "Down",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "right_without_shift",
|
|
"key_string": "Right",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "up_without_shift",
|
|
"key_string": "Up",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "left_without_shift",
|
|
"key_string": "Left",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "down_with_shift",
|
|
"key_string": "Down",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "non_arrow", "key_string": "a", "modifiers": 0, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_forward_caret_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_forward_caret_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_forward_caret_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "down_with_shift",
|
|
"key_string": "Down",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "right_with_shift",
|
|
"key_string": "Right",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "up_with_shift",
|
|
"key_string": "Up",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "left_with_shift",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "down_without_shift",
|
|
"key_string": "Down",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "non_arrow", "key_string": "a", "modifiers": 1 << 0, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_forward_caret_selection(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_forward_caret_selection."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_forward_caret_selection()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "left_no_modifiers",
|
|
"key_string": "Left",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "right_no_modifiers",
|
|
"key_string": "Right",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "left_with_ctrl",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "right_with_alt",
|
|
"key_string": "Right",
|
|
"modifiers": 1 << 3,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "non_horizontal_arrow",
|
|
"key_string": "Up",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "non_arrow", "key_string": "a", "modifiers": 0, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_character_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_character_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_character_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "left_with_ctrl",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "right_with_ctrl",
|
|
"key_string": "Right",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{"id": "left_no_ctrl", "key_string": "Left", "modifiers": 0, "expected_result": False},
|
|
{
|
|
"id": "right_no_ctrl",
|
|
"key_string": "Right",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "non_horizontal_arrow",
|
|
"key_string": "Up",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "non_arrow", "key_string": "a", "modifiers": 1 << 2, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_word_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_word_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_word_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "left_with_ctrl",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "right_with_ctrl",
|
|
"key_string": "Right",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "left_no_ctrl", "key_string": "Left", "modifiers": 0, "expected_result": False},
|
|
{"id": "non_arrow", "key_string": "a", "modifiers": 1 << 2, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_previous_word_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_previous_word_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_previous_word_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "right_with_ctrl",
|
|
"key_string": "Right",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "left_with_ctrl",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "right_no_ctrl",
|
|
"key_string": "Right",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "non_arrow", "key_string": "a", "modifiers": 1 << 2, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_next_word_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_next_word_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_next_word_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "up_multiline_not_controlled",
|
|
"key_string": "Up",
|
|
"modifiers": 0,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "down_multiline_not_controlled",
|
|
"key_string": "Down",
|
|
"modifiers": 0,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "up_with_ctrl",
|
|
"key_string": "Up",
|
|
"modifiers": 1 << 2,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "up_single_line",
|
|
"key_string": "Up",
|
|
"modifiers": 0,
|
|
"is_single_line": True,
|
|
"is_widget_controlled": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "up_widget_controlled",
|
|
"key_string": "Up",
|
|
"modifiers": 0,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "non_vertical_arrow",
|
|
"key_string": "Left",
|
|
"modifiers": 0,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": False,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_line_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_line_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
mock_focus = test_context.Mock()
|
|
essential_modules["cthulhu.focus_manager"].get_locus_of_focus.return_value = mock_focus
|
|
essential_modules["ax_utilities_class"].is_single_line.return_value = case["is_single_line"]
|
|
essential_modules[
|
|
"ax_utilities_class"
|
|
].is_widget_controlled_by_line_navigation.return_value = case["is_widget_controlled"]
|
|
result = input_event_manager.last_event_was_line_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "up_with_ctrl_no_shift",
|
|
"key_string": "Up",
|
|
"modifiers": (1 << 2),
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "down_with_ctrl_no_shift",
|
|
"key_string": "Down",
|
|
"modifiers": (1 << 2),
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "up_with_ctrl_and_shift",
|
|
"key_string": "Up",
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"expected_result": False,
|
|
},
|
|
{"id": "up_no_ctrl", "key_string": "Up", "modifiers": 0, "expected_result": False},
|
|
{
|
|
"id": "non_vertical_arrow",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_paragraph_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_paragraph_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_paragraph_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{"id": "home_no_ctrl", "key_string": "Home", "modifiers": 0, "expected_result": True},
|
|
{"id": "end_no_ctrl", "key_string": "End", "modifiers": 0, "expected_result": True},
|
|
{
|
|
"id": "home_with_ctrl",
|
|
"key_string": "Home",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "end_with_ctrl",
|
|
"key_string": "End",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "non_boundary_key",
|
|
"key_string": "Left",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_line_boundary_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_line_boundary_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_line_boundary_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "home_with_ctrl",
|
|
"key_string": "Home",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "end_with_ctrl",
|
|
"key_string": "End",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{"id": "home_no_ctrl", "key_string": "Home", "modifiers": 0, "expected_result": False},
|
|
{"id": "end_no_ctrl", "key_string": "End", "modifiers": 0, "expected_result": False},
|
|
{
|
|
"id": "non_boundary_key",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_file_boundary_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_file_boundary_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_file_boundary_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "page_up_multiline_not_controlled",
|
|
"key_string": "Page_Up",
|
|
"modifiers": 0,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "page_down_multiline_not_controlled",
|
|
"key_string": "Page_Down",
|
|
"modifiers": 0,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "page_up_with_ctrl",
|
|
"key_string": "Page_Up",
|
|
"modifiers": 1 << 2,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "page_up_single_line",
|
|
"key_string": "Page_Up",
|
|
"modifiers": 0,
|
|
"is_single_line": True,
|
|
"is_widget_controlled": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "page_up_widget_controlled",
|
|
"key_string": "Page_Up",
|
|
"modifiers": 0,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "non_page_key",
|
|
"key_string": "Left",
|
|
"modifiers": 0,
|
|
"is_single_line": False,
|
|
"is_widget_controlled": False,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_page_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_page_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
mock_focus = test_context.Mock()
|
|
essential_modules["cthulhu.focus_manager"].get_locus_of_focus.return_value = mock_focus
|
|
essential_modules["ax_utilities_class"].is_single_line.return_value = case["is_single_line"]
|
|
essential_modules[
|
|
"ax_utilities_class"
|
|
].is_widget_controlled_by_line_navigation.return_value = case["is_widget_controlled"]
|
|
result = input_event_manager.last_event_was_page_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "numeric_with_alt",
|
|
"key_string": "1",
|
|
"modifiers": 1 << 3,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "numeric_2_with_alt",
|
|
"key_string": "2",
|
|
"modifiers": 1 << 3,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "page_up_with_ctrl",
|
|
"key_string": "Page_Up",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "page_down_with_ctrl",
|
|
"key_string": "Page_Down",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{"id": "numeric_no_alt", "key_string": "1", "modifiers": 0, "expected_result": False},
|
|
{
|
|
"id": "page_up_no_ctrl",
|
|
"key_string": "Page_Up",
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "non_numeric_non_page",
|
|
"key_string": "a",
|
|
"modifiers": 1 << 3,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_page_switch(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_page_switch."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_page_switch()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "tab_no_modifiers",
|
|
"key_string": "Tab",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "shift_tab_no_modifiers",
|
|
"key_string": "ISO_Left_Tab",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "tab_with_ctrl",
|
|
"key_string": "Tab",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "tab_with_alt",
|
|
"key_string": "Tab",
|
|
"modifiers": 1 << 3,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "non_tab_key", "key_string": "a", "modifiers": 0, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_tab_navigation(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_tab_navigation."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_tab_navigation()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "not_table_header",
|
|
"is_table_header": False,
|
|
"is_mouse_button": True,
|
|
"is_primary_click": True,
|
|
"is_keyboard": False,
|
|
"is_return_or_space": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "table_header_mouse_primary_click",
|
|
"is_table_header": True,
|
|
"is_mouse_button": True,
|
|
"is_primary_click": True,
|
|
"is_keyboard": False,
|
|
"is_return_or_space": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "table_header_mouse_not_primary",
|
|
"is_table_header": True,
|
|
"is_mouse_button": True,
|
|
"is_primary_click": False,
|
|
"is_keyboard": False,
|
|
"is_return_or_space": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "table_header_keyboard_return_space",
|
|
"is_table_header": True,
|
|
"is_mouse_button": False,
|
|
"is_primary_click": False,
|
|
"is_keyboard": True,
|
|
"is_return_or_space": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "table_header_keyboard_not_return_space",
|
|
"is_table_header": True,
|
|
"is_mouse_button": False,
|
|
"is_primary_click": False,
|
|
"is_keyboard": True,
|
|
"is_return_or_space": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "table_header_neither_mouse_nor_keyboard",
|
|
"is_table_header": True,
|
|
"is_mouse_button": False,
|
|
"is_primary_click": False,
|
|
"is_keyboard": False,
|
|
"is_return_or_space": False,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_table_sort(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_table_sort."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_focus = test_context.Mock()
|
|
essential_modules["cthulhu.focus_manager"].get_locus_of_focus.return_value = mock_focus
|
|
essential_modules["ax_utilities_class"].is_table_header.return_value = case[
|
|
"is_table_header"
|
|
]
|
|
input_event_manager.last_event_was_mouse_button = test_context.Mock(
|
|
return_value=case["is_mouse_button"],
|
|
)
|
|
input_event_manager.last_event_was_primary_click = test_context.Mock(
|
|
return_value=case["is_primary_click"],
|
|
)
|
|
input_event_manager.last_event_was_keyboard = test_context.Mock(
|
|
return_value=case["is_keyboard"],
|
|
)
|
|
input_event_manager.last_event_was_return_or_space = test_context.Mock(
|
|
return_value=case["is_return_or_space"],
|
|
)
|
|
result = input_event_manager.last_event_was_table_sort()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "left_no_modifiers",
|
|
"key_string": "Left",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "right_no_modifiers",
|
|
"key_string": "Right",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{"id": "up_no_modifiers", "key_string": "Up", "modifiers": 0, "expected_result": True},
|
|
{
|
|
"id": "down_no_modifiers",
|
|
"key_string": "Down",
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "left_with_ctrl",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "left_with_shift",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "left_with_alt",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 3,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "left_with_cthulhu_modifier",
|
|
"key_string": "Left",
|
|
"modifiers": 1 << 8,
|
|
"expected_result": False,
|
|
},
|
|
{"id": "non_arrow_key", "key_string": "a", "modifiers": 0, "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_unmodified_arrow(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_unmodified_arrow."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_unmodified_arrow()
|
|
assert result == case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "has_alt_modifier",
|
|
"modifiers": 1 << 3,
|
|
"expected_result": 8,
|
|
}, # Returns bitwise result, not boolean
|
|
{"id": "no_alt_modifier", "modifiers": 0, "expected_result": 0},
|
|
{
|
|
"id": "alt_and_ctrl_modifiers",
|
|
"modifiers": (1 << 3) | (1 << 2),
|
|
"expected_result": 8,
|
|
}, # Alt bit is still 8
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_alt_modified(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager.last_event_was_alt_modified."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=("a", case["modifiers"]),
|
|
)
|
|
result = input_event_manager.last_event_was_alt_modified()
|
|
assert result == case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{"id": "backspace_key", "key_string": "BackSpace", "expected_result": True},
|
|
{"id": "delete_key", "key_string": "Delete", "expected_result": False},
|
|
{"id": "regular_key", "key_string": "a", "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_backspace(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager.last_event_was_backspace."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], 0),
|
|
)
|
|
result = input_event_manager.last_event_was_backspace()
|
|
assert result == case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{"id": "down_key", "key_string": "Down", "expected_result": True},
|
|
{"id": "up_key", "key_string": "Up", "expected_result": False},
|
|
{"id": "regular_key", "key_string": "a", "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_down(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager.last_event_was_down."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], 0),
|
|
)
|
|
result = input_event_manager.last_event_was_down()
|
|
assert result == case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{"id": "f1_key", "key_string": "F1", "expected_result": True},
|
|
{"id": "f2_key", "key_string": "F2", "expected_result": False},
|
|
{"id": "regular_key", "key_string": "a", "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_f1(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager.last_event_was_f1."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], 0),
|
|
)
|
|
result = input_event_manager.last_event_was_f1()
|
|
assert result == case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{"id": "left_key", "key_string": "Left", "expected_result": True},
|
|
{"id": "right_key", "key_string": "Right", "expected_result": False},
|
|
{"id": "regular_key", "key_string": "a", "expected_result": False},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_left(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager.last_event_was_left."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], 0),
|
|
)
|
|
result = input_event_manager.last_event_was_left()
|
|
assert result == case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "left_or_right_left_key",
|
|
"method_name": "last_event_was_left_or_right",
|
|
"key_string": "Left",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "left_or_right_right_key",
|
|
"method_name": "last_event_was_left_or_right",
|
|
"key_string": "Right",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "left_or_right_up_key",
|
|
"method_name": "last_event_was_left_or_right",
|
|
"key_string": "Up",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "page_up_or_down_page_up",
|
|
"method_name": "last_event_was_page_up_or_page_down",
|
|
"key_string": "Page_Up",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "page_up_or_down_page_down",
|
|
"method_name": "last_event_was_page_up_or_page_down",
|
|
"key_string": "Page_Down",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "page_up_or_down_up_key",
|
|
"method_name": "last_event_was_page_up_or_page_down",
|
|
"key_string": "Up",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "right_right_key",
|
|
"method_name": "last_event_was_right",
|
|
"key_string": "Right",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "right_left_key",
|
|
"method_name": "last_event_was_right",
|
|
"key_string": "Left",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "return_return_key",
|
|
"method_name": "last_event_was_return",
|
|
"key_string": "Return",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "return_enter_key",
|
|
"method_name": "last_event_was_return",
|
|
"key_string": "Enter",
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_single_key_detection(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager single key detection methods."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], 0),
|
|
)
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result == case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "return_or_space_return",
|
|
"method_name": "last_event_was_return_or_space",
|
|
"key_string": "Return",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "return_or_space_space_key",
|
|
"method_name": "last_event_was_return_or_space",
|
|
"key_string": "space",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "return_or_space_space_char",
|
|
"method_name": "last_event_was_return_or_space",
|
|
"key_string": " ",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "return_or_space_enter",
|
|
"method_name": "last_event_was_return_or_space",
|
|
"key_string": "Enter",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "return_tab_space_return",
|
|
"method_name": "last_event_was_return_tab_or_space",
|
|
"key_string": "Return",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "return_tab_space_tab",
|
|
"method_name": "last_event_was_return_tab_or_space",
|
|
"key_string": "Tab",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "return_tab_space_space_key",
|
|
"method_name": "last_event_was_return_tab_or_space",
|
|
"key_string": "space",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "return_tab_space_space_char",
|
|
"method_name": "last_event_was_return_tab_or_space",
|
|
"key_string": " ",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "return_tab_space_enter",
|
|
"method_name": "last_event_was_return_tab_or_space",
|
|
"key_string": "Enter",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "space_space_character",
|
|
"method_name": "last_event_was_space",
|
|
"key_string": " ",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "space_space_key",
|
|
"method_name": "last_event_was_space",
|
|
"key_string": "space",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "space_return_key",
|
|
"method_name": "last_event_was_space",
|
|
"key_string": "Return",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "tab_tab_key",
|
|
"method_name": "last_event_was_tab",
|
|
"key_string": "Tab",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "tab_shift_tab_key",
|
|
"method_name": "last_event_was_tab",
|
|
"key_string": "ISO_Left_Tab",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "up_up_key",
|
|
"method_name": "last_event_was_up",
|
|
"key_string": "Up",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "up_down_key",
|
|
"method_name": "last_event_was_up",
|
|
"key_string": "Down",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "up_or_down_up_key",
|
|
"method_name": "last_event_was_up_or_down",
|
|
"key_string": "Up",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "up_or_down_down_key",
|
|
"method_name": "last_event_was_up_or_down",
|
|
"key_string": "Down",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "up_or_down_left_key",
|
|
"method_name": "last_event_was_up_or_down",
|
|
"key_string": "Left",
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_composite_key_detection(self, test_context, case: dict) -> None:
|
|
"""Test InputEventManager composite key detection methods."""
|
|
|
|
input_event_manager, _essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["key_string"], 0),
|
|
)
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result == case["expected_result"]
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "delete_delete_key",
|
|
"method_name": "last_event_was_delete",
|
|
"keynames": ["Delete"],
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "delete_keypad_delete",
|
|
"method_name": "last_event_was_delete",
|
|
"keynames": ["KP_Delete"],
|
|
"modifiers": 0,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "delete_ctrl_d",
|
|
"method_name": "last_event_was_delete",
|
|
"keynames": ["d"],
|
|
"modifiers": 1 << 2,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "delete_d_without_ctrl",
|
|
"method_name": "last_event_was_delete",
|
|
"keynames": ["d"],
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "delete_unknown_key",
|
|
"method_name": "last_event_was_delete",
|
|
"keynames": ["x"],
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "cut_ctrl_x",
|
|
"method_name": "last_event_was_cut",
|
|
"keynames": ["x"],
|
|
"modifiers": (1 << 2),
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "cut_ctrl_shift_x",
|
|
"method_name": "last_event_was_cut",
|
|
"keynames": ["x"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "cut_x_without_ctrl",
|
|
"method_name": "last_event_was_cut",
|
|
"keynames": ["x"],
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "cut_ctrl_y",
|
|
"method_name": "last_event_was_cut",
|
|
"keynames": ["y"],
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_simple_editing_actions(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager simple editing action methods."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["keynames"][0] if case["keynames"] else "", case["modifiers"]),
|
|
)
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "copy_ctrl_c_non_terminal",
|
|
"method_name": "last_event_was_copy",
|
|
"keynames": ["c"],
|
|
"modifiers": (1 << 2),
|
|
"is_terminal": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "copy_ctrl_shift_c_terminal",
|
|
"method_name": "last_event_was_copy",
|
|
"keynames": ["c"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"is_terminal": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "copy_ctrl_shift_c_non_terminal",
|
|
"method_name": "last_event_was_copy",
|
|
"keynames": ["c"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"is_terminal": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "copy_ctrl_c_terminal",
|
|
"method_name": "last_event_was_copy",
|
|
"keynames": ["c"],
|
|
"modifiers": (1 << 2),
|
|
"is_terminal": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "copy_c_without_ctrl",
|
|
"method_name": "last_event_was_copy",
|
|
"keynames": ["c"],
|
|
"modifiers": 0,
|
|
"is_terminal": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "paste_ctrl_v_non_terminal",
|
|
"method_name": "last_event_was_paste",
|
|
"keynames": ["v"],
|
|
"modifiers": (1 << 2),
|
|
"is_terminal": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "paste_ctrl_shift_v_terminal",
|
|
"method_name": "last_event_was_paste",
|
|
"keynames": ["v"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"is_terminal": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "paste_ctrl_shift_v_non_terminal",
|
|
"method_name": "last_event_was_paste",
|
|
"keynames": ["v"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"is_terminal": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "paste_ctrl_v_terminal",
|
|
"method_name": "last_event_was_paste",
|
|
"keynames": ["v"],
|
|
"modifiers": (1 << 2),
|
|
"is_terminal": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "paste_v_without_ctrl",
|
|
"method_name": "last_event_was_paste",
|
|
"keynames": ["v"],
|
|
"modifiers": 0,
|
|
"is_terminal": False,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_terminal_aware_editing_actions(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager terminal-aware editing action methods."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_object = test_context.Mock()
|
|
mock_last_event = test_context.Mock()
|
|
mock_last_event.get_object.return_value = mock_object
|
|
input_event_manager._last_input_event = mock_last_event
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["keynames"][0] if case["keynames"] else "", case["modifiers"]),
|
|
)
|
|
essential_modules["ax_utilities_class"].is_terminal.return_value = case["is_terminal"]
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "undo_ctrl_z",
|
|
"method_name": "last_event_was_undo",
|
|
"keynames": ["z"],
|
|
"modifiers": (1 << 2),
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "undo_ctrl_shift_z",
|
|
"method_name": "last_event_was_undo",
|
|
"keynames": ["z"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "undo_z_without_ctrl",
|
|
"method_name": "last_event_was_undo",
|
|
"keynames": ["z"],
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "undo_ctrl_y",
|
|
"method_name": "last_event_was_undo",
|
|
"keynames": ["y"],
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "redo_ctrl_shift_z",
|
|
"method_name": "last_event_was_redo",
|
|
"keynames": ["z"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "redo_ctrl_y_libreoffice",
|
|
"method_name": "last_event_was_redo",
|
|
"keynames": ["y"],
|
|
"modifiers": (1 << 2),
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "redo_ctrl_z",
|
|
"method_name": "last_event_was_redo",
|
|
"keynames": ["z"],
|
|
"modifiers": (1 << 2),
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "redo_ctrl_shift_y",
|
|
"method_name": "last_event_was_redo",
|
|
"keynames": ["y"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "redo_z_without_ctrl",
|
|
"method_name": "last_event_was_redo",
|
|
"keynames": ["z"],
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "redo_unknown_key",
|
|
"method_name": "last_event_was_redo",
|
|
"keynames": ["x"],
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "select_all_ctrl_a",
|
|
"method_name": "last_event_was_select_all",
|
|
"keynames": ["a"],
|
|
"modifiers": (1 << 2),
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "select_all_ctrl_shift_a",
|
|
"method_name": "last_event_was_select_all",
|
|
"keynames": ["a"],
|
|
"modifiers": (1 << 2) | (1 << 0),
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "select_all_a_without_ctrl",
|
|
"method_name": "last_event_was_select_all",
|
|
"keynames": ["a"],
|
|
"modifiers": 0,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "select_all_unknown_key",
|
|
"method_name": "last_event_was_select_all",
|
|
"keynames": ["x"],
|
|
"modifiers": 1 << 2,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_undo_redo_select_editing_actions(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager undo/redo/select editing action methods."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
input_event_manager._last_key_and_modifiers = test_context.Mock(
|
|
return_value=(case["keynames"][0] if case["keynames"] else "", case["modifiers"]),
|
|
)
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "primary_click_primary_click",
|
|
"method_name": "last_event_was_primary_click",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"pressed": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "primary_click_primary_release",
|
|
"method_name": "last_event_was_primary_click",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "primary_click_middle_click",
|
|
"method_name": "last_event_was_primary_click",
|
|
"is_mouse_button": True,
|
|
"button": "2",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "primary_click_not_mouse_button",
|
|
"method_name": "last_event_was_primary_click",
|
|
"is_mouse_button": False,
|
|
"button": "1",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "primary_release_primary_release",
|
|
"method_name": "last_event_was_primary_release",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"pressed": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "primary_release_primary_click",
|
|
"method_name": "last_event_was_primary_release",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "primary_release_middle_release",
|
|
"method_name": "last_event_was_primary_release",
|
|
"is_mouse_button": True,
|
|
"button": "2",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "primary_release_not_mouse_button",
|
|
"method_name": "last_event_was_primary_release",
|
|
"is_mouse_button": False,
|
|
"button": "1",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_primary_mouse_button_actions(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager primary mouse button action methods."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_last_event = test_context.Mock()
|
|
mock_last_event.button = case["button"]
|
|
mock_last_event.pressed = case["pressed"]
|
|
input_event_manager._last_input_event = mock_last_event
|
|
input_event_manager.last_event_was_mouse_button = test_context.Mock(
|
|
return_value=case["is_mouse_button"],
|
|
)
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "primary_button",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "middle_button",
|
|
"is_mouse_button": True,
|
|
"button": "2",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "secondary_button",
|
|
"is_mouse_button": True,
|
|
"button": "3",
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "not_mouse_button",
|
|
"is_mouse_button": False,
|
|
"button": "1",
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_last_event_was_primary_click_or_release(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager.last_event_was_primary_click_or_release."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_last_event = test_context.Mock()
|
|
mock_last_event.button = case["button"]
|
|
input_event_manager._last_input_event = mock_last_event
|
|
input_event_manager.last_event_was_mouse_button = test_context.Mock(
|
|
return_value=case["is_mouse_button"],
|
|
)
|
|
result = input_event_manager.last_event_was_primary_click_or_release()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
@pytest.mark.parametrize(
|
|
"case",
|
|
[
|
|
{
|
|
"id": "middle_click_middle_click",
|
|
"method_name": "last_event_was_middle_click",
|
|
"is_mouse_button": True,
|
|
"button": "2",
|
|
"pressed": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "middle_click_middle_release",
|
|
"method_name": "last_event_was_middle_click",
|
|
"is_mouse_button": True,
|
|
"button": "2",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "middle_click_primary_click",
|
|
"method_name": "last_event_was_middle_click",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "middle_click_not_mouse_button",
|
|
"method_name": "last_event_was_middle_click",
|
|
"is_mouse_button": False,
|
|
"button": "2",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "middle_release_middle_release",
|
|
"method_name": "last_event_was_middle_release",
|
|
"is_mouse_button": True,
|
|
"button": "2",
|
|
"pressed": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "middle_release_middle_click",
|
|
"method_name": "last_event_was_middle_release",
|
|
"is_mouse_button": True,
|
|
"button": "2",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "middle_release_primary_release",
|
|
"method_name": "last_event_was_middle_release",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "middle_release_not_mouse_button",
|
|
"method_name": "last_event_was_middle_release",
|
|
"is_mouse_button": False,
|
|
"button": "2",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "secondary_click_secondary_click",
|
|
"method_name": "last_event_was_secondary_click",
|
|
"is_mouse_button": True,
|
|
"button": "3",
|
|
"pressed": True,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "secondary_click_secondary_release",
|
|
"method_name": "last_event_was_secondary_click",
|
|
"is_mouse_button": True,
|
|
"button": "3",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "secondary_click_primary_click",
|
|
"method_name": "last_event_was_secondary_click",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "secondary_click_not_mouse_button",
|
|
"method_name": "last_event_was_secondary_click",
|
|
"is_mouse_button": False,
|
|
"button": "3",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "secondary_release_secondary_release",
|
|
"method_name": "last_event_was_secondary_release",
|
|
"is_mouse_button": True,
|
|
"button": "3",
|
|
"pressed": False,
|
|
"expected_result": True,
|
|
},
|
|
{
|
|
"id": "secondary_release_secondary_click",
|
|
"method_name": "last_event_was_secondary_release",
|
|
"is_mouse_button": True,
|
|
"button": "3",
|
|
"pressed": True,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "secondary_release_primary_release",
|
|
"method_name": "last_event_was_secondary_release",
|
|
"is_mouse_button": True,
|
|
"button": "1",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
{
|
|
"id": "secondary_release_not_mouse_button",
|
|
"method_name": "last_event_was_secondary_release",
|
|
"is_mouse_button": False,
|
|
"button": "3",
|
|
"pressed": False,
|
|
"expected_result": False,
|
|
},
|
|
],
|
|
ids=lambda case: case["id"],
|
|
)
|
|
def test_middle_secondary_mouse_button_actions(
|
|
self,
|
|
test_context,
|
|
case: dict,
|
|
) -> None:
|
|
"""Test InputEventManager middle and secondary mouse button action methods."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
mock_last_event = test_context.Mock()
|
|
mock_last_event.button = case["button"]
|
|
mock_last_event.pressed = case["pressed"]
|
|
input_event_manager._last_input_event = mock_last_event
|
|
input_event_manager.last_event_was_mouse_button = test_context.Mock(
|
|
return_value=case["is_mouse_button"],
|
|
)
|
|
method = getattr(input_event_manager, case["method_name"])
|
|
result = method()
|
|
assert result == case["expected_result"]
|
|
if case["expected_result"]:
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
|
|
def test_get_manager(self, test_context: CthulhuTestContext) -> None:
|
|
"""Test get_manager function returns singleton."""
|
|
|
|
self._setup_input_event_manager(test_context)
|
|
from cthulhu.input_event_manager import get_manager
|
|
|
|
manager1 = get_manager()
|
|
manager2 = get_manager()
|
|
assert manager1 is manager2
|
|
|
|
def test_pause_key_watcher_with_debug_message(self, test_context: CthulhuTestContext) -> None:
|
|
"""Test InputEventManager.pause_key_watcher logs debug message."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
|
|
input_event_manager.pause_key_watcher(True, "Testing pause functionality")
|
|
|
|
essential_modules["cthulhu.debug"].print_message.assert_called()
|
|
assert input_event_manager._paused is True
|
|
|
|
input_event_manager.pause_key_watcher(False, "Testing unpause functionality")
|
|
|
|
assert input_event_manager._paused is False
|
|
|
|
def test_determine_click_count_no_multi_click_bindings(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
) -> None:
|
|
"""Test click count stays at 1 when no multi-click bindings exist for the key."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
|
|
# Mock command_manager to return False for has_multi_click_bindings
|
|
command_manager_instance = test_context.Mock()
|
|
command_manager_instance.has_multi_click_bindings = test_context.Mock(return_value=False)
|
|
test_context.patch(
|
|
"cthulhu.command_manager.get_manager",
|
|
return_value=command_manager_instance,
|
|
)
|
|
|
|
# Create first event (press)
|
|
first_event = essential_modules["cthulhu.input_event"].KeyboardEvent(
|
|
pressed=True,
|
|
keycode=79,
|
|
keysym=65429,
|
|
modifiers=0,
|
|
text="KP_Home",
|
|
)
|
|
first_event.keyval_name = "KP_Home"
|
|
first_event.time = 1000.0
|
|
first_event.is_pressed_key = test_context.Mock(return_value=True)
|
|
first_event.is_modifier_key = test_context.Mock(return_value=False)
|
|
first_event.get_click_count = test_context.Mock(return_value=1)
|
|
first_event.get_object = test_context.Mock(return_value=None)
|
|
|
|
# Set first event as last event
|
|
input_event_manager._last_input_event = first_event
|
|
input_event_manager._last_non_modifier_key_event = first_event
|
|
|
|
# Create release event
|
|
release_event = essential_modules["cthulhu.input_event"].KeyboardEvent(
|
|
pressed=False,
|
|
keycode=79,
|
|
keysym=65429,
|
|
modifiers=0,
|
|
text="KP_Home",
|
|
)
|
|
release_event.keyval_name = "KP_Home"
|
|
release_event.time = 1000.1
|
|
release_event.is_pressed_key = test_context.Mock(return_value=False)
|
|
release_event.is_modifier_key = test_context.Mock(return_value=False)
|
|
release_event.get_click_count = test_context.Mock(return_value=1)
|
|
release_event.get_object = test_context.Mock(return_value=None)
|
|
|
|
# Set release as last event
|
|
input_event_manager._last_input_event = release_event
|
|
input_event_manager._last_non_modifier_key_event = release_event
|
|
|
|
# Create second press event within doubleClickTimeout
|
|
second_event = essential_modules["cthulhu.input_event"].KeyboardEvent(
|
|
pressed=True,
|
|
keycode=79,
|
|
keysym=65429,
|
|
modifiers=0,
|
|
text="KP_Home",
|
|
)
|
|
second_event.keyval_name = "KP_Home"
|
|
second_event.id = 65429 # keyval for has_multi_click_bindings call
|
|
second_event.hw_code = 79 # keycode
|
|
second_event.modifiers = 0
|
|
second_event.time = 1000.3 # Within 0.5s timeout
|
|
second_event.is_pressed_key = test_context.Mock(return_value=True)
|
|
second_event.is_modifier_key = test_context.Mock(return_value=False)
|
|
second_event.is_cthulhu_modifier = test_context.Mock(return_value=False)
|
|
second_event.get_object = test_context.Mock(return_value=None)
|
|
|
|
# Determine click count - should stay at 1 since no multi-click bindings
|
|
result = input_event_manager._determine_keyboard_event_click_count(second_event)
|
|
|
|
assert result == 1
|
|
command_manager_instance.has_multi_click_bindings.assert_called_with(65429, 79, 0)
|
|
|
|
def test_determine_click_count_with_multi_click_bindings(
|
|
self,
|
|
test_context: CthulhuTestContext,
|
|
) -> None:
|
|
"""Test click count increments when multi-click bindings exist for the key."""
|
|
|
|
input_event_manager, essential_modules = self._setup_input_event_manager(test_context)
|
|
|
|
# Mock command_manager to return True for has_multi_click_bindings
|
|
command_manager_instance = test_context.Mock()
|
|
command_manager_instance.has_multi_click_bindings = test_context.Mock(return_value=True)
|
|
test_context.patch(
|
|
"cthulhu.command_manager.get_manager",
|
|
return_value=command_manager_instance,
|
|
)
|
|
|
|
# Create first event (press)
|
|
first_event = essential_modules["cthulhu.input_event"].KeyboardEvent(
|
|
pressed=True,
|
|
keycode=80,
|
|
keysym=65431,
|
|
modifiers=0,
|
|
text="KP_Up",
|
|
)
|
|
first_event.keyval_name = "KP_Up"
|
|
first_event.time = 1000.0
|
|
first_event.is_pressed_key = test_context.Mock(return_value=True)
|
|
first_event.is_modifier_key = test_context.Mock(return_value=False)
|
|
first_event.get_click_count = test_context.Mock(return_value=1)
|
|
first_event.get_object = test_context.Mock(return_value=None)
|
|
|
|
# Set first event as last event
|
|
input_event_manager._last_input_event = first_event
|
|
input_event_manager._last_non_modifier_key_event = first_event
|
|
|
|
# Create release event
|
|
release_event = essential_modules["cthulhu.input_event"].KeyboardEvent(
|
|
pressed=False,
|
|
keycode=80,
|
|
keysym=65431,
|
|
modifiers=0,
|
|
text="KP_Up",
|
|
)
|
|
release_event.keyval_name = "KP_Up"
|
|
release_event.time = 1000.1
|
|
release_event.is_pressed_key = test_context.Mock(return_value=False)
|
|
release_event.is_modifier_key = test_context.Mock(return_value=False)
|
|
release_event.get_click_count = test_context.Mock(return_value=1)
|
|
release_event.get_object = test_context.Mock(return_value=None)
|
|
|
|
# Set release as last event
|
|
input_event_manager._last_input_event = release_event
|
|
input_event_manager._last_non_modifier_key_event = release_event
|
|
|
|
# Create second press event within doubleClickTimeout
|
|
second_event = essential_modules["cthulhu.input_event"].KeyboardEvent(
|
|
pressed=True,
|
|
keycode=80,
|
|
keysym=65431,
|
|
modifiers=0,
|
|
text="KP_Up",
|
|
)
|
|
second_event.keyval_name = "KP_Up"
|
|
second_event.id = 65431 # keyval for has_multi_click_bindings call
|
|
second_event.hw_code = 80 # keycode
|
|
second_event.modifiers = 0
|
|
second_event.time = 1000.3 # Within 0.5s timeout
|
|
second_event.is_pressed_key = test_context.Mock(return_value=True)
|
|
second_event.is_modifier_key = test_context.Mock(return_value=False)
|
|
second_event.is_cthulhu_modifier = test_context.Mock(return_value=False)
|
|
second_event.get_object = test_context.Mock(return_value=None)
|
|
|
|
# Determine click count - should increment to 2 since multi-click bindings exist
|
|
result = input_event_manager._determine_keyboard_event_click_count(second_event)
|
|
|
|
assert result == 2
|
|
command_manager_instance.has_multi_click_bindings.assert_called_with(65431, 80, 0)
|