Files
gplan-2/game/tests/unit/presentation/playtest_logger_step_fields_test.gd
T

109 lines
5.3 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VERTICAL SLICE - NOT FOR PRODUCTION
# 日志 step 行零文案与全字段落盘断言(结算期文字列表退役批 T2——日志零文案只存字段):
# 真实入口 = sim 采集链(LevelAutoplay.run_level 挂 PlaytestLogger.start_session → 真实结算 →
# close_session 落盘 JSONL 读回),断言:
# ① 全型 step 行零中文文案(text / display_name 两键不存在);
# ② 公共七字段(kind/type/source/cell/round/value/highlight)与平铺原件(origin_cell/round_index/
# source_class)逐型在位——日志逐行全字段落盘义务不变(公共字段集除文案两键外零删减);
# ③ payload 键抽样在位(damage 行 roll/ac/tier/normal/pierce/magic/baseline——改前键集实证在册,
# 反事实精确重算数据面不被零文案改动静默吞键)。
# 运行:godot --headless --path game --script res://tests/unit/presentation/playtest_logger_step_fields_test.gd(expect 0)
extends SceneTree
const Kit := preload("res://tests/unit/test_kit.gd")
const ConfigDBScript := preload("res://core/config_db.gd")
var _problems: Array = []
func check(cond: bool, msg: String) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
if not cond:
_problems.append(msg)
func _init() -> void:
# 判据出处: design/gdd/08-Alpha版本标准.md:154 演出链在役(逐行结算排播已随 v1.29 退役)——
# 日志零文案只存字段(text/display_name 不落盘),其余全字段与 payload 逐键保留
var db = ConfigDBScript.new()
if not db.load_tables("res://data/tables", true):
_problems.append("数值表加载失败(夹具前提)")
_finish()
return
_assert_no_text_and_full_payload(db)
_finish()
func _assert_no_text_and_full_payload(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:87 显示名等玩家可见文案是数据面字段(日志消费端零文案)
var logger = load("res://presentation/playtest_logger.gd").new()
logger.ap_per_round = int(db.run.action_economy.ap_per_round) # 注入序前置(守卫拒后开——R5 必填)
var log_path: String = logger.start_session(4242)
var autoplay = load("res://sim/level_autoplay.gd")
var st = autoplay.run_level(db, 4242, 1, 0, 0, false, logger, "normal", "min")
logger.close_session()
check(bool(st.get("terminated", false)) or int(st.get("rounds", 0)) > 0,
"真实结算已跑(夹具前提:rounds>0——result=%s log_path=%s)" % [String(st.get("result", "?")), String(st.get("log_path", "?"))])
# 落盘 JSONL 读回(start_session 返回路径——采集链同源)
var f := FileAccess.open(log_path, FileAccess.READ)
check(f != null, "日志文件可读(%s)" % log_path)
if f == null:
return
var steps: Array = []
while not f.eof_reached():
var line := f.get_line()
if line.strip_edges() == "":
continue
var parsed: Variant = JSON.parse_string(line)
if parsed is Dictionary and String(parsed.get("kind", "")) == "step":
steps.append(parsed)
f.close()
check(steps.size() > 0, "step 行非空(断言前提:%d 行)" % steps.size())
# ---- ① 全型零文案(text / display_name 两键不存在)----
var text_hits := 0
var display_hits := 0
for s in steps:
if (s as Dictionary).has("text"):
text_hits += 1
if (s as Dictionary).has("display_name"):
display_hits += 1
check(text_hits == 0, "全 step 行零 text 键(命中 %d/%d)〔退役改 V-退役卡 R3〕" % [text_hits, steps.size()])
check(display_hits == 0, "全 step 行零 display_name 键(命中 %d/%d)〔退役改 V-退役卡 R3〕" % [display_hits, steps.size()])
# ---- ② 公共七字段 + 平铺原件逐型在位 ----
var common := ["kind", "type", "source", "cell", "round", "value", "highlight",
"origin_cell", "round_index", "source_class"]
var misses: Array[String] = []
for s in steps:
for k in common:
if not (s as Dictionary).has(k):
misses.append("%s 缺 %s" % [String(s.get("type", "?")), k])
check(misses.is_empty(), "公共字段与平铺原件逐行在位(缺:%s)〔退役改 V-退役卡 R3〕" % [", ".join(misses)])
# ---- ③ damage 行 payload 键并集抽样(反事实精确重算数据面在册——单行键随行型分布,
# 并集才是改前契约形态:掷点键逐行必有、分量键按攻击来源分布)----
var dmg_union := {}
var dmg_seen := 0
for s in steps:
if String(s.get("type", "")) == "damage":
dmg_seen += 1
for k in (s as Dictionary).keys():
dmg_union[k] = true
check(dmg_seen > 0, "damage 行在册(抽样前提:%d 行)" % dmg_seen)
var payload_missing: Array[String] = []
for k in ["roll", "ac", "tier", "normal", "baseline"]:
if not dmg_union.has(k):
payload_missing.append(k)
check(payload_missing.is_empty(),
"damage 行 payload 键并集在位(缺:%s)〔退役改 V-退役卡 R3〕" % [", ".join(payload_missing)])
func _finish() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
if _problems.is_empty():
print("[playtest_logger_step_fields_test] PASS — 日志 step 行零文案与全字段落盘 全绿")
quit(0)
else:
for p in _problems:
push_error("[playtest_logger_step_fields_test] FAIL — " + p)
print("[playtest_logger_step_fields_test] FAIL — " + p)
quit(1)