import json import sys import unittest from pathlib import Path from tempfile import TemporaryDirectory sys.path.insert(0, str(Path(__file__).resolve().parent)) from generate_configuration_startup_closure import candidates, generate, resolve_row class ConfigurationStartupClosureTests(unittest.TestCase): def test_explicit_library_and_argument_tail(self): paths, kind, error, args = candidates("LIB:basic_sim.tcl -no_sim_spindle", "linuxcnc/configs/sim/demo/main.ini") self.assertEqual(kind, "library") self.assertIsNone(error) self.assertEqual(args, ["-no_sim_spindle"]) self.assertEqual(paths[0], "linuxcnc/lib/hallib/basic_sim.tcl") def test_relative_does_not_search_by_basename(self): row = {"resource_source_id": "r1", "entrypoint": "linuxcnc/configs/sim/demo/main.ini", "raw_value": "core.hal", "path": "linuxcnc/configs/sim/demo/core.hal", "parse_status": "missing"} result = resolve_row(row, {"linuxcnc/lib/hallib/core.hal"}) self.assertEqual(result["status"], "blocked_missing") self.assertEqual(result["resolution"], "relative") def test_host_and_outside_paths_fail_closed(self): host = resolve_row({"entrypoint": "linuxcnc/configs/sim/demo/main.ini", "raw_value": "~/linuxcnc/nc_files", "path": "~/linuxcnc/nc_files", "parse_status": "host_or_variable_path"}, set()) outside = resolve_row({"entrypoint": "linuxcnc/configs/sim/demo/main.ini", "raw_value": "../../../../etc/passwd", "path": "../../../../etc/passwd", "parse_status": "outside_repo"}, set()) self.assertEqual(host["status"], "blocked_host_path") self.assertEqual(outside["status"], "blocked_outside_repo") def test_generation_is_deterministic(self): root = Path(__file__).resolve().parents[1] with TemporaryDirectory() as directory: output = Path(directory) / "report.json" first = generate(root, output) before = output.read_bytes() second = generate(root, output) self.assertEqual(first, second) self.assertEqual(before, output.read_bytes()) self.assertEqual(json.loads(before)["report_sha256"], second["report_sha256"]) if __name__ == "__main__": unittest.main()