# Unit tests for table_navigator.py methods. # # Copyright 2025 Igalia, S.L. # Author: Joanmarie Diggs # # 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 """Unit tests for table_navigator.py methods.""" from __future__ import annotations from typing import TYPE_CHECKING import gi import pytest gi.require_version("Atspi", "2.0") from gi.repository import Atspi if TYPE_CHECKING: from unittest.mock import MagicMock from cthulhu_test_context import CthulhuTestContext @pytest.mark.unit class TestTableNavigator: """Test TableNavigator class methods.""" def _setup_dependencies(self, test_context: CthulhuTestContext) -> dict[str, MagicMock]: """Set up dependencies for table_navigator module testing.""" additional_modules = [ "cthulhu.command_manager", "cthulhu.guilabels", "cthulhu.input_event_manager", "cthulhu.cmdnames", "cthulhu.messages", "cthulhu.object_properties", "cthulhu.cthulhu_gui_navlist", "cthulhu.cthulhu_i18n", "cthulhu.AXHypertext", "cthulhu.AXObject", "cthulhu.AXTable", "cthulhu.AXText", "cthulhu.AXUtilities", "cthulhu.input_event", "cthulhu.braille_presenter", "cthulhu.presentation_manager", ] essential_modules = test_context.setup_shared_dependencies(additional_modules) # Set up cmdnames with all required values for structural_navigator cmdnames = essential_modules["cthulhu.cmdnames"] cmdnames.STRUCTURAL_NAVIGATION_MODE_CYCLE = "cycle_mode" cmdnames.BLOCKQUOTE_PREV = "previous_blockquote" cmdnames.BLOCKQUOTE_NEXT = "next_blockquote" cmdnames.BLOCKQUOTE_LIST = "list_blockquotes" cmdnames.BUTTON_PREV = "previous_button" cmdnames.BUTTON_NEXT = "next_button" cmdnames.BUTTON_LIST = "list_buttons" cmdnames.CHECK_BOX_PREV = "previous_checkbox" cmdnames.CHECK_BOX_NEXT = "next_checkbox" cmdnames.CHECK_BOX_LIST = "list_checkboxes" cmdnames.COMBO_BOX_PREV = "previous_combobox" cmdnames.COMBO_BOX_NEXT = "next_combobox" cmdnames.COMBO_BOX_LIST = "list_comboboxes" cmdnames.ENTRY_PREV = "previous_entry" cmdnames.ENTRY_NEXT = "next_entry" cmdnames.ENTRY_LIST = "list_entries" cmdnames.FORM_FIELD_PREV = "previous_form_field" cmdnames.FORM_FIELD_NEXT = "next_form_field" cmdnames.FORM_FIELD_LIST = "list_form_fields" cmdnames.HEADING_PREV = "previous_heading" cmdnames.HEADING_NEXT = "next_heading" cmdnames.HEADING_LIST = "list_headings" cmdnames.HEADING_AT_LEVEL_PREV = "previous_heading_level_%d" cmdnames.HEADING_AT_LEVEL_NEXT = "next_heading_level_%d" cmdnames.HEADING_AT_LEVEL_LIST = "list_headings_level_%d" cmdnames.IFRAME_PREV = "previous_iframe" cmdnames.IFRAME_NEXT = "next_iframe" cmdnames.IFRAME_LIST = "list_iframes" cmdnames.IMAGE_PREV = "previous_image" cmdnames.IMAGE_NEXT = "next_image" cmdnames.IMAGE_LIST = "list_images" cmdnames.LANDMARK_PREV = "previous_landmark" cmdnames.LANDMARK_NEXT = "next_landmark" cmdnames.LANDMARK_LIST = "list_landmarks" cmdnames.LIST_PREV = "previous_list" cmdnames.LIST_NEXT = "next_list" cmdnames.LIST_LIST = "list_lists" cmdnames.LIST_ITEM_PREV = "previous_list_item" cmdnames.LIST_ITEM_NEXT = "next_list_item" cmdnames.LIST_ITEM_LIST = "list_list_items" cmdnames.LIVE_REGION_PREV = "previous_live_region" cmdnames.LIVE_REGION_NEXT = "next_live_region" cmdnames.LIVE_REGION_LAST = "last_live_region" cmdnames.PARAGRAPH_PREV = "previous_paragraph" cmdnames.PARAGRAPH_NEXT = "next_paragraph" cmdnames.PARAGRAPH_LIST = "list_paragraphs" cmdnames.RADIO_BUTTON_PREV = "previous_radio_button" cmdnames.RADIO_BUTTON_NEXT = "next_radio_button" cmdnames.RADIO_BUTTON_LIST = "list_radio_buttons" cmdnames.SEPARATOR_PREV = "previous_separator" cmdnames.SEPARATOR_NEXT = "next_separator" cmdnames.TABLE_PREV = "previous_table" cmdnames.TABLE_NEXT = "next_table" cmdnames.TABLE_LIST = "list_tables" cmdnames.UNVISITED_LINK_PREV = "previous_unvisited_link" cmdnames.UNVISITED_LINK_NEXT = "next_unvisited_link" cmdnames.UNVISITED_LINK_LIST = "list_unvisited_links" cmdnames.VISITED_LINK_PREV = "previous_visited_link" cmdnames.VISITED_LINK_NEXT = "next_visited_link" cmdnames.VISITED_LINK_LIST = "list_visited_links" cmdnames.LINK_PREV = "previous_link" cmdnames.LINK_NEXT = "next_link" cmdnames.LINK_LIST = "list_links" cmdnames.CLICKABLE_PREV = "previous_clickable" cmdnames.CLICKABLE_NEXT = "next_clickable" cmdnames.CLICKABLE_LIST = "list_clickables" cmdnames.LARGE_OBJECT_PREV = "previous_large_object" cmdnames.LARGE_OBJECT_NEXT = "next_large_object" cmdnames.LARGE_OBJECT_LIST = "list_large_objects" cmdnames.CONTAINER_START = "container_start" cmdnames.CONTAINER_END = "container_end" essential_modules["cthulhu.cthulhu_i18n"]._ = lambda x: x essential_modules["cthulhu.debug"].print_message = test_context.Mock() essential_modules["cthulhu.debug"].LEVEL_INFO = 800 controller_mock = test_context.Mock() controller_mock.register_decorated_module.return_value = None essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = controller_mock focus_manager_instance = test_context.Mock() focus_manager_instance.get_locus_of_focus.return_value = None essential_modules["cthulhu.focus_manager"].get_manager.return_value = focus_manager_instance essential_modules["cthulhu.AXObject"].supports_collection.return_value = True essential_modules["cthulhu.AXUtilities"].is_heading.return_value = False return essential_modules def test_init(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.__init__ creates instance with correct default values.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu import command_manager from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() assert navigator._previous_reported_row is None assert navigator._previous_reported_col is None assert navigator._last_input_event is None assert navigator.get_is_enabled() is True # D-Bus registration and commands are registered during setup() navigator.set_up_commands() # Verify commands are registered in CommandManager cmd_manager = command_manager.get_manager() assert cmd_manager.get_command("table_navigator_toggle_enabled") is not None assert cmd_manager.get_command("table_cell_down") is not None mock_controller.register_decorated_module.assert_called_with("TableNavigator", navigator) def test_is_enabled_default_true(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.is_enabled returns True by default.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() assert navigator.get_is_enabled() is True def test_is_enabled_after_disable(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.get_is_enabled returns False when disabled.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu import gsettings_registry from cthulhu.table_navigator import TableNavigator gsettings_registry.get_registry().set_runtime_value("table-navigation", "enabled", False) navigator = TableNavigator() assert navigator.get_is_enabled() is False def test_last_input_event_was_navigation_command_none( self, test_context: CthulhuTestContext, ) -> None: """Test last_input_event_was_navigation_command with None event returns False.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_manager = test_context.Mock() essential_modules["cthulhu.input_event_manager"].get_manager.return_value = mock_manager mock_manager.last_event_equals_or_is_release_for_event.return_value = False from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() result = navigator.last_input_event_was_navigation_command() assert result is False mock_manager.last_event_equals_or_is_release_for_event.assert_not_called() def test_last_input_event_was_navigation_command_with_event( self, test_context: CthulhuTestContext, ) -> None: """Test last_input_event_was_navigation_command with event returns True when matching.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_manager = test_context.Mock() essential_modules["cthulhu.input_event_manager"].get_manager.return_value = mock_manager mock_manager.last_event_equals_or_is_release_for_event.return_value = True mock_event = test_context.Mock() mock_event.as_single_line_string.return_value = "test_event" from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._last_input_event = mock_event result = navigator.last_input_event_was_navigation_command() assert result is True mock_manager.last_event_equals_or_is_release_for_event.assert_called_once_with(mock_event) @pytest.mark.parametrize( "initial_enabled,expected_enabled,expected_message_attr", [ (False, True, "TABLE_NAVIGATION_ENABLED"), (True, False, "TABLE_NAVIGATION_DISABLED"), ], ) def test_toggle_enabled( self, test_context: CthulhuTestContext, initial_enabled: bool, expected_enabled: bool, expected_message_attr: str, ) -> None: """Test TableNavigator.toggle_enabled toggles state and presents appropriate message.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_cmd_mgr = test_context.Mock() essential_modules["cthulhu.command_manager"].get_manager.return_value = mock_cmd_mgr from cthulhu.table_navigator import TableNavigator guilabels_mock = essential_modules["cthulhu.guilabels"] guilabels_mock.KB_GROUP_TABLE_NAVIGATION = "Table navigation" navigator = TableNavigator() mock_cmd_mgr.is_group_enabled.return_value = initial_enabled mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.toggle_enabled(mock_script, mock_event, notify_user=True) assert result is True expected_message = getattr(essential_modules["cthulhu.messages"], expected_message_attr) pres_manager.present_message.assert_called_once_with(expected_message) def test_toggle_enabled_no_notify(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.toggle_enabled does not present message when notify_user=False.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_cmd_mgr = test_context.Mock() essential_modules["cthulhu.command_manager"].get_manager.return_value = mock_cmd_mgr from cthulhu.table_navigator import TableNavigator guilabels_mock = essential_modules["cthulhu.guilabels"] guilabels_mock.KB_GROUP_TABLE_NAVIGATION = "Table navigation" navigator = TableNavigator() mock_cmd_mgr.is_group_enabled.return_value = False mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.toggle_enabled(mock_script, mock_event, notify_user=False) assert result is True pres_manager.present_message.assert_not_called() @pytest.mark.parametrize( "is_focusable, has_name, has_children, is_whitespace, expected_result", [ pytest.param(True, False, False, True, False, id="focusable_object"), pytest.param(False, True, False, True, False, id="object_with_name"), pytest.param(False, False, True, True, False, id="object_with_non_blank_children"), pytest.param(False, False, False, False, False, id="object_with_text"), pytest.param(False, False, False, True, True, id="blank_object"), pytest.param(False, False, True, True, True, id="object_with_only_blank_children"), ], ) def test_is_blank( self, test_context, is_focusable, has_name, has_children, is_whitespace, expected_result, ) -> None: """Test _is_blank correctly identifies blank objects based on various criteria.""" essential_modules = self._setup_dependencies(test_context) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_focusable", return_value=is_focusable, ) test_context.patch( "cthulhu.table_navigator.AXObject.get_name", return_value="name" if has_name else "", ) test_context.patch( "cthulhu.table_navigator.AXObject.get_child_count", return_value=1 if has_children else 0, ) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_whitespace_or_empty", return_value=is_whitespace, ) if has_children: mock_child = test_context.Mock() test_context.patch( "cthulhu.table_navigator.AXObject.iter_children", return_value=[mock_child], ) # For the recursive call on child, configure mock to handle both expected cases if expected_result and not is_focusable and not has_name: # Child should also be blank - override child-specific mocking test_context.patch( "cthulhu.table_navigator.AXUtilities.is_focusable", side_effect=lambda obj: False if obj == mock_child else is_focusable, ) test_context.patch( "cthulhu.table_navigator.AXObject.get_name", side_effect=lambda obj: ( "" if obj == mock_child else ("name" if has_name else "") ), ) test_context.patch( "cthulhu.table_navigator.AXObject.get_child_count", side_effect=lambda obj: 0 if obj == mock_child else (1 if has_children else 0), ) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_whitespace_or_empty", side_effect=lambda obj: True if obj == mock_child else is_whitespace, ) else: # Child should not be blank - make it focusable to stop recursion test_context.patch( "cthulhu.table_navigator.AXUtilities.is_focusable", side_effect=lambda obj: True if obj == mock_child else is_focusable, ) else: test_context.patch("cthulhu.table_navigator.AXObject.iter_children", return_value=[]) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() mock_obj = test_context.Mock(spec=Atspi.Accessible) result = navigator._is_blank(mock_obj) assert result == expected_result def test_get_current_cell_basic(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator._get_current_cell returns focus manager's locus when it is a cell.""" essential_modules = self._setup_dependencies(test_context) mock_cell = test_context.Mock(spec=Atspi.Accessible) mock_focus_manager = test_context.Mock() mock_focus_manager.get_locus_of_focus.return_value = mock_cell test_context.patch( "cthulhu.table_navigator.focus_manager.get_manager", return_value=mock_focus_manager, ) test_context.patch("cthulhu.table_navigator.AXObject.get_parent", return_value=None) def mock_is_cell_or_header(obj): return obj == mock_cell test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", new=mock_is_cell_or_header, ) test_context.patch("cthulhu.table_navigator.AXUtilities.find_ancestor", return_value=None) test_context.patch("cthulhu.table_navigator.debug.print_tokens", return_value=None) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() result = navigator._get_current_cell() assert result == mock_cell def test_get_current_cell_nested(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator._get_current_cell returns parent when it is also a table cell.""" essential_modules = self._setup_dependencies(test_context) mock_focus_manager = test_context.Mock() essential_modules["cthulhu.focus_manager"].get_manager.return_value = mock_focus_manager mock_inner_cell = test_context.Mock(spec=Atspi.Accessible) mock_parent_cell = test_context.Mock(spec=Atspi.Accessible) mock_focus_manager.get_locus_of_focus.return_value = mock_inner_cell test_context.patch( "cthulhu.table_navigator.AXObject.get_parent", side_effect=lambda obj: mock_parent_cell if obj == mock_inner_cell else None, ) def mock_is_table_cell(obj): return obj in [mock_inner_cell, mock_parent_cell] test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", new=mock_is_table_cell, ) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() result = navigator._get_current_cell() assert result == mock_parent_cell def test_get_cell_coordinates_basic(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator._get_cell_coordinates returns coordinates from AXTable.""" essential_modules = self._setup_dependencies(test_context) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", return_value=(2, 3), ) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() mock_cell = test_context.Mock(spec=Atspi.Accessible) result = navigator._get_cell_coordinates(mock_cell) assert result == (2, 3) def test_get_cell_coordinates_with_previous(self, test_context: CthulhuTestContext) -> None: """Test _get_cell_coordinates returns previous coordinates when cell matches.""" essential_modules = self._setup_dependencies(test_context) mock_cell = test_context.Mock(spec=Atspi.Accessible) mock_table = test_context.Mock(spec=Atspi.Accessible) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", return_value=(2, 3), ) test_context.patch("cthulhu.table_navigator.AXUtilities.get_table", return_value=mock_table) test_context.patch("cthulhu.table_navigator.AXTable.get_cell_at", return_value=mock_cell) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._previous_reported_row = 1 navigator._previous_reported_col = 2 result = navigator._get_cell_coordinates(mock_cell) assert result == (1, 2) @pytest.mark.parametrize( "direction, boundary_check, boundary_message, get_next_cell_method", [ pytest.param( "left", "is_start_of_row", "TABLE_ROW_BEGINNING", "get_cell_on_left", id="move_left", ), pytest.param( "right", "is_end_of_row", "TABLE_ROW_END", "get_cell_on_right", id="move_right", ), pytest.param( "up", "is_top_of_column", "TABLE_COLUMN_TOP", "get_cell_above", id="move_up", ), pytest.param( "down", "is_bottom_of_column", "TABLE_COLUMN_BOTTOM", "get_cell_below", id="move_down", ), ], ) def test_move_direction_scenarios( self, test_context: CthulhuTestContext, direction: str, boundary_check: str, boundary_message: str, get_next_cell_method: str, ) -> None: """Test TableNavigator move methods for various scenarios.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() mock_script = test_context.Mock() mock_event = test_context.Mock() move_method = getattr(navigator, f"move_{direction}") pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() navigator._get_current_cell = test_context.Mock(return_value=None) pres_manager.present_message.reset_mock() result = move_method(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) assert navigator._last_input_event == mock_event mock_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch(f"cthulhu.table_navigator.AXTable.{boundary_check}", return_value=True) navigator._get_current_cell = test_context.Mock(return_value=mock_cell) pres_manager.present_message.reset_mock() result = move_method(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_with( getattr(essential_modules["cthulhu.messages"], boundary_message), ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_next_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch(f"cthulhu.table_navigator.AXTable.{boundary_check}", return_value=False) test_context.patch( f"cthulhu.table_navigator.AXTable.{get_next_cell_method}", return_value=mock_next_cell, ) navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) navigator._get_cell_coordinates = test_context.Mock(return_value=(1, 2)) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script.reset_mock() result = move_method(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once() call_args = mock_present_cell.call_args[0] assert call_args[0] == mock_script assert call_args[1] == mock_next_cell assert call_args[4] == mock_current_cell assert call_args[5] is True def test_move_left_successful(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_left successfully moves to left cell and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_left_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_start_of_row", return_value=False) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_on_left", return_value=mock_left_cell, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) navigator._get_cell_coordinates = test_context.Mock(return_value=(1, 2)) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_left(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_left_cell, 1, 1, mock_current_cell, True, ) def test_move_right_successful(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_right successfully moves to right cell and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_right_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_end_of_row", return_value=False) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_on_right", return_value=mock_right_cell, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) navigator._get_cell_coordinates = test_context.Mock(return_value=(1, 2)) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_right(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_right_cell, 1, 3, mock_current_cell, True, ) def test_move_up_not_in_table(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_up presents not in table message when current cell is None.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_up(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) assert navigator._last_input_event == mock_event def test_move_up_at_top_of_column(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_up presents column top message when at top of column.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_top_of_column", return_value=True) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_up(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_COLUMN_TOP, ) def test_move_up_successful(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_up successfully moves to cell above and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_up_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_top_of_column", return_value=False) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_above", return_value=mock_up_cell, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) navigator._get_cell_coordinates = test_context.Mock(return_value=(2, 1)) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_up(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_up_cell, 1, 1, mock_current_cell, True, ) def test_move_down_successful(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_down successfully moves to cell below and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_down_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch( "cthulhu.table_navigator.AXTable.is_bottom_of_column", return_value=False, ) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_below", return_value=mock_down_cell, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) navigator._get_cell_coordinates = test_context.Mock(return_value=(1, 1)) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_down(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_down_cell, 2, 1, mock_current_cell, True, ) def test_move_to_first_cell_not_in_table(self, test_context: CthulhuTestContext) -> None: """Test move_to_first_cell presents not in table message when current cell is None.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_first_cell(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_move_to_first_cell_successful(self, test_context: CthulhuTestContext) -> None: """Test move_to_first_cell successfully moves to first cell and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_table = test_context.Mock(spec=Atspi.Accessible) mock_first_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXUtilities.get_table", return_value=mock_table) test_context.patch( "cthulhu.table_navigator.AXTable.get_first_cell", return_value=mock_first_cell, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_to_first_cell(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_first_cell, 0, 0, mock_current_cell, True, ) def test_present_cell_not_cell_or_header(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator._present_cell returns early when object is not a cell or header.""" essential_modules = self._setup_dependencies(test_context) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", return_value=False, ) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() mock_script = test_context.Mock() mock_cell = test_context.Mock(spec=Atspi.Accessible) mock_previous_cell = test_context.Mock(spec=Atspi.Accessible) navigator._present_cell(mock_script, mock_cell, 1, 2, mock_previous_cell) assert navigator._previous_reported_row != 1 assert navigator._previous_reported_col != 2 def test_present_cell_successful(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator._present_cell sets focus, coordinates, and presents cell.""" essential_modules = self._setup_dependencies(test_context) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", return_value=True, ) test_context.patch("cthulhu.table_navigator.AXObject.grab_focus", return_value=None) test_context.patch( "cthulhu.table_navigator.AXUtilities.get_descendant_supporting_text", return_value=None ) test_context.patch("cthulhu.table_navigator.AXObject.supports_text", return_value=False) test_context.patch("cthulhu.table_navigator.AXTable.get_cell_spans", return_value=(1, 1)) mock_focus_manager = test_context.Mock() essential_modules["cthulhu.focus_manager"].get_manager.return_value = mock_focus_manager mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu import gsettings_registry from cthulhu.table_navigator import TableNavigator registry = gsettings_registry.get_registry() registry.set_runtime_value("speech", "announce-cell-coordinates", False) registry.set_runtime_value("speech", "announce-cell-span", False) navigator = TableNavigator() mock_script = test_context.Mock() mock_script.utilities.grab_focus_when_setting_caret.return_value = False test_context.patch("cthulhu.table_navigator.AXUtilities.is_gui_cell", return_value=False) mock_script.present_object = test_context.Mock() mock_cell = test_context.Mock(spec=Atspi.Accessible) mock_previous_cell = test_context.Mock(spec=Atspi.Accessible) navigator._present_cell(mock_script, mock_cell, 1, 2, mock_previous_cell) assert navigator._previous_reported_row == 1 assert navigator._previous_reported_col == 2 mock_focus_manager.set_locus_of_focus.assert_called() mock_script.present_object.assert_called_once_with( mock_cell, offset=0, priorObj=mock_previous_cell, interrupt=True, ) def test_get_navigator(self, test_context: CthulhuTestContext) -> None: """Test table_navigator.get_navigator returns singleton TableNavigator instance.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu import table_navigator navigator1 = table_navigator.get_navigator() navigator2 = table_navigator.get_navigator() assert navigator1 is navigator2 assert isinstance(navigator1, table_navigator.TableNavigator) def test_get_current_cell_needs_ancestor_search(self, test_context: CthulhuTestContext) -> None: """Test _get_current_cell when cell is not table cell and needs ancestor search.""" essential_modules = self._setup_dependencies(test_context) mock_initial_cell = test_context.Mock(spec=Atspi.Accessible) mock_ancestor_cell = test_context.Mock(spec=Atspi.Accessible) mock_focus_manager = test_context.Mock() mock_focus_manager.get_locus_of_focus.return_value = mock_initial_cell test_context.patch( "cthulhu.table_navigator.focus_manager.get_manager", return_value=mock_focus_manager, ) test_context.patch("cthulhu.table_navigator.AXObject.get_parent", return_value=None) def mock_is_cell_or_header(obj): return obj == mock_ancestor_cell test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", new=mock_is_cell_or_header, ) test_context.patch( "cthulhu.table_navigator.AXUtilities.find_ancestor", return_value=mock_ancestor_cell, ) test_context.patch("cthulhu.table_navigator.debug.print_tokens", return_value=None) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() result = navigator._get_current_cell() assert result == mock_ancestor_cell def test_move_left_skip_blank_cells(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_left skipping blank cells when setting is enabled.""" essential_modules = self._setup_dependencies(test_context) from cthulhu import gsettings_registry gsettings_registry.get_registry().set_runtime_value( "table-navigation", "skip-blank-cells", True, ) mock_script = test_context.Mock() mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_blank_cell = test_context.Mock(spec=Atspi.Accessible) mock_final_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", return_value=(1, 1), ) test_context.patch( "cthulhu.table_navigator.AXTable.is_start_of_row", side_effect=lambda cell: cell == mock_final_cell, ) cell_sequence = [mock_blank_cell, mock_final_cell] call_count = [0] def mock_get_cell_on_left(_cell): if call_count[0] < len(cell_sequence): result = cell_sequence[call_count[0]] call_count[0] += 1 return result return None test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_on_left", new=mock_get_cell_on_left, ) def mock_is_blank(cell): return cell == mock_blank_cell test_context.patch("cthulhu.table_navigator.debug.print_tokens", return_value=None) test_context.patch("cthulhu.table_navigator.TableNavigator._present_cell", return_value=None) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._is_blank = mock_is_blank result = navigator.move_left(mock_script, mock_current_cell) assert result is True def test_move_right_at_end_of_row(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_right when at end of row returns True and notifies user.""" essential_modules = self._setup_dependencies(test_context) mock_script = test_context.Mock() mock_current_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", return_value=(1, 5), ) test_context.patch("cthulhu.table_navigator.AXTable.get_cell_on_right", return_value=None) test_context.patch("cthulhu.table_navigator.AXTable.is_end_of_row", return_value=True) test_context.patch("cthulhu.table_navigator.debug.print_tokens", return_value=None) test_context.patch("cthulhu.table_navigator.TableNavigator._present_cell", return_value=None) mock_focus_manager = test_context.Mock() mock_focus_manager.get_locus_of_focus.return_value = mock_current_cell test_context.patch( "cthulhu.table_navigator.focus_manager.get_manager", return_value=mock_focus_manager, ) test_context.patch("cthulhu.table_navigator.AXObject.get_parent", return_value=None) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", return_value=True, ) test_context.patch("cthulhu.table_navigator.AXUtilities.find_ancestor", return_value=None) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_right(mock_script) # move_right returns True even at end of row, but presents a message assert result is True pres_manager.present_message.assert_called_once() def test_move_to_last_cell_not_in_table(self, test_context: CthulhuTestContext) -> None: """Test move_to_last_cell presents not in table message when current cell is None.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_last_cell(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) assert navigator._last_input_event == mock_event def test_move_to_last_cell_successful(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.move_to_last_cell successfully moves to last cell and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_table = test_context.Mock(spec=Atspi.Accessible) mock_last_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXUtilities.get_table", return_value=mock_table) test_context.patch( "cthulhu.table_navigator.AXTable.get_last_cell", return_value=mock_last_cell, ) test_context.patch("cthulhu.table_navigator.AXTable.get_row_count", return_value=5) test_context.patch("cthulhu.table_navigator.AXTable.get_column_count", return_value=3) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_to_last_cell(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_last_cell, 5, 3, mock_current_cell, True, ) def test_move_to_top_of_column_not_in_table(self, test_context: CthulhuTestContext) -> None: """Test move_to_top_of_column presents not in table message when current cell is None.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_top_of_column(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_move_to_top_of_column_already_at_top(self, test_context: CthulhuTestContext) -> None: """Test move_to_top_of_column presents column top message when already at top.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_top_of_column", return_value=True) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_top_of_column(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_COLUMN_TOP, ) def test_move_to_top_of_column_successful(self, test_context: CthulhuTestContext) -> None: """Test move_to_top_of_column successfully moves to top of column and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_top_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_top_of_column", return_value=False) test_context.patch( "cthulhu.table_navigator.AXTable.get_top_of_column", return_value=mock_top_cell, ) def mock_get_cell_coordinates(cell, prefer_attribute=False): # pylint: disable=unused-argument if cell == mock_current_cell: return (3, 1) if cell == mock_top_cell: return (0, 1) return (0, 0) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", new=mock_get_cell_coordinates, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_to_top_of_column(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_top_cell, 3, 1, mock_current_cell, True, ) def test_move_to_bottom_of_column_not_in_table(self, test_context: CthulhuTestContext) -> None: """Test move_to_bottom_of_column presents not in table message when current cell is None.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_bottom_of_column(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_move_to_bottom_of_column_already_at_bottom( self, test_context: CthulhuTestContext, ) -> None: """Test move_to_bottom_of_column presents column bottom message when already at bottom.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch( "cthulhu.table_navigator.AXTable.is_bottom_of_column", return_value=True, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_bottom_of_column(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_COLUMN_BOTTOM, ) def test_move_to_bottom_of_column_successful(self, test_context: CthulhuTestContext) -> None: """Test move_to_bottom_of_column successfully moves to bottom of column and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_bottom_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch( "cthulhu.table_navigator.AXTable.is_bottom_of_column", return_value=False, ) test_context.patch( "cthulhu.table_navigator.AXTable.get_bottom_of_column", return_value=mock_bottom_cell, ) def mock_get_cell_coordinates(cell, prefer_attribute=False): # pylint: disable=unused-argument if cell == mock_current_cell: return (1, 2) if cell == mock_bottom_cell: return (4, 2) return (0, 0) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", new=mock_get_cell_coordinates, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_to_bottom_of_column(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_bottom_cell, 1, 2, mock_current_cell, True, ) def test_move_to_beginning_of_row_not_in_table(self, test_context: CthulhuTestContext) -> None: """Test move_to_beginning_of_row presents not in table message when current cell is None.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_beginning_of_row(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_move_to_beginning_of_row_already_at_start(self, test_context: CthulhuTestContext) -> None: """Test move_to_beginning_of_row presents row beginning message when already at start.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_start_of_row", return_value=True) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_beginning_of_row(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_ROW_BEGINNING, ) def test_move_to_beginning_of_row_successful(self, test_context: CthulhuTestContext) -> None: """Test move_to_beginning_of_row successfully moves to beginning of row and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_start_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_start_of_row", return_value=False) test_context.patch( "cthulhu.table_navigator.AXTable.get_start_of_row", return_value=mock_start_cell, ) def mock_get_cell_coordinates(cell, prefer_attribute=False): # pylint: disable=unused-argument if cell == mock_start_cell: return (2, 0) return (2, 3) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", new=mock_get_cell_coordinates, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_to_beginning_of_row(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_start_cell, 2, 0, mock_current_cell, True, ) def test_move_to_end_of_row_not_in_table(self, test_context: CthulhuTestContext) -> None: """Test move_to_end_of_row presents not in table message when current cell is None.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_end_of_row(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_move_to_end_of_row_already_at_end(self, test_context: CthulhuTestContext) -> None: """Test move_to_end_of_row presents row end message when already at end.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_end_of_row", return_value=True) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.move_to_end_of_row(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_ROW_END, ) def test_move_to_end_of_row_successful(self, test_context: CthulhuTestContext) -> None: """Test move_to_end_of_row successfully moves to end of row and presents it.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_end_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXTable.is_end_of_row", return_value=False) test_context.patch( "cthulhu.table_navigator.AXTable.get_end_of_row", return_value=mock_end_cell, ) def mock_get_cell_coordinates(cell, prefer_attribute=False): # pylint: disable=unused-argument if cell == mock_end_cell: return (2, 4) return (2, 1) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", new=mock_get_cell_coordinates, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_present_cell = test_context.Mock() navigator._present_cell = mock_present_cell mock_script = test_context.Mock() mock_event = test_context.Mock() result = navigator.move_to_end_of_row(mock_script, mock_event) assert result is True mock_present_cell.assert_called_once_with( mock_script, mock_end_cell, 2, 4, mock_current_cell, True, ) def test_set_dynamic_column_headers_row_not_in_table( self, test_context: CthulhuTestContext, ) -> None: """Test set_dynamic_column_headers_row presents not in table message. Test case when current cell is None. """ essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.set_dynamic_column_headers_row(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_set_dynamic_column_headers_row_successful(self, test_context: CthulhuTestContext) -> None: """Test set_dynamic_column_headers_row successfully sets column headers row.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_table = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXUtilities.get_table", return_value=mock_table) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", return_value=(1, 2), ) test_context.patch( "cthulhu.table_navigator.AXUtilities.set_dynamic_column_headers_row", return_value=None, ) essential_modules["cthulhu.messages"].DYNAMIC_COLUMN_HEADER_SET = "Column header row set to %d" from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.set_dynamic_column_headers_row(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with("Column header row set to 2") def test_clear_dynamic_column_headers_row_not_in_table( self, test_context: CthulhuTestContext, ) -> None: """Test clear_dynamic_column_headers_row presents not in table message. Test case when current cell is None. """ essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.clear_dynamic_column_headers_row(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_clear_dynamic_column_headers_row_successful( self, test_context: CthulhuTestContext, ) -> None: """Test clear_dynamic_column_headers_row successfully clears column headers row.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_table = test_context.Mock(spec=Atspi.Accessible) mock_focus_manager = test_context.Mock() essential_modules["cthulhu.focus_manager"].get_manager.return_value = mock_focus_manager mock_focus_manager.get_locus_of_focus.return_value = mock_current_cell test_context.patch("cthulhu.table_navigator.AXUtilities.get_table", return_value=mock_table) test_context.patch( "cthulhu.table_navigator.AXUtilities.clear_dynamic_column_headers_row", return_value=None, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() pres_manager.interrupt_presentation.reset_mock() result = navigator.clear_dynamic_column_headers_row(mock_script, mock_event) assert result is True pres_manager.interrupt_presentation.assert_called_once() pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].DYNAMIC_COLUMN_HEADER_CLEARED, ) def test_set_dynamic_row_headers_column_not_in_table( self, test_context: CthulhuTestContext, ) -> None: """Test set_dynamic_row_headers_column presents not in table message. Test case when current cell is None. """ essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.set_dynamic_row_headers_column(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_set_dynamic_row_headers_column_successful(self, test_context: CthulhuTestContext) -> None: """Test set_dynamic_row_headers_column successfully sets row headers column.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_table = test_context.Mock(spec=Atspi.Accessible) test_context.patch("cthulhu.table_navigator.AXUtilities.get_table", return_value=mock_table) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", return_value=(2, 1), ) test_context.patch( "cthulhu.table_navigator.AXUtilities.set_dynamic_row_headers_column", return_value=None, ) essential_modules["cthulhu.messages"].DYNAMIC_ROW_HEADER_SET = "Row header column set to %s" test_context.patch( "cthulhu.table_navigator.AXUtilities.get_column_label", create=True, return_value="B", ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.set_dynamic_row_headers_column(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with("Row header column set to B") def test_clear_dynamic_row_headers_column_not_in_table( self, test_context: CthulhuTestContext, ) -> None: """Test clear_dynamic_row_headers_column presents not in table message. Test case when current cell is None. """ essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=None) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() result = navigator.clear_dynamic_row_headers_column(mock_script, mock_event) assert result is True pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].TABLE_NOT_IN_A, ) def test_clear_dynamic_row_headers_column_successful( self, test_context: CthulhuTestContext, ) -> None: """Test clear_dynamic_row_headers_column successfully clears row headers column.""" essential_modules = self._setup_dependencies(test_context) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) mock_current_cell = test_context.Mock(spec=Atspi.Accessible) mock_table = test_context.Mock(spec=Atspi.Accessible) mock_focus_manager = test_context.Mock() essential_modules["cthulhu.focus_manager"].get_manager.return_value = mock_focus_manager mock_focus_manager.get_locus_of_focus.return_value = mock_current_cell test_context.patch("cthulhu.table_navigator.AXUtilities.get_table", return_value=mock_table) test_context.patch( "cthulhu.table_navigator.AXUtilities.clear_dynamic_row_headers_column", return_value=None, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._get_current_cell = test_context.Mock(return_value=mock_current_cell) mock_script = test_context.Mock() mock_event = test_context.Mock() pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() pres_manager.interrupt_presentation.reset_mock() result = navigator.clear_dynamic_row_headers_column(mock_script, mock_event) assert result is True pres_manager.interrupt_presentation.assert_called_once() pres_manager.present_message.assert_called_once_with( essential_modules["cthulhu.messages"].DYNAMIC_ROW_HEADER_CLEARED, ) def test_get_cell_coordinates_with_different_previous_cell( self, test_context: CthulhuTestContext, ) -> None: """Test _get_cell_coordinates returns actual coordinates when previous cell differs.""" essential_modules = self._setup_dependencies(test_context) mock_cell = test_context.Mock(spec=Atspi.Accessible) mock_table = test_context.Mock(spec=Atspi.Accessible) mock_different_cell = test_context.Mock(spec=Atspi.Accessible) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_coordinates", return_value=(2, 3), ) test_context.patch("cthulhu.table_navigator.AXUtilities.get_table", return_value=mock_table) test_context.patch( "cthulhu.table_navigator.AXTable.get_cell_at", return_value=mock_different_cell, ) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() navigator._previous_reported_row = 1 navigator._previous_reported_col = 2 result = navigator._get_cell_coordinates(mock_cell) assert result == (2, 3) def test_present_cell_with_settings_enabled(self, test_context: CthulhuTestContext) -> None: """Test _present_cell with speakCellCoordinates and speakCellSpan enabled.""" essential_modules = self._setup_dependencies(test_context) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", return_value=True, ) test_context.patch("cthulhu.table_navigator.AXObject.grab_focus", return_value=None) test_context.patch( "cthulhu.table_navigator.AXUtilities.get_descendant_supporting_text", return_value=None ) test_context.patch("cthulhu.table_navigator.AXObject.supports_text", return_value=False) test_context.patch("cthulhu.table_navigator.AXTable.get_cell_spans", return_value=(2, 3)) mock_focus_manager = test_context.Mock() essential_modules["cthulhu.focus_manager"].get_manager.return_value = mock_focus_manager essential_modules["cthulhu.messages"].TABLE_CELL_COORDINATES = "Row %(row)s, column %(column)s" essential_modules["cthulhu.messages"].cell_span.return_value = "spans 2 rows and 3 columns" mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() mock_script = test_context.Mock() mock_script.utilities.grab_focus_when_setting_caret.return_value = False test_context.patch("cthulhu.table_navigator.AXUtilities.is_gui_cell", return_value=False) mock_script.present_object = test_context.Mock() mock_cell = test_context.Mock(spec=Atspi.Accessible) mock_previous_cell = test_context.Mock(spec=Atspi.Accessible) pres_manager = essential_modules["cthulhu.presentation_manager"].get_manager() pres_manager.present_message.reset_mock() navigator._present_cell(mock_script, mock_cell, 1, 2, mock_previous_cell) assert navigator._previous_reported_row == 1 assert navigator._previous_reported_col == 2 mock_focus_manager.set_locus_of_focus.assert_called() mock_script.present_object.assert_called_once_with( mock_cell, offset=0, priorObj=mock_previous_cell, interrupt=True, ) assert pres_manager.present_message.call_count == 2 def test_present_cell_with_text_descendant_and_gui_cell( self, test_context: CthulhuTestContext, ) -> None: """Test _present_cell when cell has text descendant and is gui cell.""" essential_modules = self._setup_dependencies(test_context) mock_text_obj = test_context.Mock(spec=Atspi.Accessible) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", return_value=True, ) test_context.patch("cthulhu.table_navigator.AXObject.grab_focus", return_value=None) test_context.patch( "cthulhu.table_navigator.AXUtilities.get_descendant_supporting_text", return_value=mock_text_obj, ) test_context.patch( "cthulhu.table_navigator.AXObject.supports_text", side_effect=lambda obj: obj == mock_text_obj, ) test_context.patch("cthulhu.table_navigator.AXTable.get_cell_spans", return_value=(1, 1)) mock_focus_manager = test_context.Mock() essential_modules["cthulhu.focus_manager"].get_manager.return_value = mock_focus_manager mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu import gsettings_registry from cthulhu.table_navigator import TableNavigator registry = gsettings_registry.get_registry() registry.set_runtime_value("speech", "announce-cell-coordinates", False) registry.set_runtime_value("speech", "announce-cell-span", False) navigator = TableNavigator() mock_script = test_context.Mock() mock_script.utilities.grab_focus_when_setting_caret.return_value = True test_context.patch("cthulhu.table_navigator.AXUtilities.is_gui_cell", return_value=True) mock_script.utilities.set_caret_position = test_context.Mock() mock_script.present_object = test_context.Mock() mock_cell = test_context.Mock(spec=Atspi.Accessible) mock_previous_cell = test_context.Mock(spec=Atspi.Accessible) navigator._present_cell(mock_script, mock_cell, 1, 2, mock_previous_cell) mock_focus_manager.set_locus_of_focus.assert_called_with(None, mock_text_obj, False) assert navigator._previous_reported_row == 1 assert navigator._previous_reported_col == 2 def test_get_skip_blank_cells(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.get_skip_blank_cells returns setting value.""" self._setup_dependencies(test_context) from cthulhu import gsettings_registry from cthulhu.table_navigator import get_navigator gsettings_registry.get_registry().set_runtime_value( "table-navigation", "skip-blank-cells", True, ) nav = get_navigator() result = nav.get_skip_blank_cells() assert result is True def test_set_skip_blank_cells(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.set_skip_blank_cells updates setting.""" self._setup_dependencies(test_context) from cthulhu.table_navigator import get_navigator nav = get_navigator() result = nav.set_skip_blank_cells(True) assert result is True assert nav.get_skip_blank_cells() is True def test_set_skip_blank_cells_no_change(self, test_context: CthulhuTestContext) -> None: """Test TableNavigator.set_skip_blank_cells returns early if value unchanged.""" self._setup_dependencies(test_context) from cthulhu import gsettings_registry from cthulhu.table_navigator import get_navigator gsettings_registry.get_registry().set_runtime_value( "table-navigation", "skip-blank-cells", True, ) nav = get_navigator() result = nav.set_skip_blank_cells(True) assert result is True def test_present_cell_emits_region_changed(self, test_context: CthulhuTestContext) -> None: """Test _present_cell emits region_changed with TABLE_NAVIGATOR mode.""" essential_modules = self._setup_dependencies(test_context) test_context.patch( "cthulhu.table_navigator.AXUtilities.is_table_cell_or_header", return_value=True, ) test_context.patch("cthulhu.table_navigator.AXObject.grab_focus", return_value=None) test_context.patch( "cthulhu.table_navigator.AXUtilities.get_descendant_supporting_text", return_value=None ) test_context.patch("cthulhu.table_navigator.AXObject.supports_text", return_value=False) test_context.patch("cthulhu.table_navigator.AXTable.get_cell_spans", return_value=(1, 1)) mock_focus_manager = test_context.Mock() essential_modules["cthulhu.focus_manager"].get_manager.return_value = mock_focus_manager from cthulhu import focus_manager, gsettings_registry essential_modules["cthulhu.focus_manager"].TABLE_NAVIGATOR = focus_manager.TABLE_NAVIGATOR registry = gsettings_registry.get_registry() registry.set_runtime_value("speech", "announce-cell-coordinates", False) registry.set_runtime_value("speech", "announce-cell-span", False) mock_controller = test_context.Mock() essential_modules["cthulhu.dbus_service"].get_remote_controller.return_value = mock_controller mock_keybindings_class = test_context.Mock() mock_keybindings_instance = test_context.Mock() mock_keybindings_class.return_value = mock_keybindings_instance test_context.patch( "cthulhu.table_navigator.keybindings.KeyBindings", new=mock_keybindings_class, ) from cthulhu.table_navigator import TableNavigator navigator = TableNavigator() mock_script = test_context.Mock() mock_script.utilities.grab_focus_when_setting_caret.return_value = False test_context.patch("cthulhu.table_navigator.AXUtilities.is_gui_cell", return_value=False) mock_script.present_object = test_context.Mock() mock_cell = test_context.Mock(spec=Atspi.Accessible) mock_previous_cell = test_context.Mock(spec=Atspi.Accessible) navigator._present_cell(mock_script, mock_cell, 1, 2, mock_previous_cell) mock_focus_manager.emit_region_changed.assert_called() call_kwargs = mock_focus_manager.emit_region_changed.call_args assert call_kwargs.kwargs.get("mode") == focus_manager.TABLE_NAVIGATOR