"""Contract checks against the shipped validator, not a copy of it.""" from __future__ import annotations import copy import json import unittest from pathlib import Path ROOT = Path(__file__).resolve().parent.parent import sys sys.path.insert(0, str(ROOT)) from content_explorer.contract import ( # noqa: E402 resolve_claims, validate_dataspace, validate_documents, ) from content_explorer.render import render_explorer # noqa: E402 EXAMPLES = ROOT / "examples" / "dataspaces" RENDERER = ROOT / "content_explorer" / "render.py" def load_pair(name: str) -> tuple[dict, dict]: directory = EXAMPLES / name snapshot = json.loads((directory / "snapshot.json").read_text(encoding="utf-8")) manifest = json.loads((directory / "manifest.json").read_text(encoding="utf-8")) return snapshot, manifest class PublishedFixtures(unittest.TestCase): def test_each_example_passes_the_file_entry_point(self) -> None: names = sorted(path.name for path in EXAMPLES.iterdir() if (path / "snapshot.json").is_file()) self.assertGreaterEqual(len(names), 2) for name in names: errors = validate_dataspace(EXAMPLES / name, require_size=True) self.assertEqual(errors, [], name) def test_renderer_switches_with_the_manifest(self) -> None: systems, systems_manifest = load_pair("systems-thinking") software, software_manifest = load_pair("software-architecture") systems_view = render_explorer(systems, systems_manifest) software_view = render_explorer(software, software_manifest) switched = render_explorer(systems, software_manifest) self.assertIn(systems_manifest["home"]["heading"], systems_view) self.assertIn(software_manifest["home"]["heading"], software_view) self.assertIn(software_manifest["home"]["heading"], switched) self.assertNotIn(systems_manifest["home"]["heading"], switched) self.assertNotIn(software_manifest["home"]["heading"], systems_view) def test_renderer_source_has_no_domain_vocabulary(self) -> None: source = RENDERER.read_text(encoding="utf-8").lower() for word in ( "cancer", "oncolog", "feedback", "coupling", "ashby", "meadows", "alexander", "systems-thinking", "software-architecture", "causal", "cohesion", ): self.assertNotIn(word, source, word) class NegativeGraph(unittest.TestCase): def setUp(self) -> None: self.snapshot, self.manifest = load_pair("systems-thinking") def test_duplicate_entity_id(self) -> None: snapshot = copy.deepcopy(self.snapshot) snapshot["entities"].append(copy.deepcopy(snapshot["entities"][0])) errors = validate_documents(snapshot, self.manifest) self.assertTrue(any("duplicate entity id" in error for error in errors)) def test_dangling_relation(self) -> None: snapshot = copy.deepcopy(self.snapshot) snapshot["relations"][0]["to"] = "urn:ce:systems-thinking:concept:missing" errors = validate_documents(snapshot, self.manifest) self.assertTrue(any("dangling to" in error for error in errors)) def test_missing_source(self) -> None: snapshot = copy.deepcopy(self.snapshot) snapshot["entities"][0]["sourceRefs"] = ["src:missing"] errors = validate_documents(snapshot, self.manifest) self.assertTrue(any("missing source src:missing" in error for error in errors)) def test_taxonomic_cycle_fails_and_other_cycles_do_not(self) -> None: snapshot = copy.deepcopy(self.snapshot) left = snapshot["entities"][0]["id"] right = snapshot["entities"][1]["id"] source = snapshot["sources"][0]["id"] snapshot["relations"].extend([ { "id": "cycle-a", "predicate": "related-to", "from": left, "to": right, "sourceRefs": [source], }, { "id": "cycle-b", "predicate": "related-to", "from": right, "to": left, "sourceRefs": [source], }, ]) manifest = copy.deepcopy(self.manifest) manifest["relationLabels"]["related-to"] = {"forward": "Related to", "inverse": "Related to"} manifest["acyclicPredicates"] = [] open_cycle = validate_documents(snapshot, manifest) self.assertFalse(any("taxonomic cycle" in error for error in open_cycle)) manifest["acyclicPredicates"] = ["related-to"] closed = validate_documents(snapshot, manifest) self.assertTrue(any("taxonomic cycle" in error for error in closed)) class FactPolicy(unittest.TestCase): def test_missing_unknown_and_conflict(self) -> None: claims = [ {"key": "measure", "status": "unknown", "value": None}, {"key": "name", "status": "asserted", "value": "one"}, {"key": "name", "status": "asserted", "value": "two"}, ] self.assertEqual(resolve_claims(claims, "absent", "show-all")["state"], "missing") self.assertEqual(resolve_claims(claims, "measure", "show-all")["state"], "unknown") shown = resolve_claims(claims, "name", "show-all") self.assertEqual(shown["state"], "contradicted") self.assertEqual(shown["values"], ["one", "two"]) withheld = resolve_claims(claims, "name", "withhold") self.assertEqual(withheld["values"], []) preferred_claims = [ {"key": "name", "status": "asserted", "value": "one", "preferred": True}, {"key": "name", "status": "asserted", "value": "two"}, ] chosen = resolve_claims(preferred_claims, "name", "preferred") self.assertEqual(chosen, {"state": "present", "values": ["one"]}) if __name__ == "__main__": unittest.main()