Files
gplan-2/game/tests/unit/presentation/battle_narrator_test.gd
T
DKChan 68009b4ea8 fix(迭代34卡③审计缺漏): 补 S15 叙述寻址单测〔fv24〕+V6① 数据侧撤销证明;报告补 V7 十七行勾销表与 V9/fv26 行、四处描述改写
审计第一轮缺漏 4 条处置:V7 补覆盖行+S1–S16 逐条勾销(现工作树 file:line);V9 补件核行;
S15 boss_name 补真实入口单测(扫表取 Boss 带键,断言叙述名=boss 行集首行名;变异 "boss"→"battle" 实测红);
V6① 撤销证明换数据侧注入(bugbear 带 2→1 时 fv21 仍绿=数据驱动正证,叠加写死坐标才红)。
描述不符 4 条改写:fv17 夹具措辞、fv19 撤销归属、变异第 7 项首红、断言计数(36 条+1 行注释)。
随批入库第一轮审计报告。
2026-10-22 05:20:21 +08:00

83 lines
4.2 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.
# tests/unit/presentation/battle_narrator_test.gd — 战斗叙述直接单测
# 断言面 = 纯函数文案:休整/商店/终局三类叙述把数值带进去(玩家读数面由这里出)、
# 胜负两态文案互异、未知输入有兜底不吐空串。期望值由注入内容数出来。
# 运行:godot --headless --path game --script res://tests/unit/presentation/battle_narrator_test.gd
extends SceneTree
const Kit := preload("res://tests/unit/test_kit.gd")
const NarratorScript := preload("res://presentation/battle_narrator.gd")
# 叙述寻址的 runner 替身:只提供 boss_name 实际读的两项(当前节点、关卡行)
class _BossRunner:
var level_row: Dictionary = {"level_index": 1}
var node: Dictionary = {}
func current_node() -> Dictionary:
return node
func _init() -> void:
_test_numeric_lines_carry_values()
_test_end_text_differs_by_result()
_test_phase_text_nonempty()
_test_boss_name_uses_boss_rowset()
quit(Kit.finish("battle_narrator_test"))
func _test_numeric_lines_carry_values() -> void:
var rest: String = NarratorScript.rest_line(12, 30, 40)
Kit.check("休整叙述带入回复量与当前血量(实际「%s」)" % rest,
rest.contains("12") and rest.contains("30") and rest.contains("40"))
var shop: String = NarratorScript.shop_line(77)
Kit.check("商店叙述带入 GP 数(实际「%s」)" % shop, shop.contains("77"))
Kit.check("奖励行与休整行互异(不是同一句套所有场景)",
NarratorScript.reward_line() != rest)
func _test_end_text_differs_by_result() -> void:
# 关卡收束(level_end=true)恒为「关卡通关!」——单场胜负文案只在非收束态出现
var level: String = NarratorScript.battle_end_text("lose", true)
Kit.check("关卡收束态恒为「关卡通关!」(实际「%s」)" % level, level == "关卡通关!")
var win: String = NarratorScript.battle_end_text("victory", false)
var lose: String = NarratorScript.battle_end_text("lose", false)
Kit.check("单场胜负文案互异(胜「%s」/负「%s」)" % [win, lose], win != lose)
Kit.check("胜利文案非空(实际「%s」)" % win, win != "")
var unknown: String = NarratorScript.battle_end_text("something_else", false)
Kit.check("未知结果有兜底文案不吐空串(实际「%s」)" % unknown, unknown != "")
func _test_phase_text_nonempty() -> void:
var t: String = NarratorScript.phase_text(1, "", false, false, "")
Kit.check("相位叙述非空(实际「%s」)" % t, t != "")
var boss: String = NarratorScript.phase_text(2, "", false, true, "灰矮人石君王")
Kit.check("Boss 在场时叙述带入 Boss 名(实际「%s」)" % boss, boss.contains("灰矮人石君王"))
# 叙述寻址按行类取 Boss 行集(S 清单 S15 换代):Boss 节点名必须来自 (关卡, boss, 带) 行集,
# 不能落到同深度的战斗行集——期望名由表行集首行读出,不写死字面量。
func _test_boss_name_uses_boss_rowset() -> void:
var db = load("res://core/config_db.gd").new()
var loaded: bool = db.load_tables("res://data/tables", false)
Kit.check_quiet(loaded, "叙述寻址用例:数值表加载成功")
if not loaded:
return
var boss_row := {}
for row in db.enemy.rows:
if int(row.level_index) == 1 and String(row.get("row_kind", "")) == "boss":
boss_row = row
break
Kit.check_quiet(not boss_row.is_empty(), "叙述寻址用例:第一关有 Boss 行")
if boss_row.is_empty():
return
var boss_depth: int = int(boss_row.depth_band)
var boss_rows: Array = db.resolve_enemy_rowset(1, boss_depth, "boss")
var battle_rows: Array = db.resolve_enemy_rowset(1, boss_depth, "battle")
var boss_expect := String(boss_rows[0].get("display_name", ""))
var battle_name := String(battle_rows[0].get("display_name", ""))
var runner := _BossRunner.new()
runner.node = {"node_depth": boss_depth, "type": "boss"}
var got: String = NarratorScript.boss_name(runner, db)
Kit.check("Boss 名取自 Boss 行集首行(期望「%s」实际「%s」)〔fv24〕" % [boss_expect, got], got == boss_expect)
Kit.check("Boss 名与同深度战斗行集名不同(期望「%s」≠「%s」——行类路由可判别)〔fv24〕" % [boss_expect, battle_name], boss_expect != battle_name)