Compose migration (4 files, 2059 lines of View code → Compose): - ThemePickerDialog: Compose Canvas preview, LazyColumn theme list - TerminalDialogs: 6 dead dialogs deleted, 2 migrated (hostKey, authPrompt) with TerminalDialogRequest sealed interface on MainViewModel for imperative→declarative bridge. Added PasswordDialog for no-stored-pw case. - SnippetDialogs: full-screen Compose dialog with LazyColumn, search, inline create form, context menu - KeyboardSettingsDialog: TabRow, Slider, Canvas preview, color picker. Data classes extracted to KeyboardModels.kt AQB/CQB separation: - Independent Quick Bar preferences for AKB vs CKB modes - Settings UI mode-aware: CKB shows full keyboard dialog, AKB shows QB-only - AQB positions filtered (no above/below keyboard) - New docs: KEYBOARD.md, GLOSSARY.md (TV, AKB, CKB, AQB, CQB) Password prompt: - TerminalService prompts for password when no stored auth (SSHAuth.None) - Compose PasswordDialog with remember checkbox - clearPassword ADB broadcast for test cleanup ADB test framework (Python): - test.py runner with menu, --all, single test modes - AI visual verification via claude -p reading screenshots - 5 tests, 52 checks: connect, htop, vim, password prompt, multi-session - Timestamped results with manifest.json for cross-run comparison Coding conventions updated: 100% Compose mandated, no programmatic Views. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
59 lines
1.5 KiB
Python
Executable file
59 lines
1.5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""SSH Workbench Test Runner — menu or CLI."""
|
|
|
|
import sys, glob, os, importlib.util
|
|
from pathlib import Path
|
|
|
|
TESTS_DIR = Path(__file__).resolve().parent / "tests"
|
|
tests = sorted(TESTS_DIR.glob("*.py"))
|
|
|
|
if not tests:
|
|
print("No tests found")
|
|
sys.exit(1)
|
|
|
|
def run_test(path):
|
|
print(f"\n>>> Running: {path.name}")
|
|
spec = importlib.util.spec_from_file_location(path.stem, path)
|
|
mod = importlib.util.module_from_spec(spec)
|
|
try:
|
|
spec.loader.exec_module(mod)
|
|
except SystemExit as e:
|
|
return e.code == 0
|
|
return True
|
|
|
|
# CLI: --all
|
|
if len(sys.argv) > 1 and sys.argv[1] == "--all":
|
|
ok = all(run_test(t) for t in tests)
|
|
sys.exit(0 if ok else 1)
|
|
|
|
# CLI: number or prefix
|
|
if len(sys.argv) > 1:
|
|
match = [t for t in tests if sys.argv[1] in t.name]
|
|
if match:
|
|
ok = run_test(match[0])
|
|
sys.exit(0 if ok else 1)
|
|
print(f"No test matching '{sys.argv[1]}'")
|
|
sys.exit(1)
|
|
|
|
# Interactive menu
|
|
print("\n=== SSH Workbench Test Runner ===\n")
|
|
for i, t in enumerate(tests):
|
|
print(f" {i+1}. {t.stem}")
|
|
print(f"\n a. Run all")
|
|
print(f" q. Quit\n")
|
|
|
|
choice = input("Choice: ").strip()
|
|
if choice in ("q", "Q"):
|
|
sys.exit(0)
|
|
if choice in ("a", "A"):
|
|
ok = all(run_test(t) for t in tests)
|
|
sys.exit(0 if ok else 1)
|
|
try:
|
|
idx = int(choice) - 1
|
|
if 0 <= idx < len(tests):
|
|
ok = run_test(tests[idx])
|
|
sys.exit(0 if ok else 1)
|
|
except ValueError:
|
|
pass
|
|
print("Invalid choice")
|
|
sys.exit(1)
|