Thread RP_DEBUG-driven logging through input, detection, rendering, and pager decisions so CLI behavior is inspectable without polluting stdout. Add focused coverage for debug wiring, env parsing, and stderr-only output.
189 lines
7.3 KiB
Python
189 lines
7.3 KiB
Python
"""Tests for pager integration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import signal
|
|
import subprocess
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from rp.pager import MousePager, _mouse_capable_less
|
|
|
|
|
|
class TestMouseCapableLess:
|
|
"""Tests for _mouse_capable_less()."""
|
|
|
|
def test_returns_path_when_less_supports_mouse(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value="/usr/bin/less"):
|
|
mock_result = MagicMock()
|
|
mock_result.stdout = "less 551 (POSIX regular expressions)"
|
|
mock_result.stderr = ""
|
|
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
assert _mouse_capable_less() == "/usr/bin/less"
|
|
|
|
def test_returns_none_when_less_not_found(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value=None):
|
|
assert _mouse_capable_less() is None
|
|
|
|
def test_logs_less_not_found(self) -> None:
|
|
messages: list[str] = []
|
|
|
|
with patch("rp.pager.shutil.which", return_value=None):
|
|
assert _mouse_capable_less(messages.append) is None
|
|
|
|
assert messages == ["pager: 'less' was not found"]
|
|
|
|
def test_returns_none_when_less_too_old(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value="/usr/bin/less"):
|
|
mock_result = MagicMock()
|
|
mock_result.stdout = "less 444"
|
|
mock_result.stderr = ""
|
|
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
assert _mouse_capable_less() is None
|
|
|
|
def test_returns_path_when_version_is_in_stderr(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value="/usr/bin/less"):
|
|
mock_result = MagicMock()
|
|
mock_result.stdout = ""
|
|
mock_result.stderr = "less 600"
|
|
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
assert _mouse_capable_less() == "/usr/bin/less"
|
|
|
|
def test_returns_none_on_timeout(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value="/usr/bin/less"):
|
|
with patch(
|
|
"rp.pager.subprocess.run",
|
|
side_effect=subprocess.TimeoutExpired(cmd="less", timeout=5),
|
|
):
|
|
assert _mouse_capable_less() is None
|
|
|
|
def test_returns_none_on_os_error(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value="/usr/bin/less"):
|
|
with patch("rp.pager.subprocess.run", side_effect=OSError("nope")):
|
|
assert _mouse_capable_less() is None
|
|
|
|
def test_returns_none_when_version_not_parseable(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value="/usr/bin/less"):
|
|
mock_result = MagicMock()
|
|
mock_result.stdout = "some random output"
|
|
mock_result.stderr = ""
|
|
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
assert _mouse_capable_less() is None
|
|
|
|
def test_boundary_version_543(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value="/usr/bin/less"):
|
|
mock_result = MagicMock()
|
|
mock_result.stdout = "less 543"
|
|
mock_result.stderr = ""
|
|
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
assert _mouse_capable_less() == "/usr/bin/less"
|
|
|
|
def test_boundary_version_542(self) -> None:
|
|
with patch("rp.pager.shutil.which", return_value="/usr/bin/less"):
|
|
mock_result = MagicMock()
|
|
mock_result.stdout = "less 542"
|
|
mock_result.stderr = ""
|
|
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
assert _mouse_capable_less() is None
|
|
|
|
|
|
class TestMousePager:
|
|
"""Tests for MousePager.show()."""
|
|
|
|
def test_falls_back_to_system_pager_when_no_less(self) -> None:
|
|
pager = MousePager()
|
|
|
|
with patch("rp.pager._mouse_capable_less", return_value=None):
|
|
with patch("rp.pager.SystemPager") as mock_system_pager:
|
|
mock_instance = MagicMock()
|
|
mock_system_pager.return_value = mock_instance
|
|
|
|
pager.show("content")
|
|
|
|
mock_instance.show.assert_called_once_with("content")
|
|
|
|
def test_logs_system_pager_fallback(self) -> None:
|
|
messages: list[str] = []
|
|
pager = MousePager(debug=messages.append)
|
|
|
|
with patch("rp.pager._mouse_capable_less", return_value=None):
|
|
with patch("rp.pager.SystemPager") as mock_system_pager:
|
|
mock_instance = MagicMock()
|
|
mock_system_pager.return_value = mock_instance
|
|
|
|
pager.show("content")
|
|
|
|
assert messages == ["pager: falling back to Rich's SystemPager"]
|
|
|
|
def test_uses_less_when_available(self) -> None:
|
|
pager = MousePager()
|
|
mock_result = MagicMock()
|
|
mock_result.returncode = 0
|
|
|
|
with patch("rp.pager._mouse_capable_less", return_value="/usr/bin/less"):
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result) as mock_run:
|
|
pager.show("hello")
|
|
|
|
mock_run.assert_called_once_with(
|
|
["/usr/bin/less", "-R", "--mouse"],
|
|
input="hello",
|
|
text=True,
|
|
)
|
|
|
|
def test_sigint_does_not_trigger_fallback_for_negative_code(self) -> None:
|
|
pager = MousePager()
|
|
mock_result = MagicMock()
|
|
mock_result.returncode = -signal.SIGINT
|
|
|
|
with patch("rp.pager._mouse_capable_less", return_value="/usr/bin/less"):
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
with patch("rp.pager.SystemPager") as mock_system_pager:
|
|
pager.show("content")
|
|
|
|
mock_system_pager.assert_not_called()
|
|
|
|
def test_sigint_does_not_trigger_fallback_for_128_plus_code(self) -> None:
|
|
pager = MousePager()
|
|
mock_result = MagicMock()
|
|
mock_result.returncode = 128 + signal.SIGINT
|
|
|
|
with patch("rp.pager._mouse_capable_less", return_value="/usr/bin/less"):
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
with patch("rp.pager.SystemPager") as mock_system_pager:
|
|
pager.show("content")
|
|
|
|
mock_system_pager.assert_not_called()
|
|
|
|
def test_nonzero_exit_triggers_fallback(self) -> None:
|
|
pager = MousePager()
|
|
mock_result = MagicMock()
|
|
mock_result.returncode = 1
|
|
|
|
with patch("rp.pager._mouse_capable_less", return_value="/usr/bin/less"):
|
|
with patch("rp.pager.subprocess.run", return_value=mock_result):
|
|
with patch("rp.pager.SystemPager") as mock_system_pager:
|
|
mock_instance = MagicMock()
|
|
mock_system_pager.return_value = mock_instance
|
|
|
|
pager.show("content")
|
|
|
|
mock_instance.show.assert_called_once_with("content")
|
|
|
|
def test_oserror_triggers_fallback(self) -> None:
|
|
pager = MousePager()
|
|
|
|
with patch("rp.pager._mouse_capable_less", return_value="/usr/bin/less"):
|
|
with patch("rp.pager.subprocess.run", side_effect=OSError("fail")):
|
|
with patch("rp.pager.SystemPager") as mock_system_pager:
|
|
mock_instance = MagicMock()
|
|
mock_system_pager.return_value = mock_instance
|
|
|
|
pager.show("content")
|
|
|
|
mock_instance.show.assert_called_once_with("content")
|