Files
fenrir/tests/unit/test_pty_terminal_sequences.py
T
2026-05-12 17:39:56 -04:00

232 lines
6.8 KiB
Python

import threading
import time
from unittest.mock import Mock
import pytest
from fenrirscreenreader.core.eventData import FenrirEventType
from fenrirscreenreader.screenDriver.ptyDriver import PTYConstants
from fenrirscreenreader.screenDriver.ptyDriver import Terminal
from fenrirscreenreader.screenDriver.ptyDriver import driver as PtyDriver
class DummyProcessInput:
def __init__(self):
self.data = []
def write(self, data):
self.data.append(data)
@pytest.mark.unit
def test_csi_sequences_with_intermediate_characters_do_not_render_final_byte():
terminal = Terminal(10, 3, DummyProcessInput())
terminal.feed(b"\x1b[2026$p\x1b[2048$pX")
screen = terminal.get_screen_content()
assert screen["text"].splitlines()[0] == "X "
assert "p" not in screen["text"]
@pytest.mark.unit
def test_private_sgr_sequence_from_fullscreen_apps_does_not_crash():
terminal = Terminal(10, 3, DummyProcessInput())
terminal.feed(b"\x1b[?25;7mX")
screen = terminal.get_screen_content()
assert screen["text"].splitlines()[0] == "X "
@pytest.mark.unit
def test_optional_float_setting_uses_default_when_missing():
settings_manager = type(
"SettingsManager",
(),
{"get_setting": lambda self, section, setting: ""},
)()
pty_driver = PtyDriver()
assert (
pty_driver._get_optional_float_setting(
settings_manager,
"screen",
"ptyOutputTimeout",
PTYConstants.OUTPUT_READ_TIMEOUT,
)
== PTYConstants.OUTPUT_READ_TIMEOUT
)
@pytest.mark.unit
def test_pty_stdin_input_interrupts_output_when_all_keys_interrupt_enabled():
pty_driver = PtyDriver()
settings_manager = Mock()
settings_manager.get_setting_as_bool.return_value = True
settings_manager.get_setting.return_value = ""
output_manager = Mock()
pty_driver.env = {
"runtime": {
"SettingsManager": settings_manager,
"OutputManager": output_manager,
}
}
pty_driver.interrupt_output_on_stdin_input(b"a")
pty_driver.stdin_interrupt_thread.join(timeout=1.0)
output_manager.interrupt_output.assert_called_once_with()
@pytest.mark.unit
def test_pty_stdin_input_interrupt_does_not_block_input_injection():
pty_driver = PtyDriver()
settings_manager = Mock()
settings_manager.get_setting_as_bool.return_value = True
settings_manager.get_setting.return_value = ""
interrupt_started = threading.Event()
release_interrupt = threading.Event()
def slow_interrupt():
interrupt_started.set()
release_interrupt.wait(timeout=1.0)
output_manager = Mock(interrupt_output=Mock(side_effect=slow_interrupt))
pty_driver.env = {
"input": {"curr_input": []},
"runtime": {
"SettingsManager": settings_manager,
"OutputManager": output_manager,
"DebugManager": Mock(write_debug_out=Mock()),
},
}
pty_driver.inject_text_to_screen = Mock()
start_time = time.monotonic()
pty_driver.handle_stdin_input(b"a", Mock())
elapsed = time.monotonic() - start_time
try:
assert interrupt_started.wait(timeout=0.2)
assert elapsed < 0.2
pty_driver.inject_text_to_screen.assert_called_once_with(b"a")
finally:
release_interrupt.set()
pty_driver.stdin_interrupt_thread.join(timeout=1.0)
@pytest.mark.unit
def test_pty_raw_tab_records_recent_tab_keypress():
pty_driver = PtyDriver()
settings_manager = Mock()
settings_manager.get_setting_as_bool.return_value = False
input_manager = Mock()
pty_driver.env = {
"input": {"curr_input": []},
"runtime": {
"DebugManager": Mock(write_debug_out=Mock()),
"InputManager": input_manager,
"SettingsManager": settings_manager,
},
}
pty_driver.inject_text_to_screen = Mock()
pty_driver.handle_stdin_input(b"\t", Mock())
input_manager.record_unmanaged_keypress.assert_called_once_with("KEY_TAB")
pty_driver.inject_text_to_screen.assert_called_once_with(b"\t")
@pytest.mark.unit
def test_pty_plain_stdin_does_not_record_tab_keypress():
pty_driver = PtyDriver()
settings_manager = Mock()
settings_manager.get_setting_as_bool.return_value = False
input_manager = Mock()
pty_driver.env = {
"input": {"curr_input": []},
"runtime": {
"DebugManager": Mock(write_debug_out=Mock()),
"InputManager": input_manager,
"SettingsManager": settings_manager,
},
}
pty_driver.inject_text_to_screen = Mock()
pty_driver.handle_stdin_input(b"a", Mock())
input_manager.record_unmanaged_keypress.assert_not_called()
pty_driver.inject_text_to_screen.assert_called_once_with(b"a")
@pytest.mark.unit
def test_pty_stdin_input_honors_interrupt_disabled():
pty_driver = PtyDriver()
settings_manager = Mock()
settings_manager.get_setting_as_bool.return_value = False
output_manager = Mock()
pty_driver.env = {
"runtime": {
"SettingsManager": settings_manager,
"OutputManager": output_manager,
}
}
pty_driver.interrupt_output_on_stdin_input(b"a")
output_manager.interrupt_output.assert_not_called()
@pytest.mark.unit
def test_pty_stdin_input_leaves_filtered_interrupts_to_key_events():
pty_driver = PtyDriver()
settings_manager = Mock()
settings_manager.get_setting_as_bool.return_value = True
settings_manager.get_setting.return_value = "KEY_ENTER"
output_manager = Mock()
pty_driver.env = {
"runtime": {
"SettingsManager": settings_manager,
"OutputManager": output_manager,
}
}
pty_driver.interrupt_output_on_stdin_input(b"a")
output_manager.interrupt_output.assert_not_called()
@pytest.mark.unit
def test_pty_backspace_with_fenrir_key_synthesizes_shortcut_events():
pty_driver = PtyDriver()
event_queue = Mock()
pty_driver.env = {
"input": {"curr_input": ["KEY_FENRIR"]},
}
handled = pty_driver.synthesize_backspace_shortcut(b"\x7f", event_queue)
assert handled is True
assert event_queue.put.call_count == 2
first_event = event_queue.put.call_args_list[0].args[0]
second_event = event_queue.put.call_args_list[1].args[0]
assert first_event["Type"] == FenrirEventType.keyboard_input
assert first_event["data"]["event_name"] == "KEY_BACKSPACE"
assert first_event["data"]["event_state"] == 1
assert second_event["data"]["event_state"] == 0
@pytest.mark.unit
def test_pty_plain_backspace_is_not_synthesized():
pty_driver = PtyDriver()
event_queue = Mock()
pty_driver.env = {
"input": {"curr_input": []},
}
handled = pty_driver.synthesize_backspace_shortcut(b"\x7f", event_queue)
assert handled is False
event_queue.put.assert_not_called()