feat: add csharp win helper probe

This commit is contained in:
zhaoyilun
2026-07-05 14:29:29 +08:00
parent d58b9a0274
commit f2dd1c7e57
7 changed files with 816 additions and 0 deletions

130
tests/test_win_helper.py Normal file
View File

@@ -0,0 +1,130 @@
import json
import subprocess
import unittest
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
BUILD_SCRIPT = REPO / "scripts" / "build-win-helper.ps1"
HELPER_EXE = REPO / "runs" / "win-helper" / "ISphereWinHelper.exe"
def build_helper():
result = subprocess.run(
[
"powershell",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
str(BUILD_SCRIPT),
],
cwd=REPO,
text=True,
encoding="utf-8",
errors="replace",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=60,
)
if result.returncode != 0:
raise AssertionError(result.stdout + result.stderr)
def invoke_helper(payload):
if isinstance(payload, str):
stdin = payload
else:
stdin = json.dumps(payload, ensure_ascii=False)
result = subprocess.run(
[str(HELPER_EXE), "--json"],
cwd=REPO,
input=stdin,
text=True,
encoding="utf-8",
errors="replace",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=30,
)
try:
decoded = json.loads(result.stdout)
except json.JSONDecodeError as exc:
raise AssertionError(f"stdout was not JSON: {result.stdout!r}; stderr={result.stderr!r}") from exc
return result, decoded
class WinHelperBuildTests(unittest.TestCase):
def test_build_script_creates_helper_exe(self):
if HELPER_EXE.exists():
HELPER_EXE.unlink()
build_helper()
self.assertTrue(HELPER_EXE.exists(), f"helper exe missing: {HELPER_EXE}")
class WinHelperProtocolTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
build_helper()
def request(self, op, args=None):
result, decoded = invoke_helper(
{
"protocol": "isphere.helper.v1",
"request_id": f"test-{op}",
"op": op,
"timeout_ms": 5000,
"args": args or {},
}
)
self.assertEqual(result.returncode, 0, result.stderr)
return decoded
def test_version_returns_contract_metadata(self):
decoded = self.request("version")
self.assertTrue(decoded["ok"])
self.assertEqual(decoded["protocol"], "isphere.helper.v1")
self.assertEqual(decoded["request_id"], "test-version")
self.assertEqual(decoded["op"], "version")
self.assertEqual(decoded["data"]["helper_name"], "ISphereWinHelper")
self.assertEqual(decoded["data"]["protocol"], "isphere.helper.v1")
def test_self_check_reports_desktop_and_uia_status(self):
decoded = self.request("self_check")
self.assertTrue(decoded["ok"])
self.assertIn("desktop_access", decoded["data"])
self.assertIn("uia_available", decoded["data"])
def test_scan_windows_returns_json_window_list(self):
decoded = self.request("scan_windows", {"include_all_visible": True})
self.assertTrue(decoded["ok"])
self.assertIsInstance(decoded["data"]["windows"], list)
def test_unsupported_op_returns_structured_error(self):
decoded = self.request("does_not_exist")
self.assertFalse(decoded["ok"])
self.assertEqual(decoded["error"]["code"], "UNSUPPORTED_OP")
def test_invalid_json_returns_structured_error(self):
result, decoded = invoke_helper("{not json")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertFalse(decoded["ok"])
self.assertEqual(decoded["protocol"], "isphere.helper.v1")
self.assertEqual(decoded["error"]["code"], "INVALID_REQUEST")
def test_dump_uia_with_missing_window_returns_structured_error(self):
decoded = self.request("dump_uia", {"hwnd": "0x0"})
self.assertFalse(decoded["ok"])
self.assertIn(decoded["error"]["code"], {"WINDOW_NOT_FOUND", "UIA_DUMP_FAILED"})
if __name__ == "__main__":
unittest.main()