import tempfile import unittest from pathlib import Path from unittest import mock from sbp import hostinfo from sbp.errors import SbpError from sbp.fsutil import safe_rmtree from sbp.state import StateStore class PickPortTest(unittest.TestCase): def test_stops_at_65535(self) -> None: with mock.patch("sbp.hostinfo.port_free", return_value=False) as probe: with self.assertRaises(SbpError): hostinfo.pick_port("127.0.0.1", set(), start=65535) self.assertEqual(probe.call_count, 1) def test_skips_used_ports(self) -> None: with mock.patch("sbp.hostinfo.port_free", return_value=True): self.assertEqual(hostinfo.pick_port("127.0.0.1", {20000, 20001}, start=20000), 20002) class SafeRmtreeTest(unittest.TestCase): def test_refuses_marker_outside_target(self) -> None: with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) target = root / "data" target.mkdir() marker = root / "elsewhere" marker.write_text("x") with self.assertRaises(SbpError): safe_rmtree(target, marker) self.assertTrue(target.exists()) def test_removes_when_marker_is_inside(self) -> None: with tempfile.TemporaryDirectory() as tmp: target = Path(tmp) / "data" (target / "bin").mkdir(parents=True) marker = target / "bin" / "sing-box" marker.write_text("x") safe_rmtree(target, marker) self.assertFalse(target.exists()) class TryLoadTest(unittest.TestCase): def test_corrupt_state_returns_none(self) -> None: with tempfile.TemporaryDirectory() as tmp: store = StateStore(Path(tmp)) store.path.write_text("{not json") self.assertIsNone(store.try_load()) def test_missing_state_returns_none(self) -> None: with tempfile.TemporaryDirectory() as tmp: self.assertIsNone(StateStore(Path(tmp)).try_load()) if __name__ == "__main__": unittest.main()