from __future__ import annotations import importlib.util import json import os import subprocess import tempfile import unittest from pathlib import Path MODULE_PATH = Path(__file__).with_name("pi-sbx-profile.py") SPEC = importlib.util.spec_from_file_location("pi_sbx_profile", MODULE_PATH) if SPEC is None or SPEC.loader is None: raise RuntimeError(f"Could not load profile resolver from {MODULE_PATH}") MODULE = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(MODULE) class PiSbxProfileTests(unittest.TestCase): def setUp(self) -> None: self.config = { "defaultProfile": "pi-local", "directories": { "/srv/work": "pi-work", "/srv/work/special": "pi-special", }, "defaultRuntime": { "nodeExecutable": "/usr/bin/node", "piExecutable": "~/.bun/bin/pi", "piAgentDirectory": "~/.pi/agent", }, "profileRuntimes": { "pi-work": { "nodeExecutable": "/opt/node-22/bin/node", "piAgentDirectory": "~/.pi/profiles/work", } }, } def test_longest_directory_match_wins(self) -> None: self.assertEqual( MODULE.resolve_profile(self.config, Path("/srv/work/special/repository")), ("pi-special", "directory", Path("/srv/work/special")), ) def test_directory_matches_descendants(self) -> None: self.assertEqual( MODULE.resolve_profile(self.config, Path("/srv/work/code/repository")), ("pi-work", "directory", Path("/srv/work")), ) def test_directory_does_not_match_similar_prefix(self) -> None: self.assertEqual( MODULE.resolve_profile(self.config, Path("/srv/worker/repository")), ("pi-local", "default", None), ) def test_profile_runtime_overrides_defaults(self) -> None: self.assertEqual( MODULE.runtime_for_profile(self.config, "pi-work"), { "nodeExecutable": "/opt/node-22/bin/node", "piExecutable": str(Path("~/.bun/bin/pi").expanduser()), "piAgentDirectory": str(Path("~/.pi/profiles/work").expanduser()), }, ) def test_default_runtime_is_used_without_override(self) -> None: runtime = MODULE.runtime_for_profile(self.config, "pi-special") self.assertEqual(runtime["nodeExecutable"], "/usr/bin/node") self.assertEqual(runtime["piAgentDirectory"], str(Path("~/.pi/agent").expanduser())) def test_configuration_requires_complete_default_runtime(self) -> None: del self.config["defaultRuntime"]["piExecutable"] with self.assertRaisesRegex(ValueError, "missing fields: piExecutable"): MODULE.validate_config(self.config) def test_configuration_rejects_noncanonical_directory(self) -> None: self.config["directories"] = {"~/work": "pi-local"} with self.assertRaisesRegex(ValueError, "canonical absolute physical paths"): MODULE.validate_config(self.config) def test_relative_xdg_config_home_is_ignored(self) -> None: original_xdg = os.environ.get("XDG_CONFIG_HOME") original_override = os.environ.pop("PI_SBX_CONFIG", None) os.environ["XDG_CONFIG_HOME"] = "repository-controlled" try: self.assertEqual(MODULE.config_path(), MODULE.DEFAULT_CONFIG_PATH.expanduser()) finally: if original_xdg is None: os.environ.pop("XDG_CONFIG_HOME", None) else: os.environ["XDG_CONFIG_HOME"] = original_xdg if original_override is not None: os.environ["PI_SBX_CONFIG"] = original_override def test_relative_config_override_is_rejected(self) -> None: original_override = os.environ.get("PI_SBX_CONFIG") os.environ["PI_SBX_CONFIG"] = "config.json" try: with self.assertRaisesRegex(ValueError, "PI_SBX_CONFIG must be an absolute path"): MODULE.config_path() finally: if original_override is None: os.environ.pop("PI_SBX_CONFIG", None) else: os.environ["PI_SBX_CONFIG"] = original_override def test_save_and_load_configuration(self) -> None: with tempfile.TemporaryDirectory() as directory: path = Path(directory) / "pi-sbx" / "config.json" MODULE.save_config(self.config, path) self.assertEqual(MODULE.load_config(path), self.config) self.assertEqual(path.stat().st_mode & 0o777, 0o600) self.assertEqual(json.loads(path.read_text(encoding="utf-8")), self.config) def test_set_without_path_assigns_current_directory(self) -> None: with tempfile.TemporaryDirectory() as directory: temporary = Path(directory) config_path = temporary / "config.json" workdir = temporary / "repository" binary_directory = temporary / "bin" workdir.mkdir() binary_directory.mkdir() MODULE.save_config(self.config, config_path) nono = binary_directory / "nono" nono.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8") nono.chmod(0o755) environment = os.environ.copy() environment["PI_SBX_CONFIG"] = str(config_path) environment["PATH"] = f"{binary_directory}:{environment['PATH']}" result = subprocess.run( [str(MODULE_PATH), "set", "pi-special"], cwd=workdir, env=environment, check=True, capture_output=True, text=True, ) self.assertEqual(result.stdout.strip(), f"{workdir} -> pi-special") self.assertEqual(MODULE.load_config(config_path)["directories"][str(workdir)], "pi-special") subprocess.run( [str(MODULE_PATH), "unset"], cwd=workdir, env=environment, check=True, capture_output=True, text=True, ) self.assertNotIn(str(workdir), MODULE.load_config(config_path)["directories"]) def test_legacy_set_root_command_assigns_current_directory(self) -> None: with tempfile.TemporaryDirectory() as directory: temporary = Path(directory) config_path = temporary / "config.json" workdir = temporary / "repository" binary_directory = temporary / "bin" workdir.mkdir() binary_directory.mkdir() MODULE.save_config(self.config, config_path) nono = binary_directory / "nono" nono.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8") nono.chmod(0o755) environment = os.environ.copy() environment["PI_SBX_CONFIG"] = str(config_path) environment["PATH"] = f"{binary_directory}:{environment['PATH']}" subprocess.run( [str(Path(__file__).with_name("orca-nono-profile.py")), "set-root", "pi-special"], cwd=workdir, env=environment, check=True, capture_output=True, text=True, ) self.assertEqual(MODULE.load_config(config_path)["directories"][str(workdir)], "pi-special") if __name__ == "__main__": unittest.main()