iter52-卡3:迭代52卡③(presentation层封装修复): A1三类42字段公开化(280处改址)+A2拆件子件公开面(vitals14/motion14/board_hover七口)+B族组合根交接面(18服务+12句柄口,束参两处,on_*保私有)+C族杂项(UiKit三工厂/构造交付)——presentation私取sweep恒零(V1-V4,105checks),main.gd例外键32与ui_kit例外键23落基线(§3.2误测0/0反哺点),探针测试22处引用迁移,渲染golden与探针套件零转红; 验收档中
This commit is contained in:
1 parent
f2c3a3887d
commit
67024cb9ec
42 files changed
+1391
-679
No files matched your search
@@ -145,7 +145,7 @@ func _init() -> void:
|
||||
main._on_step_row({"type": "damage", "target": "hero", "value": 1})
|
||||
main._on_step_row({"type": "heal", "target": "hero", "value": 2})
|
||||
check(main.ui.screens.row_pacer.pending_rows().size() == 2, "会话更替夹具已入队(前提:%d 行)〔wr4〕" % main.ui.screens.row_pacer.pending_rows().size())
|
||||
main._begin_session(false)
|
||||
main.begin_session(false)
|
||||
check(main.ui.screens.row_pacer.pending_rows().is_empty(), "会话更替后待播队列清零(_begin_session 内机制 flush)〔wr4〕")
|
||||
_finish()
|
||||
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
# tests/unit/presentation/presentation_encapsulation_sweep_test.gd — 架构审查 presentation 层封装修复·四族结构性零命中扫描宿主
|
||||
# 断言面(全部带「扫描面非空前置+正锚」——非空防扫描面为空静默绿,正锚证新面在用):
|
||||
# V1 A1 三内部数据类(level_map_screen/_MapState、battle_end_overlay/_EndOverlayState、debug_overlay/_DebugState):
|
||||
# 非空+class 正锚+实例私取模式零命中(_map\._/st\._)+42 公开字段逐个正锚+类名文件外零消费者
|
||||
# V2 A2 拆件子件(standee_body→vitals/motion、board_view→board_hover):
|
||||
# 非空+子件私取模式零命中(st\._/mo\._/_hover_comp\._)+新公开面正锚
|
||||
# V3 B 组合根交接面(main+五分文件):
|
||||
# 非空+root\._ 与 MainXxxFlow\._ 私取零命中+束消费/新公开面正锚
|
||||
# (C 断言组随同批 T5 落地——本件四组齐后为「presentation 私取 sweep 恒零」结构性主证)
|
||||
# 手法沿 encapsulation_sweep_test(5.1 卡)源 token 扫描先例,不并件——扫描面与尾缀语义本批特有(卡 §12 同款论证)。
|
||||
# 运行:godot --headless --path game --script res://tests/unit/presentation/presentation_encapsulation_sweep_test.gd
|
||||
extends SceneTree
|
||||
|
||||
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
const A1_FILES := {
|
||||
"res://presentation/views/level_map_screen.gd": {
|
||||
"cls": "_MapState", "inst": "_map",
|
||||
"fields": ["abandon_timer", "attr_value", "bonus_row", "bonus_value", "canvas", "drawn_disp",
|
||||
"feat_value", "gp_value", "hp_bar", "hp_value", "layer_decor", "level_label", "runner", "title"],
|
||||
},
|
||||
"res://presentation/views/battle_end_overlay.gd": {
|
||||
"cls": "_EndOverlayState", "inst": "st",
|
||||
"fields": ["board_rect", "bonus_name", "bonus_row_l", "bonus_val", "cele", "crest_bricks", "dim",
|
||||
"fx_counts", "ks_name", "ks_row", "ks_val", "rows_box", "seal", "verdict"],
|
||||
},
|
||||
"res://presentation/views/debug_overlay.gd": {
|
||||
"cls": "_DebugState", "inst": "st",
|
||||
"fields": ["atk", "atk_val", "base_atk", "base_hp", "ctx_locked", "db", "eff", "hp", "hp_val",
|
||||
"run_data", "run_labels", "sim_count", "sim_out", "sim_running"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_sweep_a1_data_classes()
|
||||
_sweep_a2_subparts()
|
||||
_sweep_b_combo_root()
|
||||
_sweep_c_misc()
|
||||
quit(Kit.finish("presentation_encapsulation_sweep_test"))
|
||||
|
||||
|
||||
# 源文件读取+非空前置(返 "" 即已判红——调用侧跳过后续正则断言)
|
||||
func _src(path: String) -> String:
|
||||
var src := FileAccess.get_file_as_string(path)
|
||||
Kit.check("扫描面非空前置:%s" % path, src.length() > 0)
|
||||
return src
|
||||
|
||||
|
||||
# 正则零命中断言(-pattern 意图写入断言文案——可 grep 定位;suffix 区分族组)
|
||||
func _zero(pattern: String, src: String, label: String, suffix: String = "pres封装 V1") -> void:
|
||||
var re := RegEx.create_from_string(pattern)
|
||||
Kit.check("%s:%s 零命中〔%s〕" % [label, pattern, suffix], re.search(src) == null)
|
||||
|
||||
|
||||
# 正锚在案断言(正则命中 ≥1——新公开面/新形态在用;suffix 区分族组)
|
||||
func _anchor(pattern: String, src: String, label: String, suffix: String = "pres封装 V1") -> void:
|
||||
var re := RegEx.create_from_string(pattern)
|
||||
Kit.check("%s:%s 正锚在案〔%s〕" % [label, pattern, suffix], re.search(src) != null)
|
||||
|
||||
|
||||
# ② V2 A2 拆件子件(行为归位子件公开方法、读走公开读法、身份构造交付)
|
||||
func _sweep_a2_subparts() -> void:
|
||||
var body := _src("res://presentation/views/standee_body.gd")
|
||||
if body.length() > 0:
|
||||
_zero("\\bst\\._|\\bmo\\._", body, "子件私取模式零命中(standee_body)", "pres封装 V2")
|
||||
_anchor("\\.configure_identity\\(", body, "身份构造交付正锚(standee_body)", "pres封装 V2")
|
||||
_anchor("\\.play_hp_flash\\(", body, "闪白归位正锚(standee_body)", "pres封装 V2")
|
||||
_anchor("\\.show_intent\\(|\\.hide_intent\\(", body, "意图行为正锚(standee_body)", "pres封装 V2")
|
||||
_anchor("mo\\.portrait_sprite\\(\\)", body, "绘制读口正锚(standee_body)", "pres封装 V2")
|
||||
var board := _src("res://presentation/views/board_view.gd")
|
||||
if board.length() > 0:
|
||||
_zero("_hover_comp\\._", board, "子件私取模式零命中(board_view)", "pres封装 V2")
|
||||
_anchor("_hover_comp\\.(rebind|reset|hover_at|detect_chord|refresh_after_paint|on_shell_mouse_exited|hover_pos)",
|
||||
board, "悬停七口正锚(board_view)", "pres封装 V2")
|
||||
|
||||
|
||||
# ③ V3 B 组合根交接面(main+五分文件——成对单行转发梯换代为公开入口+Callable 束)
|
||||
func _sweep_b_combo_root() -> void:
|
||||
var b_files := {
|
||||
"res://presentation/main.gd": false,
|
||||
"res://presentation/main_ui_build.gd": true,
|
||||
"res://presentation/main_adventure_flow.gd": true,
|
||||
"res://presentation/main_overlay_flow.gd": true,
|
||||
"res://presentation/main_debug_flow.gd": true,
|
||||
"res://presentation/main_esc_flow.gd": true,
|
||||
}
|
||||
for path in b_files:
|
||||
var src := _src(path)
|
||||
if src.length() == 0:
|
||||
continue
|
||||
if b_files[path]:
|
||||
_zero("root\\._[a-zA-Z]", src, "root 私取零命中(%s)" % path.get_file(), "pres封装 V3")
|
||||
_zero("Main(Overlay|Adventure|Debug|Esc)Flow\\._[a-zA-Z]", src, "分文件私取零命中(%s)" % path.get_file(), "pres封装 V3")
|
||||
var main_src := FileAccess.get_file_as_string("res://presentation/main.gd")
|
||||
if main_src.length() > 0:
|
||||
for fn in ["set_treasure_ui", "treasure_ui", "set_bonus", "bonus", "set_camp_pres", "camp_pres",
|
||||
"set_debug", "debug", "set_tune_sim", "tune_sim", "set_confirm_consumer", "refresh_presentations",
|
||||
"quit_game", "begin_session", "open_save_select", "seed_value"]:
|
||||
_anchor("func %s\\(" % fn, main_src, "main 公开口正锚(%s)" % fn, "pres封装 V3")
|
||||
var wiring := FileAccess.get_file_as_string("res://presentation/main_ui_build.gd")
|
||||
if wiring.length() > 0:
|
||||
_anchor("handlers\\[\"board_action\"\\]", wiring, "束消费正锚(ui_build)", "pres封装 V3")
|
||||
_anchor("root\\.set_treasure_ui\\(", wiring, "句柄设置口正锚(ui_build)", "pres封装 V3")
|
||||
_anchor("root\\.camp_pres\\(\\)\\.", wiring, "句柄读投影正锚(ui_build)", "pres封装 V3")
|
||||
var adv := FileAccess.get_file_as_string("res://presentation/main_adventure_flow.gd")
|
||||
if adv.length() > 0:
|
||||
_anchor("handlers\\[\"adventure_finished\"\\]", adv, "束消费正锚(adventure)", "pres封装 V3")
|
||||
_anchor("root\\.bonus\\(\\)\\.", adv, "句柄读投影正锚(adventure)", "pres封装 V3")
|
||||
|
||||
|
||||
# ④ V4 C 杂项(UiKit 私有工厂公开化+cell_mark 构造交付)
|
||||
func _sweep_c_misc() -> void:
|
||||
var offenders: PackedStringArray = []
|
||||
var scanned := 0
|
||||
_walk_gd_for("res://", "UiKit\\._[a-zA-Z]", "res://presentation/views/ui_kit.gd", offenders)
|
||||
scanned = _scanned
|
||||
Kit.check("UiKit 私有工厂全库零外调(扫描面 %d 件非空前置;越界=%s)〔pres封装 V4〕"
|
||||
% [scanned, str(offenders)], offenders.is_empty())
|
||||
var cm := _src("res://presentation/views/cell_mark_overlay.gd")
|
||||
if cm.length() > 0:
|
||||
_zero("_owner\\._", cm, "宿主私有回引零命中(cell_mark_overlay)", "pres封装 V4")
|
||||
_anchor("_mask_set\\.is_valid\\(\\)", cm, "构造交付正锚(cell_mark_overlay)", "pres封装 V4")
|
||||
var uk := _src("res://presentation/views/ui_kit.gd")
|
||||
if uk.length() > 0:
|
||||
_anchor("func (gradient_base|beams_rect|switch_toggle)\\(", uk, "三工厂公开正锚(ui_kit)", "pres封装 V4")
|
||||
|
||||
|
||||
func _walk_gd_for(dir_path: String, pattern: String, exclude: String, offenders: PackedStringArray) -> void:
|
||||
var re := RegEx.create_from_string(pattern)
|
||||
var dir := DirAccess.open(dir_path)
|
||||
if dir == null:
|
||||
return
|
||||
dir.list_dir_begin()
|
||||
var name := dir.get_next()
|
||||
while name != "":
|
||||
var full := dir_path.path_join(name)
|
||||
if dir.current_is_dir():
|
||||
if not name.begins_with("."):
|
||||
_walk_gd_for(full, pattern, exclude, offenders)
|
||||
elif name.ends_with(".gd") and full != exclude:
|
||||
_scanned += 1
|
||||
if re.search(FileAccess.get_file_as_string(full)) != null:
|
||||
offenders.append(full)
|
||||
name = dir.get_next()
|
||||
dir.list_dir_end()
|
||||
|
||||
|
||||
# ① V1 A1 三内部数据类(字段公开化——宿主直读写内类私有字段清零)
|
||||
func _sweep_a1_data_classes() -> void:
|
||||
for path in A1_FILES:
|
||||
var spec: Dictionary = A1_FILES[path]
|
||||
var src := _src(path)
|
||||
if src.length() == 0:
|
||||
continue
|
||||
var cls: String = spec["cls"]
|
||||
var inst: String = spec["inst"]
|
||||
_anchor("class %s" % cls, src, "class 正锚(%s)" % cls)
|
||||
_zero("%s\\._[a-zA-Z]" % inst, src, "实例私取模式零命中(%s.%s)" % [path.get_file(), inst])
|
||||
for field in spec["fields"]:
|
||||
_anchor("\\.%s\\b" % field, src, "公开字段正锚(%s.%s)" % [cls, field])
|
||||
# 类名文件外零消费者:全 game/ .gd 递归扫描(排除三类宿主文件与本测试件自身——本件源文本含类名 token)
|
||||
var hosts := ["res://presentation/views/level_map_screen.gd",
|
||||
"res://presentation/views/battle_end_overlay.gd", "res://presentation/views/debug_overlay.gd"]
|
||||
var offenders: PackedStringArray = []
|
||||
_walk_gd("res://", hosts, offenders)
|
||||
Kit.check("A1 三类文件外零消费者(全 game/ .gd 扫描面 %d 件非空前置;越界=%s)"
|
||||
% [_scanned, str(offenders)], offenders.is_empty())
|
||||
|
||||
|
||||
var _scanned := 0
|
||||
|
||||
|
||||
func _walk_gd(dir_path: String, exclude: Array, offenders: PackedStringArray) -> void:
|
||||
var dir := DirAccess.open(dir_path)
|
||||
if dir == null:
|
||||
return
|
||||
dir.list_dir_begin()
|
||||
var name := dir.get_next()
|
||||
while name != "":
|
||||
var full := dir_path.path_join(name)
|
||||
if dir.current_is_dir():
|
||||
if not name.begins_with("."):
|
||||
_walk_gd(full, exclude, offenders)
|
||||
elif name.ends_with(".gd") and not exclude.has(full) and not full.contains("presentation_encapsulation_sweep_test"):
|
||||
_scanned += 1
|
||||
var src := FileAccess.get_file_as_string(full)
|
||||
for cls in ["_MapState", "_EndOverlayState", "_DebugState"]:
|
||||
if src.contains(cls):
|
||||
offenders.append("%s:%s" % [full, cls])
|
||||
name = dir.get_next()
|
||||
dir.list_dir_end()
|
||||
@@ -0,0 +1 @@
|
||||
uid://bk88rqu43srjn
|
||||
@@ -0,0 +1,52 @@
|
||||
# tests/unit/presentation/seal_mark_params_test.gd — 封印印记参数化绘制守门(卡④ R1–R4)
|
||||
# 断言面:五常量取值逐项相等(ui_kit ↔ art-bible §8.2 对照);着色器文件存在且七个 uniform 名在文;
|
||||
# 迷雾门控(seal_on × fog_state → 封印子件可见性)〔seal批 V1–V4〕。
|
||||
# 运行:godot --headless --path game --script res://tests/unit/presentation/seal_mark_params_test.gd
|
||||
extends SceneTree
|
||||
|
||||
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
const SEAL_SHADER := "res://presentation/views/seal_mark.gdshader"
|
||||
const CELL_UNIT := preload("res://presentation/views/board_cell_unit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_test_param_values()
|
||||
_test_shader_uniforms()
|
||||
_test_fog_gate()
|
||||
quit(Kit.finish("seal_mark_params_test"))
|
||||
|
||||
|
||||
# R1–R3/R7 前置:五常量取值逐项相等(art-bible §8.2 定值)
|
||||
func _test_param_values() -> void:
|
||||
Kit.check("SEAL_RING_FRAC = 0.82〔seal批 V1〕", UiKit.SEAL_RING_FRAC == 0.82)
|
||||
Kit.check("SEAL_WALL_FRAC = 0.11〔seal批 V2〕", UiKit.SEAL_WALL_FRAC == 0.11)
|
||||
Kit.check("SEAL_ARM_FRAC = 0.156〔seal批 V2〕", UiKit.SEAL_ARM_FRAC == 0.156)
|
||||
Kit.check("SEAL_HALO_ALPHA = 0.50〔seal批 V3〕", UiKit.SEAL_HALO_ALPHA == 0.50)
|
||||
Kit.check("SEAL_HALO_GAMMA = 1.6〔seal批 V3〕", UiKit.SEAL_HALO_GAMMA == 1.6)
|
||||
|
||||
|
||||
# R1–R3/R7:着色器存在+七个 uniform 名在文(参数注入面契约)
|
||||
func _test_shader_uniforms() -> void:
|
||||
var src := FileAccess.get_file_as_string(SEAL_SHADER)
|
||||
Kit.check("着色器文件存在且非空:%s〔seal批 V1〕" % SEAL_SHADER, src.length() > 0)
|
||||
if src.length() == 0:
|
||||
return
|
||||
for uniform in ["cell_px", "ring_frac", "wall_frac", "arm_frac", "halo_frac", "halo_alpha", "halo_gamma", "mark_col"]:
|
||||
Kit.check("着色器 uniform 在文:%s〔seal批 V1〕" % uniform, src.contains(uniform))
|
||||
Kit.check("着色器含光圈半径夹取行(r ≤ cell_px/2——光圈不出格)〔seal批 V3〕",
|
||||
src.contains("min(r, cell_px * 0.5)"))
|
||||
|
||||
|
||||
# R4 迷雾门控:seal_on × fog_state → 封印子件可见性(内部字段直查=受控例外——子件可见性无公开可观测面,
|
||||
# 卡面 R4 断言即 prescribe 子件 visible 直查;对照表该行注记理由)
|
||||
func _test_fog_gate() -> void:
|
||||
var u: Node2D = CELL_UNIT.new()
|
||||
u.seal_on = true
|
||||
Kit.check("seal_on 即挂封印子件〔seal批 V4〕", u._seal_layer != null)
|
||||
u.fog_state = 1
|
||||
Kit.check("雾态(fog_state=1)封印子件不可见〔seal批 V4〕", u._seal_layer.visible == false)
|
||||
u.fog_state = 0
|
||||
Kit.check("非雾态(fog_state=0)封印子件可见〔seal批 V4〕", u._seal_layer.visible == true)
|
||||
u.seal_on = false
|
||||
Kit.check("撤 seal_on 即撤子件〔seal批 V4〕", u._seal_layer == null)
|
||||
u.free()
|
||||
@@ -0,0 +1 @@
|
||||
uid://cc7y2oxe2d15p
|
||||
@@ -161,5 +161,5 @@ func _test_beams_retired() -> void:
|
||||
not cmap.has("BEAM_LIGHT") and not cmap.has("STAGE_BG"))
|
||||
var uf := FileAccess.open("res://presentation/views/ui_kit.gd", FileAccess.READ)
|
||||
var usrc := uf.get_as_text() if uf != null else ""
|
||||
Kit.check("菜单斜光带 _beams_rect 仍在(不在退役面)〔舞台背景 V5〕",
|
||||
usrc.contains("_beams_rect"))
|
||||
Kit.check("菜单斜光带 beams_rect 仍在(不在退役面)〔舞台背景 V5〕",
|
||||
usrc.contains("beams_rect"))
|
||||
@@ -623,7 +623,7 @@ func _smoke_texture_filter() -> void:
|
||||
Kit.check("V3 白名单在位:暗角 vignette 显式 LINEAR",
|
||||
vg.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
||||
vg.free()
|
||||
var bm = uikit_s._beams_rect()
|
||||
var bm = uikit_s.beams_rect()
|
||||
Kit.check("V3 白名单在位:光柱 beams 显式 LINEAR",
|
||||
bm.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
||||
# T4 光柱连续 alpha 结构断言(观感归目检):带心峰值 0.05/带缘连续过渡/纵向衰减上亮下暗
|
||||
@@ -648,7 +648,7 @@ func _smoke_texture_filter() -> void:
|
||||
Kit.check("T4 光柱纵向衰减生效(上半亮度 %.0f > 下半 %.0f 的 2 倍——上亮下暗)" % [top_sum, bot_sum],
|
||||
top_sum > bot_sum * 2.0)
|
||||
bm.free()
|
||||
var gb = uikit_s._gradient_base(Color.BLACK, Color.WHITE)
|
||||
var gb = uikit_s.gradient_base(Color.BLACK, Color.WHITE)
|
||||
Kit.check("V3 白名单在位:地图渐变 gradient_base 显式 LINEAR",
|
||||
gb.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
||||
gb.free()
|
||||
|
||||
Reference in new issue
Block a user