106 lines
5.5 KiB
GDScript
106 lines
5.5 KiB
GDScript
# tests/unit/data_config/level_gen_params_test.gd — 关卡节点图参数档单测(节点图生成器核心批 卡① T1/V2)
|
||
# 覆盖:生产表三行加载+validate 零违例、域校验逐类负向(出口 L1 恒 1/配比合计 1/层深下限/增幅变大/
|
||
# 岔口去路数锁定/键集闭集/键重复)、ConfigDB 访问器按 level_index 读回与缺行空字典。
|
||
# 运行:godot --headless --path game --script res://tests/unit/data_config/level_gen_params_test.gd(expect 0)
|
||
# 协议(tests/README):extends SceneTree + quit(code);负向用例资源直构不碰生产表。
|
||
extends SceneTree
|
||
|
||
const ConfigDBScript := preload("res://core/config_db.gd")
|
||
const LgpScript := preload("res://data/schemas/level_gen_params.gd")
|
||
const Kit := preload("res://tests/unit/test_kit.gd")
|
||
|
||
|
||
func _init() -> void:
|
||
var db = ConfigDBScript.new()
|
||
var load_ok: bool = db.load_tables("res://data/tables", true)
|
||
Kit.check("生产 level_gen_params.tres 随全表加载 + validate 零违例〔fv2〕",
|
||
load_ok and db.diagnostics_count("error") == 0)
|
||
if load_ok:
|
||
_test_production(db)
|
||
_test_accessor()
|
||
_test_negative()
|
||
quit(Kit.finish("level_gen_params_test"))
|
||
|
||
|
||
func _row(L: int, layers: int, bd: float, ratios: Array, entry: int, exit_c: int, floor_n: int) -> Dictionary:
|
||
return {"level_index": L, "layers": layers, "branch_density": bd,
|
||
"battle_ratio": ratios[0], "reward_ratio": ratios[1], "rest_ratio": ratios[2], "shop_ratio": ratios[3],
|
||
"entry_count": entry, "exit_count": exit_c, "battle_floor": floor_n,
|
||
"fork_ways_min": 2, "fork_ways_max": 3}
|
||
|
||
|
||
func _table(rows: Array) -> Variant:
|
||
var t = LgpScript.new()
|
||
var typed: Array[Dictionary] = []
|
||
for r in rows:
|
||
typed.append(r)
|
||
t.rows = typed
|
||
return t
|
||
|
||
|
||
# ---- 生产三行正向(V2)----
|
||
|
||
func _test_production(db) -> void:
|
||
var r1: Dictionary = db.level_gen_params_row(1)
|
||
var r2: Dictionary = db.level_gen_params_row(2)
|
||
var r3: Dictionary = db.level_gen_params_row(3)
|
||
Kit.check("访问器读回 L1 行五旋钮齐备〔fv2〕",
|
||
int(r1.get("layers", 0)) == 6 and is_equal_approx(float(r1.get("branch_density", 0.0)), 0.3)
|
||
and int(r1.get("exit_count", 0)) == 1 and int(r1.get("entry_count", 0)) == 1)
|
||
Kit.check("访问器读回 L2/L3 行层深 9/13 递增〔fv2〕",
|
||
int(r2.get("layers", 0)) == 9 and int(r3.get("layers", 0)) == 13)
|
||
Kit.check("三行出口 = 1/2/3、战斗保底 = 4/6/8 与 §8.1 表对上〔fv2〕",
|
||
int(r1.get("battle_floor", 0)) == 4 and int(r2.get("exit_count", 0)) == 2
|
||
and int(r3.get("exit_count", 0)) == 3 and int(r3.get("battle_floor", 0)) == 8)
|
||
Kit.check("生产表 validate 零错误〔fv2〕", db.level_gen_params.validate().is_empty())
|
||
|
||
|
||
# ---- 访问器缺行防御 ----
|
||
|
||
func _test_accessor() -> void:
|
||
var t = _table([_row(1, 6, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 1, 4)])
|
||
Kit.check("row_by_level_index 缺行返回空字典〔fv2〕", t.row_by_level_index(9).is_empty())
|
||
|
||
|
||
# ---- 域校验逐类负向(V2)----
|
||
|
||
func _test_negative() -> void:
|
||
# 合法基线三行
|
||
var base := [_row(1, 6, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 1, 4),
|
||
_row(2, 9, 0.5, [0.5, 0.2, 0.15, 0.15], 2, 2, 6),
|
||
_row(3, 13, 0.7, [0.55, 0.15, 0.15, 0.15], 2, 3, 8)]
|
||
Kit.check("合法三行域校验零错误(夹具自证)〔fv2〕", _table(base).validate().is_empty())
|
||
# ① L1 出口改 2 → 出口恒 1 断言红(负样本夹具)
|
||
var bad_l1_exit := [_row(1, 6, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 2, 4), base[1], base[2]]
|
||
Kit.check("L1 出口=2 被拒(出口 L1 恒 1 已锁)〔fv2〕", not _table(bad_l1_exit).validate().is_empty())
|
||
# ② 配比合计 0.5 → 合计 1 断言红(负样本夹具)
|
||
var bad_ratio := [_row(1, 6, 0.3, [0.2, 0.1, 0.1, 0.1], 1, 1, 4), base[1], base[2]]
|
||
Kit.check("配比合计 0.5 被拒(四类合计 1 已锁)〔fv2〕", not _table(bad_ratio).validate().is_empty())
|
||
# ③ 层深低于下限
|
||
var bad_layers := [_row(1, 5, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 1, 4), base[1], base[2]]
|
||
Kit.check("层深 5<6 被拒(层深下限已锁)〔fv2〕", not _table(bad_layers).validate().is_empty())
|
||
# ④ 增幅未变大(6/9/11:Δ12=3、Δ23=2)
|
||
var bad_growth := [base[0], _row(2, 9, 0.5, [0.5, 0.2, 0.15, 0.15], 2, 2, 6),
|
||
_row(3, 11, 0.7, [0.55, 0.15, 0.15, 0.15], 2, 3, 8)]
|
||
Kit.check("层深增幅倒挂被拒(递增且增幅变大)〔fv2〕", not _table(bad_growth).validate().is_empty())
|
||
# ⑤ 出口越上界(L3 出口 4)
|
||
var bad_exit := [base[0], base[1], _row(3, 13, 0.7, [0.55, 0.15, 0.15, 0.15], 2, 4, 8)]
|
||
Kit.check("出口 4 越域 [1,3] 被拒〔fv2〕", not _table(bad_exit).validate().is_empty())
|
||
# ⑥ 岔口去路数改 (2,4)
|
||
var bad_fork_row := _row(1, 6, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 1, 4)
|
||
bad_fork_row["fork_ways_max"] = 4
|
||
Kit.check("岔口去路数 (2,4) 被拒(恒 2/3 已锁)〔fv2〕",
|
||
not _table([bad_fork_row, base[1], base[2]]).validate().is_empty())
|
||
# ⑦ 键集非闭集(多塞未知键)
|
||
var bad_keys_row: Dictionary = _row(1, 6, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 1, 4)
|
||
bad_keys_row["mystery"] = 1
|
||
Kit.check("字段键集非 ROW_KEYS 闭集被拒〔fv2〕",
|
||
not _table([bad_keys_row, base[1], base[2]]).validate().is_empty())
|
||
# ⑧ level_index 重复
|
||
Kit.check("键重复行被拒〔fv2〕", not _table([base[0], base[0]]).validate().is_empty())
|
||
# ⑨ 战斗保底负值
|
||
Kit.check("战斗保底 -1 被拒(≥0)〔fv2〕",
|
||
not _table([_row(1, 6, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 1, -1), base[1], base[2]]).validate().is_empty())
|
||
# ⑩ 空表=合法态(沿 difficulty_table 先例)
|
||
Kit.check("空表域校验零错误(合法态)〔fv2〕", _table([]).validate().is_empty())
|