From cd0f9624aea24c72712986cb7515b97ed617af96 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Thu, 17 Jul 2025 21:33:06 -0400 Subject: [PATCH] Add service layer and CLI regression tests --- src/tests/test_cli_core_services.py | 69 ++++++++++++++++++++++++++++ src/tests/test_core_services.py | 71 +++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 src/tests/test_cli_core_services.py create mode 100644 src/tests/test_core_services.py diff --git a/src/tests/test_cli_core_services.py b/src/tests/test_cli_core_services.py new file mode 100644 index 0000000..45a6d9d --- /dev/null +++ b/src/tests/test_cli_core_services.py @@ -0,0 +1,69 @@ +from types import SimpleNamespace + +import typer +from typer.testing import CliRunner + +from seedpass import cli +from seedpass.cli import app + +runner = CliRunner() + + +def test_cli_vault_unlock(monkeypatch): + called = {} + + def unlock_vault(pw): + called["pw"] = pw + return 0.5 + + pm = SimpleNamespace(unlock_vault=unlock_vault, select_fingerprint=lambda fp: None) + monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli.typer, "prompt", lambda *a, **k: "pw") + result = runner.invoke(app, ["vault", "unlock"]) + assert result.exit_code == 0 + assert "Unlocked in" in result.stdout + assert called["pw"] == "pw" + + +def test_cli_entry_add_search_sync(monkeypatch): + calls = {} + + def add_entry(label, length, username=None, url=None): + calls["add"] = (label, length, username, url) + return 1 + + def search_entries(q): + calls["search"] = q + return [(1, "Label", None, None, False)] + + def sync_vault(): + calls["sync"] = True + return {"manifest_id": "m", "chunk_ids": [], "delta_ids": []} + + pm = SimpleNamespace( + entry_manager=SimpleNamespace( + add_entry=add_entry, search_entries=search_entries + ), + sync_vault=sync_vault, + select_fingerprint=lambda fp: None, + ) + monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + + # entry add + result = runner.invoke(app, ["entry", "add", "Label"]) + assert result.exit_code == 0 + assert "1" in result.stdout + assert calls["add"] == ("Label", 12, None, None) + assert calls.get("sync") is True + + # entry search + result = runner.invoke(app, ["entry", "search", "lab"]) + assert result.exit_code == 0 + assert "Label" in result.stdout + assert calls["search"] == "lab" + + # nostr sync + result = runner.invoke(app, ["nostr", "sync"]) + assert result.exit_code == 0 + assert "manifest" in result.stdout.lower() + assert calls.get("sync") is True diff --git a/src/tests/test_core_services.py b/src/tests/test_core_services.py new file mode 100644 index 0000000..d71a859 --- /dev/null +++ b/src/tests/test_core_services.py @@ -0,0 +1,71 @@ +import types +from types import SimpleNamespace + +from seedpass.core.api import VaultService, EntryService, SyncService, UnlockRequest + + +def test_vault_service_unlock(): + called = {} + + def unlock_vault(pw: str) -> float: + called["pw"] = pw + return 0.42 + + pm = SimpleNamespace(unlock_vault=unlock_vault) + service = VaultService(pm) + resp = service.unlock(UnlockRequest(password="secret")) + assert called["pw"] == "secret" + assert resp.duration == 0.42 + + +def test_entry_service_add_entry_and_search(): + called = {} + + def add_entry(label, length, username=None, url=None): + called["add"] = (label, length, username, url) + return 5 + + def search_entries(q): + called["search"] = q + return [(5, "Example", username, url, False)] + + def sync_vault(): + called["sync"] = True + + username = "user" + url = "https://ex.com" + pm = SimpleNamespace( + entry_manager=SimpleNamespace( + add_entry=add_entry, search_entries=search_entries + ), + sync_vault=sync_vault, + ) + service = EntryService(pm) + idx = service.add_entry("Example", 12, username, url) + assert idx == 5 + assert called["add"] == ("Example", 12, username, url) + assert called.get("sync") is True + + results = service.search_entries("ex") + assert results == [(5, "Example", username, url, False)] + assert called["search"] == "ex" + + +def test_sync_service_sync(): + called = {} + + def sync_vault(): + called["sync"] = True + return { + "manifest_id": "m1", + "chunk_ids": ["c1"], + "delta_ids": ["d1"], + } + + pm = SimpleNamespace(sync_vault=sync_vault) + service = SyncService(pm) + resp = service.sync() + assert called["sync"] is True + assert resp.manifest_id == "m1" + assert resp.chunk_ids == ["c1"] + assert resp.delta_ids == ["d1"]