test_app_dependency_graph.py (4007B)
1 from __future__ import annotations 2 3 import copy 4 import json 5 import sys 6 import unittest 7 from pathlib import Path 8 9 SCRIPTS = Path(__file__).resolve().parent 10 if str(SCRIPTS) not in sys.path: 11 sys.path.insert(0, str(SCRIPTS)) 12 13 import app_dependency_graph as graph # noqa: E402 14 import package_contract as contract # noqa: E402 15 16 17 class AppDependencyGraphTests(unittest.TestCase): 18 @classmethod 19 def setUpClass(cls) -> None: 20 cls.root = SCRIPTS.parent 21 cls.metadata = contract._cargo_workspace(cls.root, resolved=True) 22 cls.foundation = contract._read_toml( 23 cls.root / "radroots.lib.source-lock.v1.toml" 24 ) 25 26 def test_actual_locked_application_graph(self) -> None: 27 graph.validate(self.metadata, self.foundation) 28 29 def test_actual_graph_rejects_retired_producer_and_duplicate_resolution( 30 self, 31 ) -> None: 32 for name in graph.RETIRED: 33 with self.subTest(name=name): 34 changed = copy.deepcopy(self.metadata) 35 changed["packages"].append({"id": "retired", "name": name}) 36 with self.assertRaisesRegex(graph.GraphError, "retired"): 37 graph.validate(changed, self.foundation) 38 changed = copy.deepcopy(self.metadata) 39 changed["packages"].append(changed["packages"][0]) 40 with self.assertRaisesRegex(graph.GraphError, "duplicated"): 41 graph.validate(changed, self.foundation) 42 43 def test_actual_shared_resolution_rejects_pin_version_and_local_override( 44 self, 45 ) -> None: 46 for field, value in ( 47 ("source", None), 48 ("source", "git+https://example.invalid/lib"), 49 ("version", "9.9.9"), 50 ): 51 with self.subTest(field=field, value=value): 52 changed = copy.deepcopy(self.metadata) 53 package = next( 54 p for p in changed["packages"] if p["name"] == "radroots_sdk" 55 ) 56 package[field] = value 57 with self.assertRaisesRegex(graph.GraphError, "foundation"): 58 graph.validate(changed, self.foundation) 59 60 def test_default_lane_rejects_wasm_or_omitted_native_package(self) -> None: 61 wasm = next( 62 p["id"] for p in self.metadata["packages"] if p["name"] == "tera_wasm" 63 ) 64 for defaults in ( 65 [], 66 self.metadata["workspace_default_members"][:-1], 67 [*self.metadata["workspace_default_members"], wasm], 68 ): 69 with self.subTest(defaults=defaults): 70 changed = {**self.metadata, "workspace_default_members": defaults} 71 with self.assertRaisesRegex(graph.GraphError, "mobile defaults"): 72 graph.validate(changed, self.foundation) 73 74 def test_mobile_profile_requires_executable_ffi_edge(self) -> None: 75 changed = copy.deepcopy(self.metadata) 76 ffi = next(p for p in changed["packages"] if p["name"] == "tera_ffi") 77 edge = next(d for d in ffi["dependencies"] if d["name"] == "tera_core") 78 edge["features"] = [] 79 with self.assertRaisesRegex(graph.GraphError, "mobile-social"): 80 graph.validate(changed, self.foundation) 81 82 def test_mobile_profile_requires_resolved_feature(self) -> None: 83 changed = copy.deepcopy(self.metadata) 84 core = next(p["id"] for p in changed["packages"] if p["name"] == "tera_core") 85 node = next(n for n in changed["resolve"]["nodes"] if n["id"] == core) 86 node["features"] = [] 87 with self.assertRaisesRegex(graph.GraphError, "mobile-social"): 88 graph.validate(changed, self.foundation) 89 90 def test_resolution_is_required_and_machine_readable(self) -> None: 91 changed = json.loads(json.dumps(self.metadata)) 92 changed["resolve"] = None 93 with self.assertRaisesRegex(graph.GraphError, "resolved dependency graph"): 94 graph.validate(changed, self.foundation) 95 96 97 if __name__ == "__main__": 98 unittest.main()