Files
hate_crack/tests/test_menu.py
2026-03-16 13:08:59 -04:00

117 lines
3.9 KiB
Python

from unittest.mock import MagicMock, patch
from hate_crack.menu import (
_arrow_menu,
_numbered_menu,
_use_arrow_menu,
interactive_menu,
)
SAMPLE_ITEMS = [
("1", "Quick Crack"),
("2", "Brute Force"),
("99", "Quit"),
]
class TestUseArrowMenu:
def test_falls_back_without_library(self, monkeypatch):
import hate_crack.menu as mod
monkeypatch.setattr(mod, "_HAS_TERM_MENU", False)
monkeypatch.delenv("HATE_CRACK_PLAIN_MENU", raising=False)
assert _use_arrow_menu() is False
def test_falls_back_on_non_tty(self, monkeypatch):
import hate_crack.menu as mod
monkeypatch.setattr(mod, "_HAS_TERM_MENU", True)
monkeypatch.delenv("HATE_CRACK_PLAIN_MENU", raising=False)
monkeypatch.setattr("sys.stdout.isatty", lambda: False)
assert _use_arrow_menu() is False
def test_falls_back_with_env_var(self, monkeypatch):
import hate_crack.menu as mod
monkeypatch.setattr(mod, "_HAS_TERM_MENU", True)
monkeypatch.setenv("HATE_CRACK_PLAIN_MENU", "1")
assert _use_arrow_menu() is False
def test_enabled_when_all_conditions_met(self, monkeypatch):
import hate_crack.menu as mod
monkeypatch.setattr(mod, "_HAS_TERM_MENU", True)
monkeypatch.delenv("HATE_CRACK_PLAIN_MENU", raising=False)
monkeypatch.setattr("sys.stdout.isatty", lambda: True)
assert _use_arrow_menu() is True
class TestNumberedMenu:
def test_returns_correct_key(self, monkeypatch):
monkeypatch.setattr("builtins.input", lambda _: "2")
result = _numbered_menu(SAMPLE_ITEMS, "\nSelect: ")
assert result == "2"
def test_prints_all_labels(self, monkeypatch, capsys):
monkeypatch.setattr("builtins.input", lambda _: "1")
_numbered_menu(SAMPLE_ITEMS, "\nSelect: ")
captured = capsys.readouterr().out
for key, label in SAMPLE_ITEMS:
assert f"({key}) {label}" in captured
def test_returns_none_on_empty_input(self, monkeypatch):
monkeypatch.setattr("builtins.input", lambda _: "")
result = _numbered_menu(SAMPLE_ITEMS, "\nSelect: ")
assert result is None
class TestArrowMenu:
def test_returns_correct_key(self):
mock_menu_instance = MagicMock()
mock_menu_instance.show.return_value = 1 # index 1 -> key "2"
with patch(
"hate_crack.menu.TerminalMenu",
create=True,
return_value=mock_menu_instance,
):
result = _arrow_menu(SAMPLE_ITEMS, "Title")
assert result == "2"
def test_returns_none_on_escape(self):
mock_menu_instance = MagicMock()
mock_menu_instance.show.return_value = None
with patch(
"hate_crack.menu.TerminalMenu",
create=True,
return_value=mock_menu_instance,
):
result = _arrow_menu(SAMPLE_ITEMS, "Title")
assert result is None
class TestInteractiveMenu:
def test_uses_numbered_when_no_tty(self, monkeypatch):
import hate_crack.menu as mod
monkeypatch.setattr(mod, "_HAS_TERM_MENU", False)
monkeypatch.delenv("HATE_CRACK_PLAIN_MENU", raising=False)
monkeypatch.setattr("builtins.input", lambda _: "99")
result = interactive_menu(SAMPLE_ITEMS)
assert result == "99"
def test_uses_arrow_when_available(self, monkeypatch):
import hate_crack.menu as mod
monkeypatch.setattr(mod, "_HAS_TERM_MENU", True)
monkeypatch.delenv("HATE_CRACK_PLAIN_MENU", raising=False)
monkeypatch.setattr("sys.stdout.isatty", lambda: True)
mock_menu_instance = MagicMock()
mock_menu_instance.show.return_value = 0
with patch(
"hate_crack.menu.TerminalMenu",
create=True,
return_value=mock_menu_instance,
):
result = interactive_menu(SAMPLE_ITEMS, title="Test")
assert result == "1"