Files
pbf/tests/test_mapping_execution_evidence_audit.py

108 lines
5.0 KiB
Python

"""通用 Mapping 证据审计:两种不同 Provider 结构及 fail-closed 规则。"""
import importlib.util
import json
from pathlib import Path
import unittest
ROOT = Path(__file__).resolve().parents[1]
path = ROOT / "tools/provider-pipeline/mapping_execution_evidence_audit.py"
spec = importlib.util.spec_from_file_location("audit_mapping_module", path)
audit = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(audit)
def item(identity, standard, status, layer_indexes, style, keys):
return {
"visualObjectId": identity, "status": status, "standardLayer": standard,
"renderEvidence": {
"sourceLayer": style["layers"][layer_indexes[0]]["source-layer"],
"geometryRole": "Point", "occurrenceCount": 1,
"components": [
{"styleIndex": index, "styleLayerId": style["layers"][index]["id"],
"role": "icon" if style["layers"][index]["layout"].get("icon-image") else "text",
"resourceKey": key}
for index, key in zip(layer_indexes, keys)
],
},
}
class EvidenceAuditTests(unittest.TestCase):
def test_provider_a_direct_and_unknown_mixed_layer_preserved(self):
style = {"layers": [{"id": "icons", "source": "alpha", "source-layer": "features",
"layout": {"icon-image": ["get", "symbol"]}}]}
mapping = {"assignments": [
item("a", "navigation_marks", "LAYER_ONLY", [0], style, ["BOY"]),
item("b", None, "UNKNOWN", [0], style, ["ALIEN"]),
]}
result = audit.audit_mapping(style, mapping)
self.assertEqual(result["mappingObjectCount"], 2)
self.assertEqual(result["executionAuthorizedCount"], 0)
self.assertEqual(result["mixedStyleLayerIds"], ["icons"])
a = result["records"][0]
self.assertEqual(a["renderComponents"][0]["candidateSelector"], ["==", ["get", "symbol"], "BOY"])
self.assertIn("STANDARD_TO_DISPLAY_GROUP_CONTRACT_UNBOUND", a["blockingReasons"])
self.assertIn("UNRESOLVED_CLASSIFICATION", result["records"][1]["blockingReasons"])
def test_provider_b_other_field_multiple_components_and_inheritance(self):
style = {"layers": [
{"id": "mark-draw", "source": "beta", "source-layer": "objects",
"layout": {"icon-image": ["get", "pictogram"]}},
{"id": "mark-label", "source": "beta", "source-layer": "objects",
"layout": {"text-field": ["get", "label"]}},
]}
mapping = {"assignments": [
item("a", "facility_boundary_point", "VISUAL_OBJECT_MATCH", [0, 1],
style, ["P", None]),
]}
result = audit.audit_mapping(style, mapping)
entry = result["records"][0]
self.assertEqual(entry["renderComponents"][0]["candidateSelector"],
["==", ["get", "pictogram"], "P"])
self.assertEqual(entry["renderComponents"][1]["selectorEvidence"], "UNPROVED")
self.assertIn("MULTI_COMPONENT_IDENTITY_UNVERIFIED", entry["blockingReasons"])
self.assertIn("INHERITANCE_REQUIRES_SAME_FEATURE_PROOF", entry["blockingReasons"])
self.assertFalse(entry["executionAuthorized"])
def test_cross_layer_contradiction_and_invalid_style_index_fail_closed(self):
style = {"layers": [
{"id": "one", "source": "beta", "source-layer": "objects",
"layout": {"icon-image": ["get", "icon"]}},
{"id": "two", "source": "beta", "source-layer": "objects",
"layout": {"icon-image": ["get", "icon"]}},
]}
mapping = {"assignments": [
item("a", "mark", "LAYER_ONLY", [0, 1], style, ["A", "B"]),
]}
result = audit.audit_mapping(style, mapping)
self.assertIn("CONTRADICTORY_RESOURCE_FIELDS",
result["records"][0]["blockingReasons"])
mapping["assignments"][0]["renderEvidence"]["components"][0]["styleIndex"] = 99
with self.assertRaisesRegex(ValueError, "索引无效"):
audit.audit_mapping(style, mapping)
def test_style_sha256_binding_fails_closed(self):
import hashlib
sample = b'{"layers":[]}'
digest = hashlib.sha256(sample).hexdigest()
mapping = {"renderEvidenceSource": {"styleSha256": digest}}
audit.verify_mapping_style_fingerprint(mapping, sample)
with self.assertRaisesRegex(ValueError, "不匹配"):
audit.verify_mapping_style_fingerprint(mapping, b'{"layers":[1]}')
with self.assertRaisesRegex(ValueError, "缺失"):
audit.verify_mapping_style_fingerprint({"renderEvidenceSource": {}}, sample)
def test_duplicate_visual_id_fails_closed(self):
style = {"layers": []}
mapping = {"assignments": [
{"visualObjectId": "same", "status": "UNKNOWN"},
{"visualObjectId": "same", "status": "UNKNOWN"},
]}
with self.assertRaisesRegex(ValueError, "重复"):
audit.audit_mapping(style, mapping)
if __name__ == "__main__":
unittest.main()