import sys from pathlib import Path import unittest from unittest.mock import patch import subprocess sys.path.insert(0, str(Path(__file__).parents[1] / "vm")) import accessibility import desktop class AccessibilityTests(unittest.TestCase): def setUp(self): self.target = {"id": "1", "path": [0, 0, 2], "app": "editor", "name": "Input", "role": "text", "bounds": [10, 20, 100, 40]} self.saved = {"observationId": "abc", "size": [800, 600], "targets": [self.target]} self.current = {"targets": [self.target]} def test_center(self): self.assertEqual(accessibility.resolve_target(self.saved, self.current, "abc", "1", 800, 600), (60, 40)) def test_stale_and_missing(self): for observation, target, width in [("old", "1", 800), ("abc", "2", 800), ("abc", "1", 900)]: with self.assertRaises(ValueError): accessibility.resolve_target(self.saved, self.current, observation, target, width, 600) with self.assertRaises(ValueError): accessibility.resolve_target(self.saved, {"targets": []}, "abc", "1", 800, 600) def test_moved_target(self): moved = {**self.target, "bounds": [100, 100, 100, 40]} with self.assertRaises(ValueError): accessibility.resolve_target(self.saved, {"targets": [moved]}, "abc", "1", 800, 600) def test_timeout_fallback(self): with patch.object(subprocess, "run", side_effect=subprocess.TimeoutExpired("scan", 3)): result = accessibility.collect(800, 600) self.assertEqual(result["targets"], []) self.assertIn("unavailable", result["warning"]) def test_target_must_be_first(self): target = {"type": "click_target", "target": "1", "observationId": "abc"} desktop.validate({"actions": [target]}, 800, 600) with self.assertRaises(ValueError): desktop.validate({"actions": [{"type": "keys", "keys": ["Return"]}, target]}, 800, 600) if __name__ == "__main__": unittest.main()