Files
cthulhu/tests/test_document_presenter.py

2332 lines
89 KiB
Python

# Unit tests for document_presenter.py.
#
# Copyright 2026 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=protected-access
# pylint: disable=import-outside-toplevel
# pylint: disable=too-many-public-methods
# pylint: disable=too-many-locals
# pylint: disable=too-many-lines
"""Unit tests for document_presenter.py."""
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
if TYPE_CHECKING:
from cthulhu_test_context import CthulhuTestContext
@pytest.mark.unit
class TestDocumentPresenter:
"""Test DocumentPresenter class."""
def _setup_presenter(self, test_context: CthulhuTestContext):
"""Set up mocks for document_presenter dependencies."""
additional_modules = [
"cthulhu.ax_document",
"cthulhu.ax_object",
"cthulhu.ax_table",
"cthulhu.ax_text",
"cthulhu.ax_utilities",
"cthulhu.caret_navigator",
"cthulhu.focus_manager",
"cthulhu.guilabels",
"cthulhu.input_event_manager",
"cthulhu.live_region_presenter",
"cthulhu.preferences_grid_base",
"cthulhu.script_manager",
"cthulhu.structural_navigator",
"cthulhu.table_navigator",
"cthulhu.braille_presenter",
"cthulhu.presentation_manager",
]
essential_modules = test_context.setup_shared_dependencies(additional_modules)
# Set up guilabels with required constants
guilabels = essential_modules["cthulhu.guilabels"]
guilabels.DOCUMENTS = "Documents"
guilabels.KB_GROUP_CARET_NAVIGATION = "Caret Navigation"
guilabels.KB_GROUP_STRUCTURAL_NAVIGATION = "Structural Navigation"
guilabels.KB_GROUP_TABLE_NAVIGATION = "Table Navigation"
guilabels.NATIVE_NAVIGATION = "Native Navigation"
guilabels.AUTOMATIC_FOCUS_MODE = "Automatic focus mode"
guilabels.CONTENT_LAYOUT_MODE = "Layout mode"
guilabels.TABLE_SKIP_BLANK_CELLS = "Skip blank cells"
guilabels.FIND_SPEAK_RESULTS = "Speak find results"
guilabels.FIND_ONLY_SPEAK_CHANGED_LINES = "Only speak changed lines"
guilabels.FIND_MINIMUM_MATCH_LENGTH = "Minimum match length"
guilabels.FIND_OPTIONS = "Find Options"
guilabels.READ_PAGE_UPON_LOAD = "Read page upon load"
guilabels.PAGE_SUMMARY_UPON_LOAD = "Page summary upon load"
guilabels.PAGE_LOAD = "Page Load"
guilabels.CARET_NAVIGATION_INFO = "Caret navigation info"
guilabels.STRUCTURAL_NAVIGATION_INFO = "Structural navigation info"
guilabels.NATIVE_NAVIGATION_INFO = "Native navigation info"
guilabels.AUTOMATIC_FOCUS_MODE_INFO = "Auto focus mode info"
from cthulhu import gsettings_registry
registry = gsettings_registry.get_registry()
registry.clear_runtime_values()
# Import and return the module
from cthulhu import document_presenter
return document_presenter, essential_modules
def test_get_presenter_returns_singleton(self, test_context: CthulhuTestContext) -> None:
"""Test get_presenter returns the same instance."""
module, _mocks = self._setup_presenter(test_context)
presenter1 = module.get_presenter()
presenter2 = module.get_presenter()
assert presenter1 is presenter2
def test_get_native_nav_triggers_focus_mode_default(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test get_native_nav_triggers_focus_mode returns default value."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.get_native_nav_triggers_focus_mode()
assert result is True
def test_set_native_nav_triggers_focus_mode(self, test_context: CthulhuTestContext) -> None:
"""Test set_native_nav_triggers_focus_mode updates setting."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.set_native_nav_triggers_focus_mode(False)
assert result is True
assert presenter.get_native_nav_triggers_focus_mode() is False
def test_set_native_nav_triggers_focus_mode_no_change(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test set_native_nav_triggers_focus_mode returns True when value unchanged."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.set_native_nav_triggers_focus_mode(True)
assert result is True
def test_get_say_all_on_load_default(self, test_context: CthulhuTestContext) -> None:
"""Test get_say_all_on_load returns default value."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.get_say_all_on_load()
assert result is True
def test_set_say_all_on_load(self, test_context: CthulhuTestContext) -> None:
"""Test set_say_all_on_load updates setting."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.set_say_all_on_load(False)
assert result is True
assert presenter.get_say_all_on_load() is False
def test_set_say_all_on_load_no_change(self, test_context: CthulhuTestContext) -> None:
"""Test set_say_all_on_load returns True when value unchanged."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.set_say_all_on_load(True)
assert result is True
def test_get_page_summary_on_load_default(self, test_context: CthulhuTestContext) -> None:
"""Test get_page_summary_on_load returns default value."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.get_page_summary_on_load()
assert result is True
def test_set_page_summary_on_load(self, test_context: CthulhuTestContext) -> None:
"""Test set_page_summary_on_load updates setting."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.set_page_summary_on_load(False)
assert result is True
assert presenter.get_page_summary_on_load() is False
def test_set_page_summary_on_load_no_change(self, test_context: CthulhuTestContext) -> None:
"""Test set_page_summary_on_load returns True when value unchanged."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.set_page_summary_on_load(True)
assert result is True
def test_get_speak_find_results_true(self, test_context: CthulhuTestContext) -> None:
"""Test get_speak_find_results returns True when verbosity is not NONE."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.get_speak_find_results()
assert result is True
def test_get_speak_find_results_false(self, test_context: CthulhuTestContext) -> None:
"""Test get_speak_find_results returns False when verbosity is NONE."""
module, _mocks = self._setup_presenter(test_context)
from cthulhu import gsettings_registry # pylint: disable=import-outside-toplevel
presenter = module.get_presenter()
gsettings_registry.get_registry().set_runtime_value(
"document",
"find-results-verbosity",
"none",
)
result = presenter.get_speak_find_results()
assert result is False
def test_set_speak_find_results_enable(self, test_context: CthulhuTestContext) -> None:
"""Test set_speak_find_results enables speech."""
module, _mocks = self._setup_presenter(test_context)
from cthulhu import gsettings_registry # pylint: disable=import-outside-toplevel
presenter = module.get_presenter()
gsettings_registry.get_registry().set_runtime_value(
"document",
"find-results-verbosity",
"none",
)
result = presenter.set_speak_find_results(True)
assert result is True
assert presenter.get_speak_find_results() is True
def test_set_speak_find_results_disable(self, test_context: CthulhuTestContext) -> None:
"""Test set_speak_find_results disables speech."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.set_speak_find_results(False)
assert result is True
assert presenter.get_speak_find_results() is False
def test_get_only_speak_changed_lines_true(self, test_context: CthulhuTestContext) -> None:
"""Test get_only_speak_changed_lines returns True when set."""
module, _mocks = self._setup_presenter(test_context)
from cthulhu import gsettings_registry # pylint: disable=import-outside-toplevel
presenter = module.get_presenter()
gsettings_registry.get_registry().set_runtime_value(
"document",
"find-results-verbosity",
"if-line-changed",
)
result = presenter.get_only_speak_changed_lines()
assert result is True
def test_get_only_speak_changed_lines_false(self, test_context: CthulhuTestContext) -> None:
"""Test get_only_speak_changed_lines returns False when not set."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.get_only_speak_changed_lines()
assert result is False
def test_set_only_speak_changed_lines_enable(self, test_context: CthulhuTestContext) -> None:
"""Test set_only_speak_changed_lines enables the option."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
result = presenter.set_only_speak_changed_lines(True)
assert result is True
assert presenter.get_only_speak_changed_lines() is True
def test_set_only_speak_changed_lines_disable(self, test_context: CthulhuTestContext) -> None:
"""Test set_only_speak_changed_lines disables the option."""
module, _mocks = self._setup_presenter(test_context)
from cthulhu import gsettings_registry # pylint: disable=import-outside-toplevel
presenter = module.get_presenter()
gsettings_registry.get_registry().set_runtime_value(
"document",
"find-results-verbosity",
"if-line-changed",
)
result = presenter.set_only_speak_changed_lines(False)
assert result is True
assert presenter.get_only_speak_changed_lines() is False
def test_get_find_results_minimum_length(self, test_context: CthulhuTestContext) -> None:
"""Test get_find_results_minimum_length returns current value."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
presenter.set_find_results_minimum_length(5)
result = presenter.get_find_results_minimum_length()
assert result == 5
def test_set_find_results_minimum_length(self, test_context: CthulhuTestContext) -> None:
"""Test set_find_results_minimum_length updates setting."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
presenter.set_find_results_minimum_length(5)
result = presenter.set_find_results_minimum_length(10)
assert result is True
assert presenter.get_find_results_minimum_length() == 10
def test_set_find_results_minimum_length_no_change(self, test_context: CthulhuTestContext) -> None:
"""Test set_find_results_minimum_length returns True when value unchanged."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
presenter.set_find_results_minimum_length(5)
result = presenter.set_find_results_minimum_length(5)
assert result is True
def test_reset_find_announcement_state(self, test_context: CthulhuTestContext) -> None:
"""Test reset_find_announcement_state resets the internal state."""
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
# Set the internal state to True
presenter._made_find_announcement = True
assert presenter._made_find_announcement is True
# Reset and verify
presenter.reset_find_announcement_state()
assert presenter._made_find_announcement is False
def test_present_find_results_no_active_script(self, test_context: CthulhuTestContext) -> None:
"""Test present_find_results returns False when no active script."""
module, mocks = self._setup_presenter(test_context)
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = None
presenter = module.get_presenter()
result = presenter.present_find_results(None, 0)
assert result is False
def test_present_find_results_no_document(self, test_context: CthulhuTestContext) -> None:
"""Test present_find_results returns False when no document."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
# Set up mock script with utilities
mock_script = MagicMock()
mock_script.utilities.get_document_for_object.return_value = None
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
presenter = module.get_presenter()
mock_obj = MagicMock()
result = presenter.present_find_results(mock_obj, 0)
assert result is False
def test_present_find_results_selection_too_short(self, test_context: CthulhuTestContext) -> None:
"""Test present_find_results returns False when selection is too short."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
from cthulhu import gsettings_registry # pylint: disable=import-outside-toplevel
gsettings_registry.get_registry().set_runtime_value(
"document",
"find-results-minimum-length",
5,
)
# Set up mock script
mock_script = MagicMock()
mock_script.utilities.get_document_for_object.return_value = MagicMock()
mock_script.utilities.get_caret_context.return_value = (None, 0)
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
# Set up AXText mock to return short selection (length 3)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.get_selection_start_offset.return_value = 0
ax_utilities.AXUtilities.get_selection_end_offset.return_value = 3
presenter = module.get_presenter()
mock_obj = MagicMock()
result = presenter.present_find_results(mock_obj, 0)
assert result is False
def test_present_find_results_speak_disabled(self, test_context: CthulhuTestContext) -> None:
"""Test present_find_results returns False when speak is disabled."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
from cthulhu import gsettings_registry # pylint: disable=import-outside-toplevel
registry = gsettings_registry.get_registry()
registry.set_runtime_value("document", "find-results-minimum-length", 3)
registry.set_runtime_value("document", "find-results-verbosity", "none")
# Set up mock script
mock_script = MagicMock()
mock_script.utilities.get_document_for_object.return_value = MagicMock()
mock_script.utilities.get_caret_context.return_value = (None, 0)
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
# Set up AXText mock with valid selection length
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.get_selection_start_offset.return_value = 0
ax_utilities.AXUtilities.get_selection_end_offset.return_value = 10
presenter = module.get_presenter()
mock_obj = MagicMock()
result = presenter.present_find_results(mock_obj, 0)
assert result is False
def test_present_find_results_success(self, test_context: CthulhuTestContext) -> None:
"""Test present_find_results returns True and presents when conditions are met."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
from cthulhu import gsettings_registry # pylint: disable=import-outside-toplevel
gsettings_registry.get_registry().set_runtime_value(
"document",
"find-results-minimum-length",
3,
)
# Set up mock script
mock_script = MagicMock()
mock_script.utilities.get_document_for_object.return_value = MagicMock()
mock_script.utilities.get_caret_context.return_value = (None, 0)
mock_script.utilities.get_line_contents_at_offset.return_value = ["test content"]
mock_script.utilities.get_find_results_count.return_value = "1 of 5"
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
# Set up AXText mock with valid selection length
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.get_selection_start_offset.return_value = 0
ax_utilities.AXUtilities.get_selection_end_offset.return_value = 10
presenter = module.get_presenter()
presenter._made_find_announcement = False
pres_manager = mocks["cthulhu.presentation_manager"].get_manager()
pres_manager.speak_contents.reset_mock()
pres_manager.present_message.reset_mock()
mock_obj = MagicMock()
result = presenter.present_find_results(mock_obj, 0)
assert result is True
assert presenter._made_find_announcement is True
pres_manager.speak_contents.assert_called_once()
mock_script.update_braille.assert_called_once()
pres_manager.present_message.assert_called_once_with("1 of 5")
def test_present_find_results_skips_same_line_when_only_changed(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test present_find_results skips when same line and only_speak_changed_lines."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
from cthulhu import gsettings_registry # pylint: disable=import-outside-toplevel
registry = gsettings_registry.get_registry()
registry.set_runtime_value("document", "find-results-minimum-length", 3)
registry.set_runtime_value("document", "find-results-verbosity", "if-line-changed")
# Set up mock script
mock_script = MagicMock()
mock_script.utilities.get_document_for_object.return_value = MagicMock()
mock_script.utilities.get_caret_context.return_value = (MagicMock(), 5)
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
# Set up AXText mock with valid selection length
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.get_selection_start_offset.return_value = 0
ax_utilities.AXUtilities.get_selection_end_offset.return_value = 10
ax_text = mocks["cthulhu.ax_text"]
ax_text.AXText.get_range_rect.return_value = MagicMock()
ax_utilities.AXUtilities.rects_are_on_same_line = MagicMock(return_value=True)
presenter = module.get_presenter()
presenter._made_find_announcement = True # Already announced
pres_manager = mocks["cthulhu.presentation_manager"].get_manager()
pres_manager.speak_contents.reset_mock()
mock_obj = MagicMock()
result = presenter.present_find_results(mock_obj, 5)
assert result is False
pres_manager.speak_contents.assert_not_called()
def test_use_focus_mode_no_active_script(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns False when no active script."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = None
presenter = module.get_presenter()
result = presenter.use_focus_mode(MagicMock())
assert result is False
def test_use_focus_mode_sticky_focus_mode(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns True when focus mode is sticky."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=True,
browse_mode_is_sticky=False,
)
result = presenter.use_focus_mode(MagicMock())
assert result is True
def test_use_focus_mode_sticky_browse_mode(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns False when browse mode is sticky."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=True,
)
result = presenter.use_focus_mode(MagicMock())
assert result is False
def test_use_focus_mode_in_say_all(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns False when in say all."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = True
presenter = module.get_presenter()
# No sticky state set (defaults to browse mode)
result = presenter.use_focus_mode(MagicMock())
assert result is False
def test_use_focus_mode_struct_nav_prevents(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns False when struct nav prevents it."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = True
presenter = module.get_presenter()
result = presenter.use_focus_mode(MagicMock())
assert result is False
def test_use_focus_mode_table_nav_prevents(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns False when table nav was last command."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = True
presenter = module.get_presenter()
result = presenter.use_focus_mode(MagicMock())
assert result is False
def test_use_focus_mode_caret_nav_prevents(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns False when caret nav prevents it."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
caret_nav = mocks["cthulhu.caret_navigator"]
caret_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = True
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.is_dead.return_value = False
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.find_ancestor_inclusive.return_value = None
presenter = module.get_presenter()
result = presenter.use_focus_mode(MagicMock(), MagicMock())
assert result is False
def test_use_focus_mode_focus_mode_widget(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns True for focus mode widget."""
from unittest.mock import MagicMock, patch
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
caret_nav = mocks["cthulhu.caret_navigator"]
caret_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
presenter = module.get_presenter()
with patch.object(presenter, "is_focus_mode_widget", return_value=True):
result = presenter.use_focus_mode(MagicMock())
assert result is True
def test_use_focus_mode_entering_web_app(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns True when entering a web application."""
from unittest.mock import MagicMock, patch
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
caret_nav = mocks["cthulhu.caret_navigator"]
caret_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_link.return_value = False
ax_utilities.AXUtilities.is_radio_button.return_value = False
ax_utilities.AXUtilities.is_embedded = MagicMock()
# prev_obj not in app, obj in app
ax_utilities.AXUtilities.find_ancestor.side_effect = [None, MagicMock()]
presenter = module.get_presenter()
with patch.object(presenter, "is_focus_mode_widget", return_value=False):
result = presenter.use_focus_mode(MagicMock(), MagicMock())
assert result is True
def test_use_focus_mode_default_false(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns False by default."""
from unittest.mock import MagicMock, patch
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
caret_nav = mocks["cthulhu.caret_navigator"]
caret_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_link.return_value = False
ax_utilities.AXUtilities.is_radio_button.return_value = False
ax_utilities.AXUtilities.is_embedded = MagicMock()
ax_utilities.AXUtilities.find_ancestor.return_value = None
presenter = module.get_presenter()
with patch.object(presenter, "is_focus_mode_widget", return_value=False):
result = presenter.use_focus_mode(MagicMock())
assert result is False
def test_use_focus_mode_native_nav_no_trigger(self, test_context: CthulhuTestContext) -> None:
"""Test use_focus_mode returns current mode when native nav doesn't trigger."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
nav_mock = struct_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
caret_nav = mocks["cthulhu.caret_navigator"]
caret_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
nav_mock = caret_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
presenter = module.get_presenter()
presenter.set_native_nav_triggers_focus_mode(False)
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
result = presenter.use_focus_mode(MagicMock())
assert result is True
def test_in_focus_mode_default_false(self, test_context: CthulhuTestContext) -> None:
"""Test in_focus_mode returns False when no state exists for app."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
mock_app = MagicMock()
result = presenter.in_focus_mode(mock_app)
assert result is False
def test_in_focus_mode_returns_state(self, test_context: CthulhuTestContext) -> None:
"""Test in_focus_mode returns stored state."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
mock_app = MagicMock()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
result = presenter.in_focus_mode(mock_app)
assert result is True
def test_focus_mode_is_sticky_default_false(self, test_context: CthulhuTestContext) -> None:
"""Test focus_mode_is_sticky returns False by default."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
mock_app = MagicMock()
result = presenter.focus_mode_is_sticky(mock_app)
assert result is False
def test_focus_mode_is_sticky_returns_state(self, test_context: CthulhuTestContext) -> None:
"""Test focus_mode_is_sticky returns stored state."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
mock_app = MagicMock()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=True,
browse_mode_is_sticky=False,
)
result = presenter.focus_mode_is_sticky(mock_app)
assert result is True
def test_browse_mode_is_sticky_default_false(self, test_context: CthulhuTestContext) -> None:
"""Test browse_mode_is_sticky returns False by default."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
mock_app = MagicMock()
result = presenter.browse_mode_is_sticky(mock_app)
assert result is False
def test_browse_mode_is_sticky_returns_state(self, test_context: CthulhuTestContext) -> None:
"""Test browse_mode_is_sticky returns stored state."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
mock_app = MagicMock()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=True,
)
result = presenter.browse_mode_is_sticky(mock_app)
assert result is True
def test_get_state_for_app_sets_mode(self, test_context: CthulhuTestContext) -> None:
"""Test _get_state_for_app can be used to set mode state."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
mock_app = MagicMock()
state = presenter._get_state_for_app(mock_app)
state.in_focus_mode = True
assert presenter.in_focus_mode(mock_app) is True
state = presenter._get_state_for_app(mock_app)
state.in_focus_mode = False
assert presenter.in_focus_mode(mock_app) is False
def test_clear_state_for_app(self, test_context: CthulhuTestContext) -> None:
"""Test clear_state_for_app removes app state."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
mock_app = MagicMock()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=True,
)
presenter.clear_state_for_app(mock_app)
assert presenter.in_focus_mode(mock_app) is False
assert presenter.focus_mode_is_sticky(mock_app) is False
def test_per_app_state_isolation(self, test_context: CthulhuTestContext) -> None:
"""Test that different apps have isolated mode state."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
presenter = module.get_presenter()
app1 = MagicMock()
app2 = MagicMock()
presenter._app_states[hash(app1)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=True,
browse_mode_is_sticky=False,
)
presenter._app_states[hash(app2)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=True,
)
assert presenter.in_focus_mode(app1) is True
assert presenter.focus_mode_is_sticky(app1) is True
assert presenter.browse_mode_is_sticky(app1) is False
assert presenter.in_focus_mode(app2) is False
assert presenter.focus_mode_is_sticky(app2) is False
assert presenter.browse_mode_is_sticky(app2) is True
def test_set_presentation_mode_not_in_document(self, test_context: CthulhuTestContext) -> None:
"""Test set_presentation_mode returns False when not in document."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_script = MagicMock()
mock_script.utilities.in_document_content.return_value = False
mocks["cthulhu.messages"] = MagicMock()
mocks["cthulhu.messages"].DOCUMENT_NOT_IN_A = "Not in document"
presenter = module.get_presenter()
pres_manager = mocks["cthulhu.presentation_manager"].get_manager()
pres_manager.present_message.reset_mock()
result = presenter._set_presentation_mode(mock_script, True, obj=MagicMock())
assert result is False
pres_manager.present_message.assert_called_once()
def test_set_presentation_mode_same_mode(self, test_context: CthulhuTestContext) -> None:
"""Test set_presentation_mode returns False when already in requested mode."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_script.utilities.in_document_content.return_value = True
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
result = presenter._set_presentation_mode(mock_script, True, obj=MagicMock())
assert result is False
def test_set_presentation_mode_to_browse(self, test_context: CthulhuTestContext) -> None:
"""Test set_presentation_mode switches to browse mode."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_script.utilities.in_document_content.return_value = True
mock_script.utilities.get_caret_context.return_value = (MagicMock(), 0)
struct_nav = mocks["cthulhu.structural_navigator"]
caret_nav = mocks["cthulhu.caret_navigator"]
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
result = presenter._set_presentation_mode(mock_script, False, obj=MagicMock())
assert result is True
assert presenter.in_focus_mode(mock_app) is False
struct_nav.get_navigator.return_value.set_mode.assert_called()
caret_nav.get_navigator.return_value.set_enabled_for_script.assert_called()
def test_set_presentation_mode_to_focus(self, test_context: CthulhuTestContext) -> None:
"""Test set_presentation_mode switches to focus mode."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_script.utilities.in_document_content.return_value = True
mock_script.utilities.get_caret_context.return_value = (MagicMock(), 0)
caret_nav = mocks["cthulhu.caret_navigator"]
nav_mock = caret_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
nav_mock = struct_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
result = presenter._set_presentation_mode(mock_script, True, obj=MagicMock())
assert result is True
assert presenter.in_focus_mode(mock_app) is True
def test_set_presentation_mode_dead_obj_fallback(self, test_context: CthulhuTestContext) -> None:
"""Test set_presentation_mode uses locus of focus when obj is dead."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_script.utilities.in_document_content.return_value = True
mock_script.utilities.get_caret_context.return_value = (MagicMock(), 0)
caret_nav = mocks["cthulhu.caret_navigator"]
nav_mock = caret_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
nav_mock = struct_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.is_dead.return_value = True
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
dead_obj = MagicMock()
result = presenter._set_presentation_mode(mock_script, True, obj=dead_obj)
assert result is True
mock_script.utilities.in_document_content.assert_called_with(None)
def test_suspend_navigators(self, test_context: CthulhuTestContext) -> None:
"""Test suspend_navigators suspends all navigators."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
caret_nav = mocks["cthulhu.caret_navigator"]
struct_nav = mocks["cthulhu.structural_navigator"]
presenter = module.get_presenter()
result = presenter.suspend_navigators(mock_script, True, "test")
assert result is True
caret_nav.get_navigator.return_value.suspend_commands.assert_called_with(
mock_script,
True,
"test",
)
struct_nav.get_navigator.return_value.suspend_commands.assert_called_with(
mock_script,
True,
"test",
)
def test_enable_sticky_focus_mode(self, test_context: CthulhuTestContext) -> None:
"""Test enable_sticky_focus_mode sets sticky focus mode."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
presenter = module.get_presenter()
pres_manager = mocks["cthulhu.presentation_manager"].get_manager()
pres_manager.present_message.reset_mock()
result = presenter.enable_sticky_focus_mode(mock_script)
assert result is True
assert presenter.in_focus_mode(mock_app) is True
assert presenter.focus_mode_is_sticky(mock_app) is True
assert presenter.browse_mode_is_sticky(mock_app) is False
pres_manager.present_message.assert_called()
def test_enable_sticky_browse_mode(self, test_context: CthulhuTestContext) -> None:
"""Test enable_sticky_browse_mode sets sticky browse mode."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
presenter = module.get_presenter()
pres_manager = mocks["cthulhu.presentation_manager"].get_manager()
pres_manager.present_message.reset_mock()
result = presenter.enable_sticky_browse_mode(mock_script)
assert result is True
assert presenter.in_focus_mode(mock_app) is False
assert presenter.focus_mode_is_sticky(mock_app) is False
assert presenter.browse_mode_is_sticky(mock_app) is True
pres_manager.present_message.assert_called()
def test_toggle_presentation_mode_not_in_document(self, test_context: CthulhuTestContext) -> None:
"""Test toggle_presentation_mode when not in document."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_script = MagicMock()
mock_script.utilities.in_document_content.return_value = False
presenter = module.get_presenter()
pres_manager = mocks["cthulhu.presentation_manager"].get_manager()
pres_manager.present_message.reset_mock()
result = presenter.toggle_presentation_mode(mock_script)
assert result is True
pres_manager.present_message.assert_called()
def test_toggle_presentation_mode_to_focus(self, test_context: CthulhuTestContext) -> None:
"""Test toggle_presentation_mode switches to focus mode."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_script.utilities.in_document_content.return_value = True
mock_script.utilities.get_caret_context.return_value = (MagicMock(), 0)
caret_nav = mocks["cthulhu.caret_navigator"]
nav_mock = caret_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
nav_mock = struct_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
result = presenter.toggle_presentation_mode(mock_script)
assert result is True
assert presenter.in_focus_mode(mock_app) is True
def test_restore_mode_for_script_no_app(self, test_context: CthulhuTestContext) -> None:
"""Test restore_mode_for_script with no app does nothing."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
mock_script = MagicMock()
mock_script.app = None
presenter = module.get_presenter()
presenter.restore_mode_for_script(mock_script)
def test_restore_mode_for_script_no_state(self, test_context: CthulhuTestContext) -> None:
"""Test restore_mode_for_script with no existing state does nothing."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
mock_script = MagicMock()
mock_script.app = MagicMock()
presenter = module.get_presenter()
presenter.restore_mode_for_script(mock_script)
def test_restore_mode_for_script_with_state(self, test_context: CthulhuTestContext) -> None:
"""Test restore_mode_for_script restores navigator suspension state."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
caret_nav = mocks["cthulhu.caret_navigator"]
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
presenter.restore_mode_for_script(mock_script)
caret_nav.get_navigator.return_value.suspend_commands.assert_called()
def test_restore_mode_for_script_browse_mode_enables_navigators(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test restore_mode_for_script re-enables navigators when restoring browse mode."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
struct_nav = mocks["cthulhu.structural_navigator"]
caret_nav = mocks["cthulhu.caret_navigator"]
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
presenter.restore_mode_for_script(mock_script)
struct_nav.get_navigator.return_value.set_mode.assert_called_once()
caret_nav.get_navigator.return_value.set_enabled_for_script.assert_called_once_with(
mock_script,
True,
)
def test_update_mode_if_needed_not_in_doc(self, test_context: CthulhuTestContext) -> None:
"""Test update_mode_if_needed when neither in document suspends navigators."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_script = MagicMock()
mock_script.utilities.get_top_level_document_for_object.return_value = None
caret_nav = mocks["cthulhu.caret_navigator"]
presenter = module.get_presenter()
result = presenter.update_mode_if_needed(mock_script, MagicMock(), MagicMock())
# When focus is not in a document, navigators should be suspended
assert result is True
caret_nav.get_navigator.return_value.suspend_commands.assert_called()
def test_update_mode_if_needed_leaving_doc(self, test_context: CthulhuTestContext) -> None:
"""Test update_mode_if_needed when leaving document."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_doc = MagicMock()
mock_script.utilities.get_top_level_document_for_object.side_effect = [mock_doc, None]
caret_nav = mocks["cthulhu.caret_navigator"]
presenter = module.get_presenter()
old_focus = MagicMock()
new_focus = MagicMock()
result = presenter.update_mode_if_needed(mock_script, old_focus, new_focus)
assert result is True
caret_nav.get_navigator.return_value.suspend_commands.assert_called()
def test_update_mode_if_needed_sticky_focus(self, test_context: CthulhuTestContext) -> None:
"""Test update_mode_if_needed with sticky focus mode when entering document."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_doc = MagicMock()
mock_script.utilities.get_top_level_document_for_object.side_effect = [None, mock_doc]
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.old_focus_was_dead.return_value = False
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=True,
browse_mode_is_sticky=False,
)
pres_manager = mocks["cthulhu.presentation_manager"].get_manager()
pres_manager.present_message.reset_mock()
result = presenter.update_mode_if_needed(mock_script, MagicMock(), MagicMock())
assert result is True
pres_manager.present_message.assert_called()
def test_update_mode_if_needed_sticky_browse(self, test_context: CthulhuTestContext) -> None:
"""Test update_mode_if_needed with sticky browse mode when entering document."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_doc = MagicMock()
mock_script.utilities.get_top_level_document_for_object.side_effect = [None, mock_doc]
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.old_focus_was_dead.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
caret_nav = mocks["cthulhu.caret_navigator"]
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=True,
)
pres_manager = mocks["cthulhu.presentation_manager"].get_manager()
pres_manager.present_message.reset_mock()
result = presenter.update_mode_if_needed(mock_script, MagicMock(), MagicMock())
assert result is True
pres_manager.present_message.assert_called()
struct_nav.get_navigator.return_value.set_mode.assert_called()
caret_nav.get_navigator.return_value.set_enabled_for_script.assert_called()
def test_handle_entering_document_refreshes_commands(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test entering document refreshes commands even when mode unchanged."""
from unittest.mock import MagicMock, patch
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_doc = MagicMock()
mock_script.utilities.get_top_level_document_for_object.side_effect = [None, mock_doc]
caret_nav = mocks["cthulhu.caret_navigator"]
nav_mock = caret_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
caret_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
nav_mock = struct_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
focus_manager.get_manager.return_value.old_focus_was_dead.return_value = False
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
presenter = module.get_presenter()
# Already in browse mode - entering document should still refresh commands
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
with patch.object(presenter, "is_focus_mode_widget", return_value=False):
result = presenter.update_mode_if_needed(mock_script, MagicMock(), MagicMock())
assert result is True
# Verify commands were refreshed (suspend_commands called with suspended=False for browse)
caret_nav.get_navigator.return_value.suspend_commands.assert_called()
struct_nav.get_navigator.return_value.suspend_commands.assert_called()
def test_is_likely_electron_app_true(self, test_context: CthulhuTestContext) -> None:
"""Test _is_likely_electron_app returns True for Chromium toolkit non-browser."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_toolkit_name.return_value = "Chromium"
ax_object.AXObject.get_name.return_value = "code"
mock_app = MagicMock()
presenter = module.get_presenter()
result = presenter._is_likely_electron_app(mock_app)
assert result is True
def test_is_likely_electron_app_false_for_browser(self, test_context: CthulhuTestContext) -> None:
"""Test _is_likely_electron_app returns False for known browsers."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_toolkit_name.return_value = "Chromium"
ax_object.AXObject.get_name.return_value = "google-chrome"
mock_app = MagicMock()
presenter = module.get_presenter()
result = presenter._is_likely_electron_app(mock_app)
assert result is False
def test_is_likely_electron_app_false_for_non_chromium(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test _is_likely_electron_app returns False for non-Chromium toolkit."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_toolkit_name.return_value = "gtk"
ax_object.AXObject.get_name.return_value = "gedit"
mock_app = MagicMock()
presenter = module.get_presenter()
result = presenter._is_likely_electron_app(mock_app)
assert result is False
def test_update_mode_electron_app_sticky_focus(self, test_context: CthulhuTestContext) -> None:
"""Test update_mode_if_needed enables sticky focus for Electron apps when entering."""
from unittest.mock import MagicMock, patch
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_doc = MagicMock()
mock_script.utilities.get_top_level_document_for_object.side_effect = [None, mock_doc]
mock_script.utilities.in_document_content.return_value = True
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.old_focus_was_dead.return_value = False
presenter = module.get_presenter()
with patch.object(presenter, "_is_likely_electron_app", return_value=True):
result = presenter.update_mode_if_needed(mock_script, MagicMock(), MagicMock())
assert result is True
assert presenter.in_focus_mode(mock_app) is True
assert presenter.focus_mode_is_sticky(mock_app) is True
def test_is_top_level_web_app_true(self, test_context: CthulhuTestContext) -> None:
"""Test _is_top_level_web_app returns True for embedded doc with http URI."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_doc = MagicMock()
mock_script = MagicMock()
mock_script.utilities.active_document.return_value = mock_doc
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_embedded.return_value = True
ax_document = mocks["cthulhu.ax_document"]
ax_document.AXDocument.get_uri.return_value = "https://docs.google.com/document"
presenter = module.get_presenter()
result = presenter._is_top_level_web_app(mock_script, MagicMock())
assert result is True
def test_is_top_level_web_app_false_no_http(self, test_context: CthulhuTestContext) -> None:
"""Test _is_top_level_web_app returns False for non-http URI."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_doc = MagicMock()
mock_script = MagicMock()
mock_script.utilities.active_document.return_value = mock_doc
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_embedded.return_value = True
ax_document = mocks["cthulhu.ax_document"]
ax_document.AXDocument.get_uri.return_value = "file:///home/user/doc.html"
presenter = module.get_presenter()
result = presenter._is_top_level_web_app(mock_script, MagicMock())
assert result is False
def test_is_top_level_web_app_false_no_document(self, test_context: CthulhuTestContext) -> None:
"""Test _is_top_level_web_app returns False when no active document."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
mock_script = MagicMock()
mock_script.utilities.active_document.return_value = None
presenter = module.get_presenter()
result = presenter._is_top_level_web_app(mock_script, MagicMock())
assert result is False
def test_is_top_level_web_app_false_not_embedded(self, test_context: CthulhuTestContext) -> None:
"""Test _is_top_level_web_app returns False when document is not embedded role."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
mock_doc = MagicMock()
mock_script = MagicMock()
mock_script.utilities.active_document.return_value = mock_doc
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_embedded.return_value = False
presenter = module.get_presenter()
result = presenter._is_top_level_web_app(mock_script, MagicMock())
assert result is False
def test_update_mode_top_level_web_app_sticky_focus(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test update_mode_if_needed enables sticky focus for top-level web apps when entering."""
from unittest.mock import MagicMock, patch
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_doc = MagicMock()
mock_script.utilities.get_top_level_document_for_object.side_effect = [None, mock_doc]
mock_script.utilities.in_document_content.return_value = True
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.old_focus_was_dead.return_value = False
presenter = module.get_presenter()
with (
patch.object(presenter, "_is_likely_electron_app", return_value=False),
patch.object(presenter, "_is_top_level_web_app", return_value=True),
):
result = presenter.update_mode_if_needed(mock_script, MagicMock(), MagicMock())
assert result is True
assert presenter.in_focus_mode(mock_app) is True
assert presenter.focus_mode_is_sticky(mock_app) is True
def test_is_focus_mode_widget_editable(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for editable objects."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = True
mock_script = MagicMock()
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_combo_box(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for combo boxes."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_combo_box.return_value = True
mock_script = MagicMock()
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_expandable_focusable(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for expandable focusable non-links."""
from unittest.mock import MagicMock
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = True
ax_utilities.AXUtilities.is_focusable.return_value = True
ax_utilities.AXUtilities.is_link.return_value = False
mock_script = MagicMock()
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_expandable_link_false(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test is_focus_mode_widget returns False for expandable focusable links."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = True
ax_utilities.AXUtilities.is_focusable.return_value = True
ax_utilities.AXUtilities.is_link.return_value = True
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = False
ax_utilities.AXUtilities.is_grid = MagicMock()
ax_utilities.AXUtilities.is_menu = MagicMock()
ax_utilities.AXUtilities.is_tool_bar = MagicMock()
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.LINK
ax_utilities.AXUtilities.find_ancestor.return_value = None
mock_script = MagicMock()
mock_script.utilities.is_content_editable_with_embedded_objects.return_value = False
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is False
def test_is_focus_mode_widget_always_focus_role(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for always-focus-mode roles."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.SLIDER
mock_script = MagicMock()
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_layout_table_false(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns False for layout tables."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.TABLE_CELL
ax_utilities.AXUtilities.get_table.return_value = MagicMock()
ax_utilities.AXUtilities.is_layout_table.return_value = True
mock_script = MagicMock()
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is False
def test_is_focus_mode_widget_list_box_item(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for list box items."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = True
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.LIST_ITEM
ax_utilities.AXUtilities.is_layout_table.return_value = False
mock_script = MagicMock()
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_button_with_popup(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for buttons with popup."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = True
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.BUTTON
ax_utilities.AXUtilities.is_layout_table.return_value = False
mock_script = MagicMock()
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_table_cell_not_layout(
self,
test_context: CthulhuTestContext,
) -> None:
"""Test is_focus_mode_widget returns True for non-layout table cells."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = False
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.TABLE_CELL
ax_utilities.AXUtilities.get_table.return_value = MagicMock()
ax_utilities.AXUtilities.is_layout_table.return_value = False
ax_document = mocks["cthulhu.ax_document"]
ax_document.AXDocument.is_pdf.return_value = False
mock_script = MagicMock()
mock_script.utilities.is_text_block_element.return_value = False
mock_script.utilities.has_name_and_action_and_no_useful_children.return_value = False
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_grid_descendant(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for grid descendants."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = False
ax_utilities.AXUtilities.is_grid = MagicMock()
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.PARAGRAPH
ax_utilities.AXUtilities.find_ancestor.return_value = MagicMock()
ax_utilities.AXUtilities.is_layout_table.return_value = False
mock_script = MagicMock()
mock_script.utilities.is_text_block_element.return_value = True
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_menu_descendant(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for menu descendants."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = False
ax_utilities.AXUtilities.is_grid = MagicMock()
ax_utilities.AXUtilities.is_menu = MagicMock()
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.PARAGRAPH
ax_utilities.AXUtilities.find_ancestor.side_effect = [None, MagicMock()]
ax_utilities.AXUtilities.is_layout_table.return_value = False
mock_script = MagicMock()
mock_script.utilities.is_text_block_element.return_value = True
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_toolbar_descendant(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for toolbar descendants."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = False
ax_utilities.AXUtilities.is_grid = MagicMock()
ax_utilities.AXUtilities.is_menu = MagicMock()
ax_utilities.AXUtilities.is_tool_bar = MagicMock()
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.PARAGRAPH
ax_utilities.AXUtilities.find_ancestor.side_effect = [None, None, MagicMock()]
ax_utilities.AXUtilities.is_layout_table.return_value = False
mock_script = MagicMock()
mock_script.utilities.is_text_block_element.return_value = True
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_content_editable(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns True for content editable with embedded."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = False
ax_utilities.AXUtilities.is_grid = MagicMock()
ax_utilities.AXUtilities.is_menu = MagicMock()
ax_utilities.AXUtilities.is_tool_bar = MagicMock()
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.PARAGRAPH
ax_utilities.AXUtilities.find_ancestor.return_value = None
ax_utilities.AXUtilities.is_layout_table.return_value = False
mock_script = MagicMock()
mock_script.utilities.is_text_block_element.return_value = True
mock_script.utilities.is_content_editable_with_embedded_objects.return_value = True
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is True
def test_is_focus_mode_widget_default_false(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns False by default."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = False
ax_utilities.AXUtilities.is_grid = MagicMock()
ax_utilities.AXUtilities.is_menu = MagicMock()
ax_utilities.AXUtilities.is_tool_bar = MagicMock()
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.PARAGRAPH
ax_utilities.AXUtilities.find_ancestor.return_value = None
ax_utilities.AXUtilities.is_layout_table.return_value = False
mock_script = MagicMock()
mock_script.utilities.is_text_block_element.return_value = True
mock_script.utilities.is_content_editable_with_embedded_objects.return_value = False
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is False
def test_is_focus_mode_widget_pdf_table_false(self, test_context: CthulhuTestContext) -> None:
"""Test is_focus_mode_widget returns False for table cells in PDFs."""
from unittest.mock import MagicMock
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
module, mocks = self._setup_presenter(test_context)
ax_utilities = mocks["cthulhu.ax_utilities"]
ax_utilities.AXUtilities.is_editable.return_value = False
ax_utilities.AXUtilities.is_expandable.return_value = False
ax_utilities.AXUtilities.is_list_box_item.return_value = False
ax_utilities.AXUtilities.is_button_with_popup.return_value = False
ax_utilities.AXUtilities.is_grid = MagicMock()
ax_utilities.AXUtilities.is_menu = MagicMock()
ax_utilities.AXUtilities.is_tool_bar = MagicMock()
ax_object = mocks["cthulhu.ax_object"]
ax_object.AXObject.get_role.return_value = Atspi.Role.TABLE_CELL
ax_utilities.AXUtilities.find_ancestor.return_value = None
ax_utilities.AXUtilities.get_table.return_value = MagicMock()
ax_utilities.AXUtilities.is_layout_table.return_value = False
ax_document = mocks["cthulhu.ax_document"]
ax_document.AXDocument.is_pdf.return_value = True
mock_script = MagicMock()
mock_script.utilities.is_text_block_element.return_value = False
mock_script.utilities.has_name_and_action_and_no_useful_children.return_value = False
mock_script.utilities.is_content_editable_with_embedded_objects.return_value = False
mock_obj = MagicMock()
presenter = module.get_presenter()
result = presenter.is_focus_mode_widget(mock_script, mock_obj)
assert result is False
def test_get_in_focus_mode_no_script(self, test_context: CthulhuTestContext) -> None:
"""Test get_in_focus_mode returns False when no active script."""
module, mocks = self._setup_presenter(test_context)
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = None
presenter = module.get_presenter()
result = presenter.get_in_focus_mode()
assert result is False
def test_get_focus_mode_is_sticky_no_script(self, test_context: CthulhuTestContext) -> None:
"""Test get_focus_mode_is_sticky returns False when no active script."""
module, mocks = self._setup_presenter(test_context)
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = None
presenter = module.get_presenter()
result = presenter.get_focus_mode_is_sticky()
assert result is False
def test_get_browse_mode_is_sticky_no_script(self, test_context: CthulhuTestContext) -> None:
"""Test get_browse_mode_is_sticky returns False when no active script."""
module, mocks = self._setup_presenter(test_context)
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = None
presenter = module.get_presenter()
result = presenter.get_browse_mode_is_sticky()
assert result is False
def test_has_state_for_app(self, test_context: CthulhuTestContext) -> None:
"""Test has_state_for_app returns correct value."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
presenter = module.get_presenter()
assert presenter.has_state_for_app(mock_app) is False
presenter._app_states[hash(mock_app)] = module._AppModeState()
assert presenter.has_state_for_app(mock_app) is True
def test_update_mode_if_needed_within_doc(self, test_context: CthulhuTestContext) -> None:
"""Test update_mode_if_needed when moving within document."""
from unittest.mock import MagicMock, patch
module, mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_doc = MagicMock()
mock_script.utilities.get_top_level_document_for_object.return_value = mock_doc
mock_script.utilities.in_document_content.return_value = True
mock_script.utilities.get_caret_context.return_value = (MagicMock(), 0)
caret_nav = mocks["cthulhu.caret_navigator"]
nav_mock = caret_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
caret_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
struct_nav = mocks["cthulhu.structural_navigator"]
nav_mock = struct_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
struct_nav.get_navigator.return_value.last_command_prevents_focus_mode.return_value = False
table_nav = mocks["cthulhu.table_navigator"]
nav_mock = table_nav.get_navigator.return_value
nav_mock.last_input_event_was_navigation_command.return_value = False
focus_manager = mocks["cthulhu.focus_manager"]
focus_manager.get_manager.return_value.in_say_all.return_value = False
script_manager = mocks["cthulhu.script_manager"]
script_manager.get_manager.return_value.get_active_script.return_value = mock_script
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=False,
focus_mode_is_sticky=False,
browse_mode_is_sticky=False,
)
with patch.object(presenter, "is_focus_mode_widget", return_value=False):
result = presenter.update_mode_if_needed(mock_script, MagicMock(), MagicMock())
assert result is True
def test_update_mode_if_needed_sticky_within_doc(self, test_context: CthulhuTestContext) -> None:
"""Test update_mode_if_needed within doc with sticky mode returns False."""
from unittest.mock import MagicMock
module, _mocks = self._setup_presenter(test_context)
mock_app = MagicMock()
mock_script = MagicMock()
mock_script.app = mock_app
mock_doc = MagicMock()
mock_script.utilities.get_top_level_document_for_object.return_value = mock_doc
presenter = module.get_presenter()
presenter._app_states[hash(mock_app)] = module._AppModeState(
in_focus_mode=True,
focus_mode_is_sticky=True,
browse_mode_is_sticky=False,
)
result = presenter.update_mode_if_needed(mock_script, MagicMock(), MagicMock())
assert result is False