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_hal_component_manifest import OUTPUT, generate, parse_comp, parse_hal ROOT = Path(__file__).resolve().parents[1] class HalComponentManifestTests(unittest.TestCase): def test_parse_component_contract(self): with TemporaryDirectory() as directory: root = Path(directory) path = root / "linuxcnc/src/hal/components/demo.comp" path.parent.mkdir(parents=True) path.write_text("component demo;\npin in float input;\npin out bit output;\nparam rw float gain = 1.0;\nfunction update;\n", encoding="utf-8") report = parse_comp(root, path) self.assertEqual(report["status"], "verified") self.assertEqual(report["component"], "demo") self.assertEqual(len(report["pins"]), 2) self.assertEqual(report["params"][0]["default"], "1.0") self.assertEqual(report["functions"][0]["name"], "update") def test_hal_unknown_and_dynamic_loaders_block(self): with TemporaryDirectory() as directory: root = Path(directory) path = root / "linuxcnc/lib/hallib/demo.hal" path.parent.mkdir(parents=True) path.write_text("loadrt demo names=d0\nloadrt [KINS]KINEMATICS\nloadusr -W external\naddf d0 servo-thread\n", encoding="utf-8") records = parse_hal(root, path, {"demo"}, "resource:demo") self.assertEqual(records[0]["status"], "declared") self.assertEqual(records[1]["code"], "undeclared_or_variable_component") self.assertEqual(records[2]["code"], "host_dynamic_loader") self.assertEqual(records[3]["status"], "checked") def test_generation_is_deterministic(self): before = (ROOT / OUTPUT).read_bytes() first = generate(ROOT, ROOT / OUTPUT) after = (ROOT / OUTPUT).read_bytes() self.assertEqual(before, after) self.assertEqual(first["report_sha256"], json.loads(after.decode())["report_sha256"]) if __name__ == "__main__": unittest.main()