Files
hate_crack/tests/test_ui_test_pushover.py
Justin Bollinger ce625a7874 fix(tests): patch hate_crack.main._notify directly
tests/test_random_rules_attack.py purges and re-imports hate_crack.*
modules, which leaves main._notify pointing at a different notify
object than a top-level patch("hate_crack.notify._send_pushover")
would touch. Under the full suite that caused the test's mock to
miss and the production call to hit the real Pushover API.

Switch to patch.object(hc_main, "_notify") -- same pattern as
tests/test_run_hcat_cmd.py but anchored to the exact module object
already bound as hc_main, so it is immune to sys.modules churn
regardless of import order. Drop the now-redundant _install_settings
helper and _reset_notify_state fixture.
2026-04-22 18:07:52 -04:00

80 lines
3.7 KiB
Python

"""Unit tests for main.test_pushover_notification().
These tests patch ``hate_crack.main._notify`` directly rather than
``hate_crack.notify._send_pushover``. The latter is fragile because
``tests/test_random_rules_attack.py`` purges ``hate_crack.*`` from
``sys.modules`` and re-imports, which leaves ``main._notify`` pointing
at a different module object than the one a top-level ``patch`` would
touch. Patching the attribute on ``main`` itself is robust to that.
We use ``patch.object(hc_main, "_notify")`` rather than
``patch("hate_crack.main._notify")`` so the patch target is the exact
module object whose function we invoke. A string target would re-resolve
``hate_crack.main`` through ``sys.modules``, which — again thanks to the
purge in ``test_random_rules_attack.py`` — can be a different object from
the ``hc_main`` reference bound at test-module import time.
"""
from types import SimpleNamespace
from unittest.mock import patch
from hate_crack import main as hc_main
def _settings(
*, enabled: bool = True, token: str = "tok", user: str = "usr"
) -> SimpleNamespace:
"""Minimal stand-in for ``NotifySettings`` — we only read three fields."""
return SimpleNamespace(enabled=enabled, pushover_token=token, pushover_user=user)
class TestTestPushoverNotification:
def test_success_prints_confirmation_and_sends(self, capsys):
with patch.object(hc_main, "_notify") as mock_notify:
mock_notify.get_settings.return_value = _settings(enabled=True)
mock_notify._send_pushover.return_value = True
hc_main.test_pushover_notification()
mock_notify._send_pushover.assert_called_once()
args = mock_notify._send_pushover.call_args.args
assert args[0] == "tok"
assert args[1] == "usr"
assert args[2] == "hate_crack: test notification"
assert "test notification from hate_crack" in args[3]
out = capsys.readouterr().out
assert "[+] Test Pushover notification sent" in out
def test_failure_prints_failure_line(self, capsys):
with patch.object(hc_main, "_notify") as mock_notify:
mock_notify.get_settings.return_value = _settings(enabled=True)
mock_notify._send_pushover.return_value = False
hc_main.test_pushover_notification()
out = capsys.readouterr().out
assert "[!] Test Pushover notification failed" in out
def test_missing_token_skips_send_and_warns(self, capsys):
with patch.object(hc_main, "_notify") as mock_notify:
mock_notify.get_settings.return_value = _settings(enabled=True, token="")
hc_main.test_pushover_notification()
mock_notify._send_pushover.assert_not_called()
out = capsys.readouterr().out
assert "[!] Pushover credentials missing" in out
assert "notify_pushover_token" in out
def test_missing_user_skips_send_and_warns(self, capsys):
with patch.object(hc_main, "_notify") as mock_notify:
mock_notify.get_settings.return_value = _settings(enabled=True, user="")
hc_main.test_pushover_notification()
mock_notify._send_pushover.assert_not_called()
out = capsys.readouterr().out
assert "[!] Pushover credentials missing" in out
def test_globally_off_still_sends_with_note(self, capsys):
with patch.object(hc_main, "_notify") as mock_notify:
mock_notify.get_settings.return_value = _settings(enabled=False)
mock_notify._send_pushover.return_value = True
hc_main.test_pushover_notification()
mock_notify._send_pushover.assert_called_once()
out = capsys.readouterr().out
assert "notifications are globally OFF" in out
assert "[+] Test Pushover notification sent" in out