|
|
@@ -0,0 +1,100 @@
|
|
|
+import re
|
|
|
+from pathlib import Path
|
|
|
+
|
|
|
+
|
|
|
+ROOT = Path(__file__).resolve().parents[1]
|
|
|
+ROUTES = ROOT / "frontend/src/router/routes.js"
|
|
|
+
|
|
|
+
|
|
|
+def _route_block(source: str, *, indent: int, name: str) -> str:
|
|
|
+ start_token = "\n" + " " * indent + "{\n"
|
|
|
+ name_token = " " * (indent + 2) + f"name: '{name}'"
|
|
|
+ assert name_token in source, f"route {name!r} marker not found"
|
|
|
+ name_at = source.index(name_token)
|
|
|
+ start = source.rfind(start_token, 0, name_at)
|
|
|
+ if start >= 0:
|
|
|
+ start += 1
|
|
|
+ elif source.startswith(start_token[1:]):
|
|
|
+ start = 0
|
|
|
+ terminators = [
|
|
|
+ "\n" + " " * indent + "},",
|
|
|
+ "\n" + " " * indent + "}",
|
|
|
+ ]
|
|
|
+ ends = [(source.find(token, name_at), token) for token in terminators]
|
|
|
+ valid_ends = [(end, token) for end, token in ends if end >= 0]
|
|
|
+ assert start >= 0 and valid_ends, f"route {name!r} block boundaries not found"
|
|
|
+ end, end_token = min(valid_ends)
|
|
|
+ return source[start : end + len(end_token)]
|
|
|
+
|
|
|
+
|
|
|
+def _assert_exact_line(block: str, *, indent: int, field: str, value: str) -> None:
|
|
|
+ expected = " " * indent + f"{field}: {value}"
|
|
|
+ assert re.search(rf"(?m)^{re.escape(expected)},?$", block), f"missing exact line: {expected}"
|
|
|
+
|
|
|
+
|
|
|
+def _meta_block(route: str, *, indent: int) -> str:
|
|
|
+ start_token = "\n" + " " * indent + "meta: {\n"
|
|
|
+ end_token = "\n" + " " * indent + "},"
|
|
|
+ start = route.find(start_token)
|
|
|
+ end = route.find(end_token, start)
|
|
|
+ assert start >= 0 and end >= 0, "route meta block boundaries not found"
|
|
|
+ return route[start + 1 : end + len(end_token)]
|
|
|
+
|
|
|
+
|
|
|
+def test_enterprise_identity_is_owned_only_by_system_management():
|
|
|
+ routes = ROUTES.read_text(encoding="utf-8")
|
|
|
+ data_research = _route_block(routes, indent=4, name="data-governance")
|
|
|
+ system = _route_block(routes, indent=4, name="systemManage")
|
|
|
+
|
|
|
+ assert "systemEnterpriseIdentity" not in data_research
|
|
|
+ assert "path: '/systemManage/enterprise-identity'" not in data_research
|
|
|
+ assert "component: 'systemManage/enterpriseIdentity'" not in data_research
|
|
|
+ assert routes.count("name: 'systemEnterpriseIdentity'") == 1
|
|
|
+ assert routes.count("path: '/systemManage/enterprise-identity'") == 1
|
|
|
+ assert routes.count("component: 'systemManage/enterpriseIdentity'") == 1
|
|
|
+
|
|
|
+ identity = _route_block(system, indent=8, name="systemEnterpriseIdentity")
|
|
|
+ for field, value in [
|
|
|
+ ("hidden", "0"),
|
|
|
+ ("type", "1"),
|
|
|
+ ("title", "'企业身份与 SSO'"),
|
|
|
+ ("path", "'/systemManage/enterprise-identity'"),
|
|
|
+ ("children", "[]"),
|
|
|
+ ("label", "'企业身份与 SSO'"),
|
|
|
+ ("sort", "2"),
|
|
|
+ ("component", "'systemManage/enterpriseIdentity'"),
|
|
|
+ ("name", "'systemEnterpriseIdentity'"),
|
|
|
+ ("alwaysShow", "0"),
|
|
|
+ ]:
|
|
|
+ _assert_exact_line(identity, indent=10, field=field, value=value)
|
|
|
+
|
|
|
+ meta = _meta_block(identity, indent=10)
|
|
|
+ for field, value in [
|
|
|
+ ("title", "'企业身份与 SSO'"),
|
|
|
+ ("icon", "'mdi-account-key-outline'"),
|
|
|
+ ("permissions", "['identity:manage']"),
|
|
|
+ ]:
|
|
|
+ _assert_exact_line(meta, indent=12, field=field, value=value)
|
|
|
+
|
|
|
+
|
|
|
+def test_system_management_navigation_order_is_stable():
|
|
|
+ routes = ROUTES.read_text(encoding="utf-8")
|
|
|
+ system = _route_block(routes, indent=4, name="systemManage")
|
|
|
+ names = [
|
|
|
+ "systemUserManage",
|
|
|
+ "systemEnterpriseIdentity",
|
|
|
+ "systemResponsibilityManage",
|
|
|
+ "systemGovernanceAudit",
|
|
|
+ "systemAgentGovernance",
|
|
|
+ ]
|
|
|
+ for name in names:
|
|
|
+ assert routes.count(f"name: '{name}'") == 1
|
|
|
+ positions = []
|
|
|
+ for name in names:
|
|
|
+ marker = f"name: '{name}'"
|
|
|
+ assert marker in system, f"System Management is missing route {name!r}"
|
|
|
+ positions.append(system.index(marker))
|
|
|
+ assert positions == sorted(positions)
|
|
|
+ for expected, name in enumerate(names, start=1):
|
|
|
+ block = _route_block(system, indent=8, name=name)
|
|
|
+ assert re.search(rf"(?m)^\s+sort: {expected},?$", block)
|