from __future__ import annotations import os import subprocess import tempfile import unittest from pathlib import Path LAUNCHER = Path(__file__).with_name("pi-sbx.fish") class PiSbxLauncherTests(unittest.TestCase): def run_launcher_with_resolver(self, output: str) -> subprocess.CompletedProcess[str]: with tempfile.TemporaryDirectory() as directory: resolver = Path(directory) / "resolver" resolver.write_text(f"#!/bin/sh\nprintf '%s' '{output}'\n", encoding="utf-8") resolver.chmod(0o755) environment = os.environ.copy() environment["PI_SBX_PROFILE_COMMAND"] = str(resolver) return subprocess.run( ["/usr/bin/fish", str(LAUNCHER)], env=environment, check=False, capture_output=True, text=True, ) def test_rejects_incomplete_launcher_configuration(self) -> None: result = self.run_launcher_with_resolver("pi-local\n/usr/bin/node\n") self.assertEqual(result.returncode, 1) self.assertIn("could not resolve a valid configuration", result.stderr) def test_rejects_unavailable_profile(self) -> None: result = self.run_launcher_with_resolver( "profile-that-does-not-exist\n/usr/bin/node\n/home/jb/.bun/bin/pi\n/home/jb/.pi/agent\n" ) self.assertEqual(result.returncode, 1) self.assertIn("resolved nono profile is unavailable", result.stderr) def test_uses_nono_from_path(self) -> None: with tempfile.TemporaryDirectory() as directory: temporary = Path(directory) resolver = temporary / "resolver" resolver.write_text( "#!/bin/sh\nprintf '%b' 'pi-local\\n/missing/node\\n/missing/pi\\n/missing/agent\\n'\n", encoding="utf-8", ) resolver.chmod(0o755) nono = temporary / "nono" nono.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8") nono.chmod(0o755) environment = os.environ.copy() environment["PI_SBX_PROFILE_COMMAND"] = str(resolver) environment["PATH"] = f"{temporary}:{environment['PATH']}" result = subprocess.run( ["/usr/bin/fish", str(LAUNCHER)], env=environment, check=False, capture_output=True, text=True, ) self.assertEqual(result.returncode, 1) self.assertIn("Node runtime is unavailable", result.stderr) if __name__ == "__main__": unittest.main()