"""U-007 tests: backend process start/stop, c_pick_folder route (osascript mocked at the subprocess boundary), and the zero-third-party-dependency constraint (05 §5.7) checked statically via AST, not just trusted. Run: python3 -m unittest src.test_backend_server -v """ import ast import http.client import json import os import subprocess import sys import threading import unittest from unittest.mock import patch from src import backend_server class ServerStartStopTest(unittest.TestCase): def test_can_start_serve_and_stop(self): # deliberately hits an unrelated route, not /api/system/pick-folder -- # that one would pop a real, unmocked osascript dialog on this machine # and hang waiting for a human who isn't there. server = backend_server.create_server() thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() try: host, port = server.server_address conn = http.client.HTTPConnection(host, port, timeout=5) conn.request("POST", "/api/does-not-exist", body=b"{}") resp = conn.getresponse() resp.read() conn.close() self.assertEqual(resp.status, 404) finally: server.shutdown() server.server_close() thread.join(timeout=5) self.assertFalse(thread.is_alive()) def test_unknown_route_returns_404(self): server = backend_server.create_server() thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() try: host, port = server.server_address conn = http.client.HTTPConnection(host, port, timeout=5) conn.request("POST", "/api/does-not-exist") resp = conn.getresponse() body = json.loads(resp.read()) conn.close() self.assertEqual(resp.status, 404) self.assertEqual(body["error"], "NOT_FOUND") finally: server.shutdown() server.server_close() thread.join(timeout=5) class PickFolderTest(unittest.TestCase): def test_success_returns_selected_path(self): with patch("src.backend_server.platform.system", return_value="Darwin"), \ patch("src.backend_server.subprocess.run") as run: run.return_value = subprocess.CompletedProcess( args=["osascript"], returncode=0, stdout="/Users/x/some-project\n", stderr="" ) result = backend_server.pick_folder() self.assertEqual(result, {"selected_path": "/Users/x/some-project"}) def test_user_cancel_returns_null_path_not_an_error(self): with patch("src.backend_server.platform.system", return_value="Darwin"), \ patch("src.backend_server.subprocess.run") as run: run.return_value = subprocess.CompletedProcess( args=["osascript"], returncode=1, stdout="", stderr="execution error: User canceled. (-128)", ) result = backend_server.pick_folder() self.assertEqual(result, {"selected_path": None}) def test_non_macos_raises_dialog_unavailable(self): with patch("src.backend_server.platform.system", return_value="Linux"): with self.assertRaises(backend_server.DialogUnavailableError): backend_server.pick_folder() def test_osascript_failure_other_than_cancel_raises_dialog_unavailable(self): with patch("src.backend_server.platform.system", return_value="Darwin"), \ patch("src.backend_server.subprocess.run") as run: run.return_value = subprocess.CompletedProcess( args=["osascript"], returncode=1, stdout="", stderr="some other AppleScript error", ) with self.assertRaises(backend_server.DialogUnavailableError): backend_server.pick_folder() class PickFolderRouteTest(unittest.TestCase): def setUp(self): self.server = backend_server.create_server() self.thread = threading.Thread(target=self.server.serve_forever, daemon=True) self.thread.start() def tearDown(self): self.server.shutdown() self.server.server_close() self.thread.join(timeout=5) def _post(self, path): host, port = self.server.server_address conn = http.client.HTTPConnection(host, port, timeout=5) conn.request("POST", path, body=b"{}") resp = conn.getresponse() body = json.loads(resp.read()) conn.close() return resp.status, body def test_route_returns_selected_path_on_success(self): with patch("src.backend_server.platform.system", return_value="Darwin"), \ patch("src.backend_server.subprocess.run") as run: run.return_value = subprocess.CompletedProcess( args=["osascript"], returncode=0, stdout="/tmp/chosen\n", stderr="" ) status, body = self._post("/api/system/pick-folder") self.assertEqual(status, 200) self.assertEqual(body, {"selected_path": "/tmp/chosen"}) def test_route_returns_422_dialog_unavailable_off_macos(self): with patch("src.backend_server.platform.system", return_value="Linux"): status, body = self._post("/api/system/pick-folder") self.assertEqual(status, 422) self.assertEqual(body["error"], "DIALOG_UNAVAILABLE") class ZeroThirdPartyDependencyTest(unittest.TestCase): """05 §5.7: no Flask/FastAPI/Express/Node.js -- checked statically so this doesn't silently rot if someone adds an import later.""" def test_backend_server_only_imports_stdlib(self): path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "backend_server.py") with open(path, encoding="utf-8") as f: tree = ast.parse(f.read(), filename=path) top_level_names = set() for node in ast.walk(tree): if isinstance(node, ast.Import): for alias in node.names: top_level_names.add(alias.name.split(".")[0]) elif isinstance(node, ast.ImportFrom) and node.module and node.level == 0: top_level_names.add(node.module.split(".")[0]) self.assertTrue(top_level_names, "expected at least one import to check") non_stdlib = {name for name in top_level_names if name not in sys.stdlib_module_names} self.assertEqual(non_stdlib, set(), "non-stdlib imports found: {}".format(non_stdlib)) if __name__ == "__main__": unittest.main()