# tests/unit/test_kit.gd — 单元测试协议样板单点(T6 样板收口批 2026-10-02) # 收口范围:11 份套件的 _check/_problems 样板(计数器 + PASS/FAIL 行 + 汇总退出)+ # reward_dangling_aux/aux_target_violation 两致命类用例各自复制的 BAD 表目录夹具。 # 用法(--script 模式无 autoload/全局标识符——禁 class_name 裸引用,使用方 preload): # const Kit := preload("res://tests/unit/test_kit.gd") # Kit.check("断言描述", cond) # 计数 + 即时 PASS/FAIL 行 # Kit.check_quiet(cond, "描述") # 计数 + 失败收集(finish 时统一汇总——原 _problems 风格,原参序) # quit(Kit.finish("suite_name")) # 汇总输出 + 返回退出码(0 全绿 / 1 有败) # 计数器为 static(套件 = 独立 Godot 子进程恰一份生命周期,见 run_all.gd 执行形态); # 单进程跑多套件须先 Kit.reset()。 extends RefCounted static var checks: int = 0 static var failures: int = 0 static var problems: Array = [] # 主通道:计数 + 即时 PASS/FAIL 行(config_db/rng_service/damage_math/system_contracts/ # damage_controller/ui_font_asset/terrain_tile_sets 等套件原 _check 同款输出,描述在前) static func check(desc: String, ok: bool) -> void: checks += 1 if ok: print(" [PASS] " + desc) else: failures += 1 push_error(" [FAIL] " + desc) # 静默收集通道:失败只记入 problems(即时零刷屏),finish 统一汇总。 # 参序沿原函数式套件 aux_items/breakpoint_resume 的 check(cond, msg)——条件在前,与主通道相反。 static func check_quiet(ok: bool, desc: String) -> void: checks += 1 if not ok: failures += 1 problems.append(desc) # 汇总退出:返回退出码(调用方 `quit(Kit.finish(...))`)。pass_line = 成功尾行覆盖 #(保留原套件 PASS 摘要文案;缺省 = "all green (N checks)" 计数口径)。 # 失败路径:push_error 计数汇总 + problems 逐条 FAIL 行(print + push_error 双通道——原两风格并档)。 static func finish(suite: String, pass_line: String = "") -> int: if failures > 0: push_error("[%s] %d/%d 项失败" % [suite, failures, checks]) for p in problems: print("[%s] FAIL — %s" % [suite, p]) push_error("[%s] FAIL — %s" % [suite, p]) return 1 print("[%s] %s" % [suite, pass_line if pass_line != "" else "all green (%d checks)" % checks]) return 0 # BAD 表夹具共享(原 reward_dangling_aux/aux_target_violation 各自复制的 _copy_tables): # 整目录拷贝 src_dir → bad_dir(目录已建)。BAD_DIR 常量仍由各用例自持(名字互异——独立进程并行不互踩)。 static func copy_tables(src_dir: String, bad_dir: String) -> bool: DirAccess.make_dir_recursive_absolute(bad_dir) var dir := DirAccess.open(src_dir) if dir == null: return false dir.list_dir_begin() var f := dir.get_next() while f != "": if not dir.current_is_dir(): if dir.copy(src_dir + "/" + f, bad_dir + "/" + f) != OK: return false f = dir.get_next() return true static func reset() -> void: checks = 0 failures = 0 problems = []