Merge branch 'testing' into wine-access
This commit is contained in:
@@ -3441,6 +3441,20 @@ class Script(script.Script):
|
||||
|
||||
return requested
|
||||
|
||||
def should_interrupt_for_mode_announcement(
|
||||
self,
|
||||
requested: bool,
|
||||
already_handled: bool = False,
|
||||
) -> bool:
|
||||
"""Returns whether a mode announcement should interrupt prior output."""
|
||||
|
||||
if requested and already_handled:
|
||||
msg = "DEFAULT: Mode announcement interruption already handled by input dispatch"
|
||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||
return False
|
||||
|
||||
return requested
|
||||
|
||||
def presentKeyboardEvent(self, event):
|
||||
"""Convenience method to present the KeyboardEvent event. Returns True
|
||||
if we fully present the event; False otherwise."""
|
||||
|
||||
@@ -1523,7 +1523,11 @@ class Script(default.Script):
|
||||
self.utilities.setCaretContext(AXObject.get_parent(parent), -1)
|
||||
if not self._loadingDocumentContent:
|
||||
if inputEvent is not None:
|
||||
self.presentMessage(messages.MODE_BROWSE, interrupt=True)
|
||||
interrupt = self.should_interrupt_for_mode_announcement(
|
||||
True,
|
||||
already_handled=True,
|
||||
)
|
||||
self.presentMessage(messages.MODE_BROWSE, interrupt=interrupt)
|
||||
else:
|
||||
self.presentMessage(messages.MODE_BROWSE)
|
||||
if not self._shouldSuppressBrowseModeSound(obj, inputEvent):
|
||||
@@ -1536,7 +1540,11 @@ class Script(default.Script):
|
||||
self.utilities.grabFocus(obj)
|
||||
|
||||
if inputEvent is not None:
|
||||
self.presentMessage(messages.MODE_FOCUS, interrupt=True)
|
||||
interrupt = self.should_interrupt_for_mode_announcement(
|
||||
True,
|
||||
already_handled=True,
|
||||
)
|
||||
self.presentMessage(messages.MODE_FOCUS, interrupt=interrupt)
|
||||
else:
|
||||
self.presentMessage(messages.MODE_FOCUS)
|
||||
sound_theme_manager.getManager().playFocusModeSound()
|
||||
|
||||
@@ -493,7 +493,7 @@ structNavTriggersFocusMode = False
|
||||
caretNavTriggersFocusMode = False
|
||||
nativeNavTriggersFocusMode = True
|
||||
|
||||
layoutMode = True
|
||||
layoutMode = False
|
||||
|
||||
rewindAndFastForwardInSayAll = False
|
||||
structNavInSayAll = False
|
||||
|
||||
@@ -269,13 +269,33 @@ class WebPresentationModeSpeechRegressionTests(unittest.TestCase):
|
||||
self.assertFalse(testScript._browseModeIsSticky)
|
||||
testScript.refreshKeyGrabs.assert_called_once_with()
|
||||
|
||||
def test_manual_presentation_mode_toggle_still_interrupts(self):
|
||||
def test_manual_focus_mode_announcement_does_not_interrupt_after_keyboard_dispatch(self):
|
||||
testScript = self._make_script(inFocusMode=False)
|
||||
|
||||
with mock.patch.object(web_script.sound_theme_manager, "getManager", return_value=mock.Mock()):
|
||||
web_script.Script.togglePresentationMode(testScript, object(), "document")
|
||||
|
||||
testScript.presentMessage.assert_called_once_with(messages.MODE_FOCUS, interrupt=True)
|
||||
testScript.presentMessage.assert_called_once_with(messages.MODE_FOCUS, interrupt=False)
|
||||
|
||||
def test_manual_browse_mode_announcement_does_not_interrupt_after_keyboard_dispatch(self):
|
||||
testScript = self._make_script(inFocusMode=True)
|
||||
|
||||
with (
|
||||
mock.patch.object(web_script.AXObject, "get_parent", return_value=None),
|
||||
mock.patch.object(web_script.AXUtilities, "is_list_box", return_value=False),
|
||||
mock.patch.object(web_script.AXUtilities, "is_menu", return_value=False),
|
||||
mock.patch.object(web_script.sound_theme_manager, "getManager", return_value=mock.Mock()),
|
||||
):
|
||||
web_script.Script.togglePresentationMode(testScript, object(), "document")
|
||||
|
||||
testScript.presentMessage.assert_called_once_with(messages.MODE_BROWSE, interrupt=False)
|
||||
|
||||
def test_non_keyboard_mode_announcement_keeps_interrupt_request(self):
|
||||
testScript = self._make_script(inFocusMode=False)
|
||||
|
||||
result = web_script.Script.should_interrupt_for_mode_announcement(testScript, True)
|
||||
|
||||
self.assertTrue(result)
|
||||
|
||||
|
||||
class WebObjectPresentationInterruptionRegressionTests(unittest.TestCase):
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("Atspi", "2.0")
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from cthulhu import settings
|
||||
from cthulhu import settings_manager
|
||||
from cthulhu.scripts.web import script_utilities as web_script_utilities
|
||||
|
||||
|
||||
class WebLayoutModeSettingsRegressionTests(unittest.TestCase):
|
||||
def test_layout_mode_defaults_to_object_mode(self):
|
||||
self.assertFalse(settings.layoutMode)
|
||||
|
||||
def test_explicit_persisted_layout_mode_true_is_preserved(self):
|
||||
with tempfile.TemporaryDirectory() as tempDir:
|
||||
with mock.patch.object(settings, "layoutMode", False):
|
||||
manager = settings_manager.SettingsManager(mock.Mock())
|
||||
manager.activate(prefsDir=tempDir)
|
||||
settingsPath = Path(tempDir, "user-settings.toml")
|
||||
settingsText = settingsPath.read_text(encoding="utf-8")
|
||||
settingsPath.write_text(
|
||||
settingsText.replace("layoutMode = false", "layoutMode = true"),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
reloadedManager = settings_manager.SettingsManager(mock.Mock())
|
||||
reloadedManager.activate(prefsDir=tempDir)
|
||||
|
||||
self.assertTrue(reloadedManager.getSetting("layoutMode"))
|
||||
|
||||
def test_application_specific_layout_mode_true_is_preserved(self):
|
||||
with tempfile.TemporaryDirectory() as tempDir:
|
||||
with mock.patch.object(settings, "layoutMode", False):
|
||||
manager = settings_manager.SettingsManager(mock.Mock())
|
||||
manager.activate(prefsDir=tempDir)
|
||||
manager._backend.saveAppSettings(
|
||||
"Browser",
|
||||
manager.profile,
|
||||
{"layoutMode": True},
|
||||
{},
|
||||
{},
|
||||
)
|
||||
script = mock.Mock()
|
||||
script.app = object()
|
||||
script.getKeyBindings.return_value = mock.Mock()
|
||||
|
||||
with mock.patch.object(
|
||||
settings_manager.AXObject,
|
||||
"get_name",
|
||||
return_value="Browser",
|
||||
):
|
||||
manager.loadAppSettings(script)
|
||||
|
||||
self.assertTrue(manager.getSetting("layoutMode"))
|
||||
|
||||
|
||||
class WebLayoutModeLineRegressionTests(unittest.TestCase):
|
||||
def _make_utilities(self):
|
||||
obj = object()
|
||||
contents = [[obj, 0, 4, "Text"]]
|
||||
utilities = web_script_utilities.Utilities.__new__(
|
||||
web_script_utilities.Utilities
|
||||
)
|
||||
utilities._script = mock.Mock()
|
||||
utilities._script.inFocusMode.return_value = False
|
||||
utilities._currentLineContents = []
|
||||
utilities._debugContentsInfo = mock.Mock()
|
||||
utilities.findObjectInContents = mock.Mock(return_value=-1)
|
||||
utilities.treatAsEndOfLine = mock.Mock(return_value=False)
|
||||
utilities.getExtents = mock.Mock(return_value=[0, 0, 10, 10])
|
||||
utilities.isInlineListDescendant = mock.Mock(return_value=False)
|
||||
utilities._getContentsForObj = mock.Mock(return_value=contents)
|
||||
utilities.isLink = mock.Mock(return_value=False)
|
||||
utilities.isMath = mock.Mock(return_value=False)
|
||||
utilities.isMathTopLevel = mock.Mock(return_value=False)
|
||||
utilities.getDocumentForObject = mock.Mock(return_value=object())
|
||||
utilities.findPreviousCaretInOrder = mock.Mock(return_value=(None, -1))
|
||||
utilities.findNextCaretInOrder = mock.Mock(return_value=(None, -1))
|
||||
utilities.isContentEditableWithEmbeddedObjects = mock.Mock(return_value=False)
|
||||
return utilities, obj, contents
|
||||
|
||||
def _get_line_for_setting(self, layoutMode):
|
||||
utilities, obj, contents = self._make_utilities()
|
||||
settingsManager = mock.Mock()
|
||||
settingsManager.getSetting.return_value = layoutMode
|
||||
|
||||
with (
|
||||
mock.patch.object(
|
||||
web_script_utilities.cthulhu.cthulhuApp,
|
||||
"settingsManager",
|
||||
settingsManager,
|
||||
),
|
||||
mock.patch.object(
|
||||
web_script_utilities.AXObject,
|
||||
"is_dead",
|
||||
return_value=False,
|
||||
),
|
||||
mock.patch.object(
|
||||
web_script_utilities.AXObject,
|
||||
"find_ancestor",
|
||||
return_value=None,
|
||||
),
|
||||
mock.patch.object(
|
||||
web_script_utilities.AXUtilities,
|
||||
"is_tool_bar",
|
||||
return_value=False,
|
||||
),
|
||||
mock.patch.object(
|
||||
web_script_utilities.AXUtilities,
|
||||
"is_menu_bar",
|
||||
return_value=False,
|
||||
),
|
||||
mock.patch.object(
|
||||
web_script_utilities.AXUtilities,
|
||||
"is_table_row",
|
||||
return_value=False,
|
||||
),
|
||||
):
|
||||
result = web_script_utilities.Utilities._getLineContentsAtOffset(
|
||||
utilities,
|
||||
obj,
|
||||
0,
|
||||
layoutMode=None,
|
||||
useCache=False,
|
||||
)
|
||||
|
||||
return utilities, obj, contents, result
|
||||
|
||||
def test_unset_profile_setting_uses_object_mode_for_web_line(self):
|
||||
utilities, obj, contents, result = self._get_line_for_setting(False)
|
||||
|
||||
self.assertEqual(result, contents)
|
||||
utilities.getDocumentForObject.assert_not_called()
|
||||
utilities._debugContentsInfo.assert_called_once_with(
|
||||
obj,
|
||||
0,
|
||||
contents,
|
||||
"Line (not layout mode)",
|
||||
)
|
||||
|
||||
def test_explicit_layout_mode_true_uses_visual_web_line(self):
|
||||
utilities, obj, contents, result = self._get_line_for_setting(True)
|
||||
|
||||
self.assertEqual(result, contents)
|
||||
utilities.getDocumentForObject.assert_called_once_with(obj)
|
||||
utilities._debugContentsInfo.assert_called_once_with(
|
||||
obj,
|
||||
0,
|
||||
contents,
|
||||
"Line (layout mode)",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user