"""B2.5:不同 Provider 形态、Tile ID 作用域和 PRIMARY 审核门禁。""" from __future__ import annotations import importlib.util from pathlib import Path import tempfile import unittest from mapbox_vector_tile.Mapbox import vector_tile_pb2 BASE = Path(__file__).resolve().parents[1] MODULE_FILE = BASE / "tools/provider-pipeline/feature_identity_scope_audit.py" spec = importlib.util.spec_from_file_location("feature_identity_scope_audit", MODULE_FILE) module = importlib.util.module_from_spec(spec) assert spec and spec.loader spec.loader.exec_module(module) def write_tile(root: Path, tile: str, source_layer: str, feature_ids: list[int | None], *, property_value: str | None = None): obj = vector_tile_pb2.tile() layer = obj.layers.add() layer.name = source_layer layer.version = 2 layer.extent = 4096 if property_value is not None: layer.keys.append("sampleLabel") prop = layer.values.add() prop.string_value = property_value for fid in feature_ids: feature = layer.features.add() if fid is not None: feature.id = fid feature.type = 1 feature.geometry.extend([9, 0, 0]) if property_value is not None: feature.tags.extend([0, 0]) target = root / f"{tile}.pbf" target.parent.mkdir(parents=True, exist_ok=True) target.write_bytes(obj.SerializeToString()) def visual_object(name: str, tile: str, source_layer: str, fid: int | None): return { "visual_object_id": name, "provenance": {"source_layer": source_layer}, "example": {"tile": tile, "feature_id": fid}, "components": [{"style_layer_id": "shape", "style_index": 0, "role": "icon", "resource_key": "X"}], } class FeatureIdentityScopeTests(unittest.TestCase): def test_two_provider_field_independent_tile_scoped_locator(self): for source, layer, label in (("alpha", "points", "VO-A"), ("other-provider", "objects", "VO-B")): with self.subTest(source=source), tempfile.TemporaryDirectory() as folder: root = Path(folder) write_tile(root, "1/0/0", layer, [7, 8]) style = {"layers": [{"id": "shape", "source": source, "source-layer": layer}]} mapping = {"assignments": [{"visualObjectId": label, "status": "LAYER_ONLY", "standardLayer": "navigation_marks"}]} audit = module.audit_scope( {"visual_objects": [visual_object(label, "1/0/0", layer, 7)]}, style, root, provider_id=source, dataset_id="d1", mapping=mapping, ) self.assertEqual(audit["exampleLocatorStatusCounts"], {"TILE_LOCAL_LOCATOR_CONFIRMED": 1}) self.assertEqual(audit["fidScope"], "unknown") row = audit["reviewQueue"][0] self.assertEqual(row["tileLocalFeatureLocator"]["sourceId"], source) self.assertIsNone(row["stableEntityId"]) self.assertIsNone(row["primaryStyleComponentIndex"]) self.assertEqual(row["primaryReviewStatus"], "PENDING_REVIEW") self.assertFalse(row["pickupDeduplicationAuthorized"]) self.assertEqual(row["assignmentStatus"], "LAYER_ONLY") def test_reused_raw_id_across_tiles_not_global_claim(self): with tempfile.TemporaryDirectory() as folder: root = Path(folder) write_tile(root, "1/0/0", "objects", [33], property_value="north") write_tile(root, "1/1/0", "objects", [33], property_value="south") style = {"layers": [{"id": "shape", "source": "beta", "source-layer": "objects"}]} catalog = {"visual_objects": [ visual_object("VO-A", "1/0/0", "objects", 33), visual_object("VO-B", "1/1/0", "objects", 33), ]} out = module.audit_scope(catalog, style, root, provider_id="beta", dataset_id="d") self.assertEqual(out["reusedRawFeatureIdAcrossExaminedTiles"], 1) self.assertEqual(out["reusedRawFeatureIdWithDifferingProperties"], 1) self.assertEqual(out["exampleLocatorStatusCounts"], {"TILE_LOCAL_LOCATOR_CONFIRMED": 2}) self.assertEqual(out["globalIdentityAuthorizedCount"], 0) self.assertNotEqual( out["reviewQueue"][0]["tileLocalFeatureLocator"]["x"], out["reviewQueue"][1]["tileLocalFeatureLocator"]["x"], ) def test_duplicate_raw_id_same_tile_blocked(self): with tempfile.TemporaryDirectory() as folder: root = Path(folder) write_tile(root, "1/0/0", "objects", [12, 12]) catalog = {"visual_objects": [visual_object("VO-A", "1/0/0", "objects", 12)]} style = {"layers": [{"id": "shape", "source": "beta", "source-layer": "objects"}]} out = module.audit_scope(catalog, style, root, provider_id="beta", dataset_id="d") self.assertEqual(out["exampleLocatorStatusCounts"], {"FEATURE_ID_AMBIGUOUS": 1}) self.assertEqual(out["examinedTileRawFeatureStats"]["duplicateFeatureIdValues"], 1) self.assertIsNone(out["reviewQueue"][0]["tileLocalFeatureLocator"]) def test_missing_id_or_ambiguous_source_remains_unknown(self): with tempfile.TemporaryDirectory() as folder: root = Path(folder) write_tile(root, "1/0/0", "objects", [None]) obj = visual_object("VO-A", "1/0/0", "objects", None) style = {"layers": [{"id": "shape", "source": "beta", "source-layer": "objects"}]} out = module.audit_scope({"visual_objects": [obj]}, style, root, provider_id="beta", dataset_id="d") self.assertEqual(out["exampleLocatorStatusCounts"], {"FEATURE_ID_UNAVAILABLE": 1}) obj["example"]["feature_id"] = 7 style["layers"].append({"id": "other", "source": "gamma", "source-layer": "objects"}) out = module.audit_scope({"visual_objects": [obj]}, style, root, provider_id="beta", dataset_id="d") self.assertEqual(out["exampleLocatorStatusCounts"], {"STYLE_SOURCE_SCOPE_UNPROVEN": 1}) def test_two_visual_types_claiming_same_raw_feature_block_both(self): with tempfile.TemporaryDirectory() as folder: root = Path(folder) write_tile(root, "1/0/0", "objects", [42]) style = {"layers": [{"id": "shape", "source": "beta", "source-layer": "objects"}]} catalog = {"visual_objects": [ visual_object("VO-A", "1/0/0", "objects", 42), visual_object("VO-B", "1/0/0", "objects", 42), ]} out = module.audit_scope(catalog, style, root, provider_id="beta", dataset_id="d") self.assertEqual( out["exampleLocatorStatusCounts"], {"EXAMPLE_LOCATOR_SHARED_BY_VISUAL_TYPES": 2}, ) self.assertTrue(all(row["tileLocalFeatureLocator"] is None for row in out["reviewQueue"])) self.assertTrue(all(row["identityScope"] == "UNVERIFIED" for row in out["reviewQueue"])) def test_invalid_tile_and_duplicate_visual_type_rejected(self): obj = visual_object("VO-A", "../1/0", "objects", 10) with self.assertRaisesRegex(ValueError, "路径"): module.audit_scope({"visual_objects": [obj]}, {"layers": []}, Path("/tmp"), provider_id="p", dataset_id="d") obj["example"]["tile"] = "1/0/0" with self.assertRaisesRegex(ValueError, "重复"): module.audit_scope({"visual_objects": [obj, obj]}, {"layers": []}, Path("/tmp"), provider_id="p", dataset_id="d") if __name__ == "__main__": unittest.main()