101 lines
5.1 KiB
GDScript
101 lines
5.1 KiB
GDScript
# tests/unit/contracts/source_guard_test.gd — 仓库自身源码契约单元测试宿主
|
||
# 断言面 = 两套(批 B 断言迁移自 smoke_all.gd,G12 施工组;被测对象=仓库自身源文件,
|
||
# 主会话裁决五新设 source_guard 子目录归「契约」语义):
|
||
# 类型闸(project.godot warning 配置在位 + 审计器闸机接线)
|
||
# 卫生件 grep 闸(产品码字符串 Callable/死代码/GP 影子账残留零命中 + 层序落位单口)
|
||
# 协议照单元侧惯例:extends SceneTree+Kit.check 主通道;被测面是仓库文件直读
|
||
# (FileAccess/DirAccess/project.godot 设置),零表夹具零 RNG。
|
||
# 运行:godot --headless --path game --script res://tests/unit/contracts/source_guard_test.gd
|
||
extends SceneTree
|
||
|
||
const Kit := preload("res://tests/unit/test_kit.gd")
|
||
|
||
|
||
func _init() -> void:
|
||
# 套执行序沿源编排序(_split_tail 尾段调用序)
|
||
_smoke_type_gate()
|
||
_smoke_hygiene_gates()
|
||
quit(Kit.finish("source_guard_test"))
|
||
|
||
|
||
# ---- 类型闸断言(V7——project.godot warning 配置在位〔源码断言〕+审计器脚本在位;
|
||
# 审计器归零判定走 static_scan S9 闸机,此处兜配置面)----
|
||
func _smoke_type_gate() -> void:
|
||
# oracle: design/engineering/code-conventions.md:41(封装边界——类型闸源码扫描组)
|
||
var pj: String = FileAccess.get_file_as_string("res://project.godot")
|
||
Kit.check("V7 类型闸 warning 配置在位(untyped_declaration=1 显形)〔迭代27 T5〕",
|
||
pj.contains("gdscript/warnings/untyped_declaration=1"))
|
||
var scan_src: String = FileAccess.get_file_as_string("res://tests/static_scan.sh")
|
||
Kit.check("V7 类型审计器闸机在位(static_scan S9 → tools/audit_type_hints.py)〔迭代27 T5〕",
|
||
scan_src.contains("audit_type_hints.py"))
|
||
|
||
|
||
# ---- 卫生件 grep 闸(V8——死代码/字符串 Callable/影子账残留零命中;源码扫描面)----
|
||
func _smoke_hygiene_gates() -> void:
|
||
# oracle: design/engineering/code-conventions.md:54(模态覆盖层层级与登记纪律——卫生闸组)
|
||
var callables := 0
|
||
for d in ["res://core", "res://presentation", "res://data"]:
|
||
var dir := DirAccess.open(d)
|
||
if dir == null:
|
||
continue
|
||
dir.list_dir_begin()
|
||
var f := dir.get_next()
|
||
while f != "":
|
||
if dir.current_is_dir() and not f.begins_with("."):
|
||
var sub := DirAccess.open(d + "/" + f)
|
||
if sub != null:
|
||
sub.list_dir_begin()
|
||
var g := sub.get_next()
|
||
while g != "":
|
||
if g.ends_with(".gd"):
|
||
var t: String = FileAccess.get_file_as_string(d + "/" + f + "/" + g)
|
||
callables += t.count("Callable(self, \"")
|
||
g = sub.get_next()
|
||
elif f.ends_with(".gd"):
|
||
var t2: String = FileAccess.get_file_as_string(d + "/" + f)
|
||
callables += t2.count("Callable(self, \"")
|
||
f = dir.get_next()
|
||
Kit.check("V8 字符串 Callable 产品码零命中(实测应 0——方法引用换装闸)〔迭代27 T6〕",
|
||
callables == 0)
|
||
Kit.check("V8 FeatsEngine 整文件退役(class_name 注销=文件删除)〔迭代27 T6〕",
|
||
not FileAccess.file_exists("res://core/feats_engine.gd"))
|
||
var bo: String = FileAccess.get_file_as_string("res://core/battle_orchestrator.gd")
|
||
Kit.check("V8 死代码抽查·_attune_row 零残留〔迭代27 T6〕",
|
||
not bo.contains("func _attune_row"))
|
||
var sm: String = FileAccess.get_file_as_string("res://core/save_manager.gd")
|
||
Kit.check("V8 死代码抽查·attunement_counters 零残留〔迭代27 T6〕",
|
||
not sm.contains("func attunement_counters"))
|
||
var mv: String = FileAccess.get_file_as_string("res://presentation/main.gd")
|
||
Kit.check("V8 GP 影子账残留零命中(main 源码面——文件已删+委托缝已拆)〔迭代27 T3〕",
|
||
not mv.contains("gp_shadow_ledger") and not mv.contains("_gp_ledger"))
|
||
# V1d 层序落位单口:注册面建件后扫全 presentation——move_child 只允许出现在 ui_registry.gd 的
|
||
# apply_layer_contract 函数体内(合同装配单口——出现第二处落位=硬编码层序,须改合同表而非加调用)
|
||
var scanned: int = 0
|
||
var outside_calls: int = 0
|
||
for fn_path: String in _list_scripts("res://presentation"):
|
||
var src: String = FileAccess.get_file_as_string(fn_path)
|
||
scanned += 1
|
||
var fn_start: int = src.find("func apply_layer_contract") if fn_path.contains("ui_registry.gd") else -1
|
||
var fn_end: int = src.find("\nfunc ", fn_start + 10) if fn_start >= 0 else -1
|
||
if fn_end < 0:
|
||
fn_end = src.length()
|
||
outside_calls += (src.substr(0, fn_start) + src.substr(fn_end)).count("move_child(")
|
||
Kit.check("V1d 层序落位单口(presentation %d 文件——apply_layer_contract 之外 move_child 调用点=%d 应=0)〔注册面 V1〕" % [scanned, outside_calls],
|
||
scanned > 0 and outside_calls == 0)
|
||
|
||
|
||
# 目录 .gd 清单(DirAccess 平铺——presentation 无子目录;扫描面>0 前置由调用侧断言承载)
|
||
static func _list_scripts(dir_path: String) -> PackedStringArray:
|
||
var out: PackedStringArray = PackedStringArray()
|
||
var dir := DirAccess.open(dir_path)
|
||
if dir == null:
|
||
return out
|
||
dir.list_dir_begin()
|
||
var fname := dir.get_next()
|
||
while fname != "":
|
||
if fname.ends_with(".gd"):
|
||
out.append(dir_path + "/" + fname)
|
||
fname = dir.get_next()
|
||
dir.list_dir_end()
|
||
return out
|