Updated tests.

This commit is contained in:
Storm Dragon
2026-07-24 19:45:47 -04:00
parent 17f196e530
commit e3427af1ad
+217 -1
View File
@@ -11,7 +11,7 @@ gi.require_version("Atspi", "2.0")
from gi.repository import Atspi from gi.repository import Atspi
from cthulhu import cthulhu_state from cthulhu import cthulhu_state
from cthulhu.ax_utilities_event import AXUtilitiesEvent from cthulhu.ax_utilities_event import AXUtilitiesEvent, TextEventReason
from cthulhu.scripts import default from cthulhu.scripts import default
from cthulhu.scripts.toolkits.Chromium import script as chromium_script from cthulhu.scripts.toolkits.Chromium import script as chromium_script
from cthulhu.scripts.toolkits.Gecko import script as gecko_script from cthulhu.scripts.toolkits.Gecko import script as gecko_script
@@ -187,6 +187,222 @@ class ChromiumTabFocusSequenceTests(unittest.TestCase):
self._assert_tab_caret_focused_sequence_presents_once(radio) self._assert_tab_caret_focused_sequence_presents_once(radio)
class FocusedChangeInteractionSequenceTests(unittest.TestCase):
"""Ordered ownership contracts around focused-change events."""
@staticmethod
def _make_script(
document: object,
caretContext: FakeAccessible,
) -> chromium_script.Script:
testScript = chromium_script.Script.__new__(chromium_script.Script)
testScript._lastCommandWasCaretNav = False
testScript._lastCommandWasStructNav = False
testScript._lastCommandWasMouseButton = False
testScript._browseModeIsSticky = False
testScript._clearSyntheticWebSelection = mock.Mock()
testScript.refreshKeyGrabs = mock.Mock()
testScript.utilities = mock.Mock()
testScript.utilities.isDocument.return_value = False
testScript.utilities.isStaticTextLeaf.return_value = False
testScript.utilities.isRedundantAutocompleteEvent.return_value = False
testScript.utilities.isZombie.return_value = False
testScript.utilities.getTopLevelDocumentForObject.return_value = document
testScript.utilities.getDocumentForObject.return_value = document
testScript.utilities.getCaretContext.return_value = (caretContext, 0)
testScript.utilities.lastInputEventWasCaretNavWithSelection.return_value = False
testScript.utilities.lastInputEventWasCharNav.return_value = False
testScript.utilities.inFindContainer.return_value = False
testScript.utilities.eventIsFromLocusOfFocusDocument.return_value = True
testScript.utilities.isWebAppDescendant.return_value = False
testScript.utilities.handleEventFromContextReplicant.return_value = False
testScript.utilities.lastInputEventWasPageNav.return_value = False
testScript.utilities.isAnchor.return_value = False
testScript.utilities.isLink.return_value = False
testScript.utilities.isChildOfCurrentFragment.return_value = False
testScript.utilities.documentFragment.return_value = ""
return testScript
def _assert_navigation_command_owns_caret_and_focus_pair(
self,
*,
caretNavigation: bool,
structuralNavigation: bool,
) -> None:
document = object()
target = FakeAccessible(Atspi.Role.PARAGRAPH)
testScript = self._make_script(document, target)
testScript._lastCommandWasCaretNav = caretNavigation
testScript._lastCommandWasStructNav = structuralNavigation
events = [
FakeEvent("object:text-caret-moved", target, detail1=4),
FakeEvent("object:state-changed:focused", target, detail1=1),
]
presentations = ["navigation-command"]
with (
mock.patch.object(cthulhu_state, "locusOfFocus", target),
mock.patch.object(
AXUtilitiesEvent,
"get_text_event_reason",
return_value=TextEventReason.NAVIGATION_BY_CHARACTER,
),
mock.patch.object(web_script.AXUtilities, "is_editable", return_value=False),
mock.patch.object(web_script.AXUtilities, "is_dialog_or_alert", return_value=False),
mock.patch.object(web_script.AXUtilities, "is_focusable", return_value=True),
mock.patch.object(web_script.AXUtilities, "is_focused", return_value=True),
mock.patch.object(web_script.AXUtilities, "is_document", return_value=False),
mock.patch.object(
default.Script,
"onCaretMoved",
side_effect=lambda _script, _event: presentations.append("caret-event"),
) as defaultCaretHandler,
mock.patch.object(
default.Script,
"onFocusedChanged",
side_effect=lambda _script, _event: presentations.append("focus-event"),
) as defaultFocusHandler,
):
WebEventSequence(testScript).run(events)
self.assertEqual(presentations, ["navigation-command"])
defaultCaretHandler.assert_not_called()
defaultFocusHandler.assert_not_called()
def test_caret_navigation_owns_following_caret_and_focus_events(self) -> None:
self._assert_navigation_command_owns_caret_and_focus_pair(
caretNavigation=True,
structuralNavigation=False,
)
def test_structural_navigation_owns_following_caret_and_focus_events(self) -> None:
self._assert_navigation_command_owns_caret_and_focus_pair(
caretNavigation=False,
structuralNavigation=True,
)
def test_tab_clears_navigation_ownership_and_real_focus_still_presents(self) -> None:
document = object()
oldTarget = FakeAccessible(Atspi.Role.PARAGRAPH)
newTarget = FakeAccessible(Atspi.Role.ENTRY, editable=True)
testScript = self._make_script(document, oldTarget)
testScript._lastCommandWasCaretNav = True
ignoredFocus = FakeEvent(
"object:state-changed:focused",
oldTarget,
detail1=1,
)
realFocus = FakeEvent(
"object:state-changed:focused",
newTarget,
detail1=1,
)
tabEvent = mock.Mock(event_string="Tab")
tabEvent.is_modifier_key.return_value = False
presentations: list[FakeAccessible] = []
with (
mock.patch.object(cthulhu_state, "locusOfFocus", oldTarget),
mock.patch.object(
web_script.AXUtilities,
"is_editable",
side_effect=lambda obj: obj.editable,
),
mock.patch.object(web_script.AXUtilities, "is_dialog_or_alert", return_value=False),
mock.patch.object(web_script.AXUtilities, "is_focusable", return_value=True),
mock.patch.object(web_script.AXUtilities, "is_focused", return_value=True),
mock.patch.object(web_script.AXUtilities, "is_document", return_value=False),
mock.patch.object(default.Script, "shouldConsumeKeyboardEvent", return_value=False),
mock.patch.object(
default.Script,
"onFocusedChanged",
side_effect=lambda _script, event: presentations.append(event.source),
) as defaultFocusHandler,
):
WebEventSequence(testScript).run([ignoredFocus])
web_script.Script.shouldConsumeKeyboardEvent(testScript, tabEvent, None)
WebEventSequence(testScript).run([realFocus])
self.assertEqual(presentations, [newTarget])
self.assertFalse(testScript._lastCommandWasCaretNav)
self.assertFalse(testScript._lastCommandWasStructNav)
defaultFocusHandler.assert_called_once_with(testScript, realFocus)
def _assert_document_focus_uses_recovered_context_once(
self,
*,
pageNavigation: bool,
documentFragment: str,
) -> None:
document = FakeAccessible(Atspi.Role.DOCUMENT_WEB)
oldFocus = FakeAccessible(Atspi.Role.FRAME)
context = FakeAccessible(Atspi.Role.LINK)
testScript = self._make_script(document, context)
testScript.utilities.getDocumentForObject.side_effect = (
lambda obj: document if obj is document else None
)
testScript.utilities.getCaretContext.return_value = (None, -1)
testScript.utilities.searchForCaretContext.return_value = (context, 6)
testScript.utilities.lastInputEventWasPageNav.return_value = pageNavigation
testScript.utilities.isLink.side_effect = lambda obj: obj is context
testScript.utilities.documentFragment.return_value = documentFragment
event = FakeEvent("object:state-changed:focused", document, detail1=1)
presentations: list[FakeAccessible] = []
def set_focus(
_event: FakeEvent,
obj: FakeAccessible,
notifyScript: bool = True,
) -> None:
if notifyScript:
presentations.append(obj)
with (
mock.patch.object(cthulhu_state, "locusOfFocus", oldFocus),
mock.patch.object(web_script.AXUtilities, "is_editable", return_value=False),
mock.patch.object(web_script.AXUtilities, "is_dialog_or_alert", return_value=False),
mock.patch.object(web_script.AXUtilities, "is_focusable", return_value=True),
mock.patch.object(
web_script.AXUtilities,
"is_focused",
side_effect=lambda obj: obj is document,
),
mock.patch.object(
web_script.AXUtilities,
"is_document",
side_effect=lambda obj: obj is document,
),
mock.patch.object(web_script.AXObject, "clear_cache"),
mock.patch.object(web_script.cthulhu, "setLocusOfFocus", side_effect=set_focus) as setFocus,
mock.patch.object(default.Script, "onFocusedChanged") as defaultFocusHandler,
):
WebEventSequence(testScript).run([event])
self.assertEqual(presentations, [context])
self.assertEqual(
setFocus.call_args_list,
[mock.call(event, context, False), mock.call(event, context)],
)
testScript.utilities.setCaretContext.assert_has_calls(
[mock.call(context, 6), mock.call(context, 6)]
if pageNavigation
else [mock.call(context, 6)]
)
defaultFocusHandler.assert_not_called()
def test_page_navigation_focus_uses_recovered_caret_context_once(self) -> None:
self._assert_document_focus_uses_recovered_context_once(
pageNavigation=True,
documentFragment="",
)
def test_page_fragment_focus_uses_recovered_caret_context_once(self) -> None:
self._assert_document_focus_uses_recovered_context_once(
pageNavigation=False,
documentFragment="#details",
)
class ChromiumNativeContainerSequenceTests(unittest.TestCase): class ChromiumNativeContainerSequenceTests(unittest.TestCase):
"""Current routing contracts for native containers in Chromium content.""" """Current routing contracts for native containers in Chromium content."""