# 致命类用例(独立进程,期望退出码 1) # treasure_target_violation——真视窄域护栏(秘宝 GDD 结构冻结):真视类行 target # 越域至 board_wide 时,TreasureItemTable.validate 必须报 load_bearing 错、load_tables 整体拒绝。 # 注入主语 = sky_eye(真视行 reveal_tiles);护栏本体 = mine_reveal/reveal_tiles 两 kind 同守 REVEAL_KINDS。 # 运行:godot --headless --path game --script res://tests/unit/data_config/treasure_target_violation_test.gd # 退出码协议:1 = 校验正确拒绝(预期);2 = 违规表被放行(回归信号)。 # 时序注:纯加载期校验——不触运行期 fatal 通道,断言 load_tables 返回 false + 诊断在案即 quit(1)。 extends SceneTree const ConfigDBScript := preload("res://core/config_db.gd") const Kit := preload("res://tests/unit/test_kit.gd") # T6 收口:BAD 表目录夹具共享(copy_tables) const SRC_DIR := "res://data/tables" const BAD_DIR := "user://treasure_fixture_target_violation" func _inject_violation() -> bool: var path := BAD_DIR + "/treasure_items.tres" var f := FileAccess.open(path, FileAccess.READ) if f == null: return false var s := f.get_as_text() f.close() # 直接改 target:天眼行是全表唯一的 reveal_tiles 真视行——把它的 area_3x3 改 board_wide # (护栏扩面后真视类 kind 全守——越域行命中 REVEAL_KINDS 护栏) var blocks := s.split("}, {") var hit := false for i in blocks.size(): if '"item_id": "sky_eye"' in blocks[i]: blocks[i] = blocks[i].replace('"target": "area_3x3"', '"target": "board_wide"') hit = true s = "}, {".join(blocks) var w := FileAccess.open(path, FileAccess.WRITE) if w == null or not hit: return false w.store_string(s) w.close() return true func _init() -> void: if not Kit.copy_tables(SRC_DIR, BAD_DIR) or not _inject_violation(): push_error("[treasure_target_violation_test] 夹具目录准备失败") quit(2) return var db = ConfigDBScript.new() var ok: bool = db.load_tables(BAD_DIR, false) if ok: push_error("[treasure_target_violation_test] 违规表被放行——真视窄域护栏失守(回归)") quit(2) return if db.diagnostics_count("error") >= 1: print("[treasure_target_violation_test] 护栏触发(load_bearing 诊断在案,加载被拒)") quit(1) return push_error("[treasure_target_violation_test] 加载被拒但无 load_bearing 诊断——护栏通道静默化(回归)") quit(2)