from __future__ import annotations import json import unittest from copy import deepcopy from pathlib import Path from techviz.spec import VizSpec from techviz.validate import has_errors, validate_spec ROOT = Path(__file__).resolve().parents[1] class ValidationTests(unittest.TestCase): def setUp(self) -> None: self.spec_data = json.loads((ROOT / "examples/work/payment/spec.json").read_text(encoding="utf-8")) self.context = json.loads((ROOT / "examples/work/payment/context.json").read_text(encoding="utf-8")) def test_example_is_clean(self) -> None: issues = validate_spec(VizSpec.from_dict(self.spec_data), self.context) self.assertFalse(has_errors(issues), issues) self.assertEqual(issues, []) def test_ungrounded_node_is_error(self) -> None: data = deepcopy(self.spec_data) data["nodes"][0]["evidence"] = [] issues = validate_spec(VizSpec.from_dict(data), self.context) self.assertTrue(any(issue.code == "ungrounded-element" and issue.path == "nodes[0]" for issue in issues)) def test_boundary_requires_evidence(self) -> None: data = deepcopy(self.spec_data) data["groups"] = [ { "id": "trust-boundary", "label": "Trust boundary", "kind": "trust", "evidence": [], "assumption": False } ] data["nodes"][1]["group"] = "trust-boundary" issues = validate_spec(VizSpec.from_dict(data), self.context) self.assertTrue(any(issue.code == "ungrounded-element" and issue.path == "groups[0]" for issue in issues)) def test_explicit_assumption_is_warning_not_grounding_error(self) -> None: data = deepcopy(self.spec_data) data["nodes"][0]["evidence"] = [] data["nodes"][0]["assumption"] = True issues = validate_spec(VizSpec.from_dict(data), self.context) self.assertFalse(any(issue.code == "ungrounded-element" and issue.path == "nodes[0]" for issue in issues)) self.assertTrue(any(issue.code == "explicit-assumption" for issue in issues)) def test_assumption_cannot_also_claim_evidence(self) -> None: data = deepcopy(self.spec_data) data["nodes"][0]["assumption"] = True issues = validate_spec(VizSpec.from_dict(data), self.context) self.assertTrue(any(issue.code == "assumption-with-evidence" for issue in issues)) def test_indirect_group_cycle_is_error(self) -> None: data = deepcopy(self.spec_data) data["groups"] = [ { "id": "a", "label": "A", "kind": "system", "parent": "b", "evidence": [{"start_line": 7, "end_line": 7}], "assumption": False, }, { "id": "b", "label": "B", "kind": "system", "parent": "a", "evidence": [{"start_line": 7, "end_line": 7}], "assumption": False, }, ] issues = validate_spec(VizSpec.from_dict(data), self.context) self.assertTrue(any(issue.code == "recursive-group" for issue in issues)) if __name__ == "__main__": unittest.main()