test(notify): cover submenu label refresh; document inline-import rationale

Added `test_labels_refresh_between_iterations` that sequences a toggle
then captures the submenu items twice, asserting the label flips
between renders. Guards against a regression where `items` is hoisted
out of the while-loop.

Also documented why the inline `from hate_crack.menu import
interactive_menu` is not actually redundant with the module-scope
import at main.py:77 — it re-reads the attribute on every call, which
is what lets tests patch `hate_crack.menu.interactive_menu`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Justin Bollinger
2026-04-22 20:22:43 -04:00
parent 9b684bb44c
commit 67bec4a40c
2 changed files with 36 additions and 1 deletions

View File

@@ -3902,7 +3902,15 @@ def rule_tools_submenu():
def notifications_submenu():
"""Submenu for all Pushover notification controls (main-menu option 82)."""
"""Submenu for all Pushover notification controls (main-menu option 82).
The inline ``interactive_menu`` import is not redundant with the
module-scope import at the top of this file: re-importing inside the
function re-reads ``hate_crack.menu.interactive_menu`` on every call,
which lets tests patch the real menu function via
``monkeypatch.setattr(hate_crack.menu, "interactive_menu", ...)``.
Removing it breaks test isolation.
"""
from hate_crack.menu import interactive_menu
while True:

View File

@@ -107,3 +107,30 @@ class TestNotificationsSubmenu:
assert labels["3"] == "Send Test Pushover Notification"
assert labels["99"] == "Back to Main Menu"
assert "Notifications" in captured_items["title"]
def test_labels_refresh_between_iterations(self, monkeypatch):
# Guards against a regression where items are built once outside
# the while-loop: labels would go stale after a toggle.
settings = NotifySettings(enabled=False, per_crack_enabled=False)
monkeypatch.setattr(_main_mod._notify, "get_settings", lambda: settings)
def _flip_enabled():
settings.enabled = not settings.enabled
monkeypatch.setattr(_main_mod, "toggle_notifications", _flip_enabled)
monkeypatch.setattr(_main_mod, "toggle_per_crack_notifications", lambda: None)
monkeypatch.setattr(_main_mod, "test_pushover_notification", lambda: None)
captured = []
choices = iter(["1", "99"])
def _fake_menu(items, title=""):
captured.append(dict(items))
return next(choices)
monkeypatch.setattr(_menu_mod, "interactive_menu", _fake_menu)
_main_mod.notifications_submenu()
assert len(captured) == 2
assert "[OFF]" in captured[0]["1"]
assert "[ON]" in captured[1]["1"]