Files
seedPass/src/tests/test_settings_menu.py
2025-08-06 21:33:16 -04:00

173 lines
5.8 KiB
Python

import sys
import importlib
import queue
import time
from pathlib import Path
from tempfile import TemporaryDirectory
from types import SimpleNamespace
from unittest.mock import patch
import pytest
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
import main
from nostr.client import DEFAULT_RELAYS
from seedpass.core.config_manager import ConfigManager
from seedpass.core.manager import Notification, PasswordManager
from seedpass.core.vault import Vault
from utils.fingerprint_manager import FingerprintManager
def setup_pm(tmp_path, monkeypatch):
monkeypatch.setattr(Path, "home", lambda: tmp_path)
import constants
importlib.reload(constants)
importlib.reload(main)
fp_dir = constants.APP_DIR / "fp"
fp_dir.mkdir(parents=True)
vault, enc_mgr = create_vault(fp_dir, TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, fp_dir)
fp_mgr = FingerprintManager(constants.APP_DIR)
nostr_stub = SimpleNamespace(
relays=list(DEFAULT_RELAYS),
close_client_pool=lambda: None,
initialize_client_pool=lambda: None,
publish_snapshot=lambda data, alt_summary=None: (None, "abcd"),
key_manager=SimpleNamespace(get_npub=lambda: "npub"),
)
pm = SimpleNamespace(
config_manager=cfg_mgr,
fingerprint_manager=fp_mgr,
nostr_client=nostr_stub,
)
return pm, cfg_mgr, fp_mgr
def test_relay_and_profile_actions(monkeypatch, capsys):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
pm, cfg_mgr, fp_mgr = setup_pm(tmp_path, monkeypatch)
# Add two fingerprints for listing
fp1 = fp_mgr.add_fingerprint(
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
)
fp2 = fp_mgr.add_fingerprint(
"legal winner thank year wave sausage worth useful legal winner thank yellow"
)
# Add a relay
with patch("builtins.input", return_value="wss://new"), patch(
"main.handle_post_to_nostr"
), patch("main._reload_relays"):
main.handle_add_relay(pm)
cfg = cfg_mgr.load_config(require_pin=False)
assert "wss://new" in cfg["relays"]
# Remove the relay
idx = cfg["relays"].index("wss://new") + 1
with patch("builtins.input", return_value=str(idx)), patch(
"main._reload_relays"
):
main.handle_remove_relay(pm)
cfg = cfg_mgr.load_config(require_pin=False)
assert "wss://new" not in cfg["relays"]
# Reset to defaults
with patch("main._reload_relays"):
main.handle_reset_relays(pm)
cfg = cfg_mgr.load_config(require_pin=False)
assert cfg["relays"] == list(DEFAULT_RELAYS)
# List profiles
main.handle_list_fingerprints(pm)
out = capsys.readouterr().out
assert fp1 in out
assert fp2 in out
def test_settings_menu_additional_backup(monkeypatch):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
pm, cfg_mgr, fp_mgr = setup_pm(tmp_path, monkeypatch)
inputs = iter(["10", ""])
with patch("main.handle_set_additional_backup_location") as handler:
with patch("builtins.input", side_effect=lambda *_: next(inputs)):
main.handle_settings(pm)
handler.assert_called_once_with(pm)
def test_settings_menu_change_password(monkeypatch):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
pm, _, _ = setup_pm(tmp_path, monkeypatch)
calls: list[tuple[str, str]] = []
pm.change_password = lambda old, new: calls.append((old, new))
inputs = iter(["3", ""])
monkeypatch.setattr(main, "prompt_existing_password", lambda *_: "oldpw")
monkeypatch.setattr(main, "prompt_new_password", lambda *_: "newpw")
monkeypatch.setattr(main, "pause", lambda: None)
with patch("builtins.input", side_effect=lambda *_: next(inputs)):
main.handle_settings(pm)
assert calls == [("oldpw", "newpw")]
def test_settings_menu_change_password_incorrect(monkeypatch, capsys):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
pm, _, _ = setup_pm(tmp_path, monkeypatch)
def fail_change(old, new):
raise ValueError("Incorrect password")
pm.change_password = fail_change
inputs = iter(["3", ""])
monkeypatch.setattr(main, "prompt_existing_password", lambda *_: "badpw")
monkeypatch.setattr(main, "prompt_new_password", lambda *_: "newpw")
monkeypatch.setattr(main, "pause", lambda: None)
with patch("builtins.input", side_effect=lambda *_: next(inputs)):
main.handle_settings(pm)
out = capsys.readouterr().out
assert "Incorrect password" in out
def test_settings_menu_without_nostr_client(monkeypatch):
pm = PasswordManager.__new__(PasswordManager)
pm.offline_mode = False
pm.nostr_client = None
pm.notifications = queue.Queue()
pm.error_queue = queue.Queue()
pm.notify = lambda msg, level="INFO": pm.notifications.put(Notification(msg, level))
pm.is_dirty = False
pm.last_update = time.time()
pm.last_activity = time.time()
pm.update_activity = lambda: None
pm.lock_vault = lambda: None
pm.unlock_vault = lambda: None
pm.start_background_relay_check = lambda: None
pm.poll_background_errors = PasswordManager.poll_background_errors.__get__(pm)
pm.display_stats = lambda: None
inputs = iter(["7", ""])
monkeypatch.setattr(main, "timed_input", lambda *_: next(inputs))
monkeypatch.setattr("builtins.input", lambda *_: "")
with pytest.raises(SystemExit):
main.display_menu(pm, sync_interval=1000, inactivity_timeout=1000)
assert pm.error_queue.empty()
assert pm.notifications.empty()