Advance TUI v2 parity with reveal/QR and landing theme

This commit is contained in:
thePR0M3TH3AN committed 2026-03-01 18:20:57 -05:00
1 parent f02b360062
commit 92f17355ad
7 files changed
+800 -20

No files matched your search

+56
View File
@@ -286,6 +286,62 @@ class TestEntryService:
mock_manager.entry_manager.get_totp_code.assert_called_once_with(1, b"key")
assert code == "123456"
def test_get_seed_phrase(self, service, mock_manager):
mock_manager.entry_manager.get_seed_phrase.return_value = "seed words"
phrase = service.get_seed_phrase(7)
mock_manager.entry_manager.get_seed_phrase.assert_called_once_with(
7, mock_manager.parent_seed
)
assert phrase == "seed words"
def test_get_managed_account_seed(self, service, mock_manager):
mock_manager.entry_manager.get_managed_account_seed.return_value = (
"managed words"
)
phrase = service.get_managed_account_seed(8)
mock_manager.entry_manager.get_managed_account_seed.assert_called_once_with(
8, mock_manager.parent_seed
)
assert phrase == "managed words"
def test_get_ssh_key_pair(self, service, mock_manager):
mock_manager.entry_manager.get_ssh_key_pair.return_value = ("priv", "pub")
result = service.get_ssh_key_pair(3)
mock_manager.entry_manager.get_ssh_key_pair.assert_called_once_with(
3, mock_manager.parent_seed
)
assert result == ("priv", "pub")
def test_get_pgp_key(self, service, mock_manager):
mock_manager.entry_manager.get_pgp_key.return_value = ("priv", "fp")
result = service.get_pgp_key(4)
mock_manager.entry_manager.get_pgp_key.assert_called_once_with(
4, mock_manager.parent_seed
)
assert result == ("priv", "fp")
def test_get_nostr_key_pair(self, service, mock_manager):
mock_manager.entry_manager.get_nostr_key_pair.return_value = ("npub", "nsec")
result = service.get_nostr_key_pair(5)
mock_manager.entry_manager.get_nostr_key_pair.assert_called_once_with(
5, mock_manager.parent_seed
)
assert result == ("npub", "nsec")
def test_get_secret_mode_enabled(self, service, mock_manager):
mock_manager.config_manager.get_secret_mode_enabled.return_value = True
assert service.get_secret_mode_enabled() is True
def test_get_clipboard_clear_delay(self, service, mock_manager):
mock_manager.config_manager.get_clipboard_clear_delay.return_value = 40
assert service.get_clipboard_clear_delay() == 40
def test_copy_to_clipboard(self, service, mock_manager):
mock_manager.config_manager.get_clipboard_clear_delay.return_value = 35
with patch("seedpass.core.api.copy_to_clipboard", return_value=True) as patched:
assert service.copy_to_clipboard("secret-value") is True
patched.assert_called_once_with("secret-value", 35)
def test_add_entry(self, service, mock_manager):
mock_manager.entry_manager.add_entry.return_value = 1
+66
View File
@@ -35,6 +35,9 @@ class MatrixEntryService:
self.fail_modify = fail_modify
self.fail_add_link = fail_add_link
self.fail_remove_link = fail_remove_link
self.secret_mode_enabled = False
self.clipboard_delay = 30
self.clipboard_values: list[str] = []
def search_entries(self, query: str, kinds: list[str] | None = None):
if self.fail_search:
@@ -74,6 +77,61 @@ class MatrixEntryService:
if value is not None:
entry[key] = value
def generate_password(self, length: int, entry_id: int) -> str:
return f"pw-{entry_id}-{length}"
def get_seed_phrase(self, entry_id: int) -> str:
entry = self._entries[int(entry_id)]
return str(entry.get("seed_phrase", "abandon " * 11 + "about")).strip()
def get_managed_account_seed(self, entry_id: int) -> str:
entry = self._entries[int(entry_id)]
return str(
entry.get(
"seed_phrase",
"legal winner thank year wave sausage worth useful legal winner thank yellow",
)
).strip()
def get_totp_secret(self, entry_id: int) -> str:
entry = self._entries[int(entry_id)]
return str(entry.get("secret", "JBSWY3DPEHPK3PXP"))
def get_totp_code(self, entry_id: int) -> str:
_ = entry_id
return "123456"
def get_ssh_key_pair(self, entry_id: int):
entry = self._entries[int(entry_id)]
return (
str(entry.get("private_key", "SSH_PRIVATE")),
str(entry.get("public_key", "ssh-ed25519 AAAA...")),
)
def get_pgp_key(self, entry_id: int):
entry = self._entries[int(entry_id)]
return (
str(entry.get("private_key", "-----BEGIN PGP PRIVATE KEY BLOCK-----")),
str(entry.get("fingerprint", "DEADBEEF")),
)
def get_nostr_key_pair(self, entry_id: int):
entry = self._entries[int(entry_id)]
return (
str(entry.get("npub", "npub1example")),
str(entry.get("nsec", "nsec1example")),
)
def get_secret_mode_enabled(self) -> bool:
return self.secret_mode_enabled
def get_clipboard_clear_delay(self) -> int:
return self.clipboard_delay
def copy_to_clipboard(self, value: str) -> bool:
self.clipboard_values.append(value)
return True
def archive_entry(self, entry_id: int) -> None:
if self.fail_archive:
raise RuntimeError("archive failed")
@@ -245,6 +303,14 @@ async def test_tui2_matrix_actions_palette_events_and_guards() -> None:
app._run_palette_command("jump 2")
await pilot.pause()
app._run_palette_command("open 2")
app.action_reveal_selected()
await pilot.pause()
assert "pw-2-" in str(app.query_one("#secret-detail").render())
app.action_show_qr()
await pilot.pause()
assert "QR not supported" in str(app.query_one("#secret-detail").render())
app.action_focus_left()
app.action_focus_center()
app.action_focus_right()
+8
View File
@@ -5,6 +5,7 @@ import pytest
from seedpass.tui_v2.app import (
pagination_window,
parse_palette_command,
render_qr_ascii,
truncate_entry_for_display,
)
@@ -61,6 +62,13 @@ def test_truncate_entry_for_display_truncates_content() -> None:
assert payload["content_truncated"] is True
def test_render_qr_ascii_nonempty() -> None:
rendered = render_qr_ascii("otpauth://totp/example?secret=JBSWY3DPEHPK3PXP")
lines = [line for line in rendered.splitlines() if line.strip()]
assert len(lines) > 4
assert any("##" in line for line in lines)
@pytest.mark.parametrize("rows", [1000, 10000, 50000])
def test_pagination_window_large_vault_sizes(rows: int) -> None:
# Large-vault smoke: pagination math remains stable at high row counts.
@@ -18,6 +18,9 @@ class FakeEntryService:
for entry in entries
}
self.fail_search_times = fail_search_times
self.secret_mode_enabled = False
self.clipboard_delay = 30
self.clipboard_values: list[str] = []
def search_entries(self, query: str, kinds: list[str] | None = None):
if self.fail_search_times > 0:
@@ -56,6 +59,61 @@ class FakeEntryService:
continue
entry[key] = value
def generate_password(self, length: int, entry_id: int) -> str:
return f"pw-{entry_id}-{length}"
def get_seed_phrase(self, entry_id: int) -> str:
entry = self._entries[int(entry_id)]
return str(entry.get("seed_phrase", "abandon " * 11 + "about")).strip()
def get_managed_account_seed(self, entry_id: int) -> str:
entry = self._entries[int(entry_id)]
return str(
entry.get(
"seed_phrase",
"legal winner thank year wave sausage worth useful legal winner thank yellow",
)
).strip()
def get_totp_secret(self, entry_id: int) -> str:
entry = self._entries[int(entry_id)]
return str(entry.get("secret", "JBSWY3DPEHPK3PXP"))
def get_totp_code(self, entry_id: int) -> str:
_ = entry_id
return "123456"
def get_ssh_key_pair(self, entry_id: int):
entry = self._entries[int(entry_id)]
return (
str(entry.get("private_key", "SSH_PRIVATE")),
str(entry.get("public_key", "ssh-ed25519 AAAA...")),
)
def get_pgp_key(self, entry_id: int):
entry = self._entries[int(entry_id)]
return (
str(entry.get("private_key", "-----BEGIN PGP PRIVATE KEY BLOCK-----")),
str(entry.get("fingerprint", "DEADBEEF")),
)
def get_nostr_key_pair(self, entry_id: int):
entry = self._entries[int(entry_id)]
return (
str(entry.get("npub", "npub1example")),
str(entry.get("nsec", "nsec1example")),
)
def get_secret_mode_enabled(self) -> bool:
return self.secret_mode_enabled
def get_clipboard_clear_delay(self) -> int:
return self.clipboard_delay
def copy_to_clipboard(self, value: str) -> bool:
self.clipboard_values.append(value)
return True
def archive_entry(self, entry_id: int) -> None:
self._entries[int(entry_id)]["archived"] = True
@@ -225,6 +283,101 @@ async def test_tui2_textual_link_commands_and_neighbor_open() -> None:
assert "No graph links" in links_text
@pytest.mark.anyio
async def test_tui2_textual_reveal_and_qr_flow() -> None:
service = FakeEntryService(
[
{"id": 1, "kind": "password", "label": "Login 1", "length": 16},
{
"id": 2,
"kind": "seed",
"label": "Seed 2",
"seed_phrase": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
},
{
"id": 3,
"kind": "totp",
"label": "TOTP 3",
"secret": "JBSWY3DPEHPK3PXP",
"period": 30,
"digits": 6,
},
]
)
app = _build_app(service)
async with app.run_test() as pilot:
await pilot.pause()
app._run_palette_command("open 1")
app.action_reveal_selected()
await pilot.pause()
assert "Password : pw-1-16" in _widget_text(app, "#secret-detail")
app._run_palette_command("open 2")
app.action_show_qr()
await pilot.pause()
qr_text = _widget_text(app, "#secret-detail")
assert "Seed #2 QR" in qr_text
assert "Payload:" in qr_text
app._run_palette_command("open 3")
app._run_palette_command("reveal")
await pilot.pause()
assert "Secret : JBSWY3DPEHPK3PXP" in _widget_text(app, "#secret-detail")
app._run_palette_command("qr")
await pilot.pause()
assert "TOTP #3 QR" in _widget_text(app, "#secret-detail")
@pytest.mark.anyio
async def test_tui2_textual_sensitive_confirm_and_secret_mode_clipboard() -> None:
service = FakeEntryService(
[
{
"id": 1,
"kind": "ssh",
"label": "SSH 1",
"private_key": "SSH_PRIVATE_1",
"public_key": "ssh-ed25519 AAAA-1",
},
{
"id": 2,
"kind": "nostr",
"label": "Nostr 2",
"npub": "npub1abc",
"nsec": "nsec1abc",
},
]
)
service.secret_mode_enabled = True
service.clipboard_delay = 45
app = _build_app(service)
async with app.run_test() as pilot:
await pilot.pause()
app._run_palette_command("open 1")
app._run_palette_command("reveal")
await pilot.pause()
assert "requires confirmation" in _status_text(app)
app._run_palette_command("reveal confirm")
await pilot.pause()
assert "copied to clipboard" in _widget_text(app, "#secret-detail")
assert service.clipboard_values[-1] == "SSH_PRIVATE_1"
app._run_palette_command("open 2")
app._run_palette_command("qr private")
await pilot.pause()
assert "requires confirmation" in _status_text(app)
app._run_palette_command("qr private confirm")
await pilot.pause()
assert "Nostr #2 QR" in _widget_text(app, "#secret-detail")
@pytest.mark.anyio
async def test_tui2_textual_retry_after_search_failure() -> None:
service = FakeEntryService(