feat: W2 经济核心+数据管线+灰盒 — Balance Bible v1.0 八表逐值落地,EconomyState/sim 14 门/灰盒主场景/单测(GDScript 待本机引擎验证)
This commit is contained in:
1 parent
856326a766
commit
24e5b0c4cc
58 files changed
+7099
-22
No files matched your search
@@ -0,0 +1,40 @@
|
||||
extends RefCounted
|
||||
|
||||
# 用例:BalanceData 载入 + 跨表引用 + CSV/Bible 关键值(数据门)
|
||||
|
||||
func run(a, data) -> void:
|
||||
a.true_(data.load_errors.is_empty(), "load_errors 为空(%s)" % str(data.load_errors))
|
||||
a.eq(data.generators.size(), 12, "12 班底")
|
||||
a.eq(data.upgrades.size(), 108, "108 升级")
|
||||
a.eq(data.meta_upgrades.size(), 12, "12 宿慧商品")
|
||||
a.eq(data.halls.size(), 10, "10 殿")
|
||||
a.eq(data.palettes.size(), 10, "10 色板")
|
||||
a.eq(data.bosses.size(), 10, "10 殿王战")
|
||||
a.eq(data.events.size(), 4, "4 事件")
|
||||
# 关键数值(Balance Bible v1.0 逐值一致)
|
||||
a.near(data.generators[11].base_rate, 1073741824.0, 0.5, "gen12 rate = 8^10")
|
||||
a.near(data.generators[1].payback_seconds(), 120.0, 0.5, "gen2 回本 120s")
|
||||
a.near(data.generators[5].payback_seconds(), 293.0, 0.5, "gen6 回本 293s")
|
||||
a.near(data.generators[11].payback_seconds(), 1118.0, 0.5, "gen12 回本 1118s")
|
||||
a.near(data.hall_by_no(1).gate_merit, 2000.0, 0.5, "H1 门 2K")
|
||||
a.near(data.hall_by_no(10).gate_merit, 1.5e9, 0.5, "H10 门 1.5B")
|
||||
a.true_(data.hall_by_no(10).is_prestige_gate, "H10 = prestige 门")
|
||||
a.near(data.boss_for_hall("hall_01_qinguang").hp_factor, 15.0, 1e-9, "殿王 HP 系数 15([B§5])")
|
||||
# 敕封诏书(P-12:requires = enthrone_ready)
|
||||
var edict := data.upgrade("up_gate_tianzi")
|
||||
a.true_(edict != null, "敕封诏书存在")
|
||||
a.eq(edict.requires, "enthrone_ready", "诏书 requires = enthrone_ready")
|
||||
a.eq(edict.cost, 800000000000, "诏书成本 800B")
|
||||
# 调参数(balance_tuning)
|
||||
a.near(data.tune_num("tune_souls_div", 0.0), 10000.0, 1e-9, "超度除数 10000")
|
||||
a.near(data.tune_num("tune_enthrone_suihui_req", 0.0), 60.0, 1e-9, "敕封宿慧门槛 60")
|
||||
a.near(data.tune_num("tune_enthrone_rebirths", 0.0), 2.0, 1e-9, "敕封转世门槛 2")
|
||||
a.eq(data.tune_text("tune_restart_curve", ""), "1:0.6:0.4:0.3", "重开曲线文本")
|
||||
a.near(data.tune_num("tune_wrath_layers", 0.0), 22.0, 1e-9, "冤煞 22 层")
|
||||
a.near(data.tune_num("tune_click_base", 0.0), 1.0, 1e-9, "点击基础值 1")
|
||||
# 跨表引用完整性(schema 管单表;这里查跨表)
|
||||
a.true_(data.check_references().is_empty(), "跨表引用无悬挂(%s)" % str(data.check_references()))
|
||||
# 每殿恰一场殿王战 + 色板
|
||||
for h in data.halls:
|
||||
a.true_(data.boss_for_hall(h.id) != null, "%s 有 boss 行" % h.id)
|
||||
a.true_(data.palette_for_hall(h.id) != null, "%s 有色板行" % h.id)
|
||||
@@ -0,0 +1,59 @@
|
||||
extends RefCounted
|
||||
|
||||
# 用例:核心公式(MultiplierSet / PrestigeModel / OfflineModel)
|
||||
|
||||
func run(a, _data) -> void:
|
||||
# ---- MultiplierSet 三乘区 + 软上限 ----
|
||||
var m := MultiplierSet.new(16.0, 8.0, 64.0)
|
||||
m.set_click_levels(4, 0.0, 0.01)
|
||||
a.near(m.click_mult(), 16.0, 1e-9, "点击区 4 级 = ×16")
|
||||
m.set_click_levels(5, 0.0, 0.01)
|
||||
a.near(m.click_mult(), 16.0, 1e-9, "点击区 5 级仍钳 ×16")
|
||||
m.set_gen_eff("gen_01_youhun", 6)
|
||||
a.near(m.gen_mult("gen_01_youhun"), 7.0, 1e-9, "班底区 6 级 = ×7")
|
||||
m.set_gen_eff("gen_01_youhun", 99)
|
||||
a.near(m.gen_mult("gen_01_youhun"), 8.0, 1e-9, "班底区钳 ×8")
|
||||
m.set_global_add(63.0)
|
||||
a.near(m.global_mult(), 64.0, 1e-9, "全局区 ×64")
|
||||
m.set_global_add(100.0)
|
||||
a.near(m.global_mult(), 64.0, 1e-9, "全局区钳 ×64")
|
||||
m.set_click_levels(4, 8.0, 0.01)
|
||||
a.near(m.click_value(1.0, 1000.0), 96.0, 1e-6, "click_value = 1×16 + 1000×8%")
|
||||
|
||||
# ---- PrestigeModel ----
|
||||
a.eq(PrestigeModel.suihui_gain(1.5e9, 1e6, 5.0, 0.0, 0.0), 193, "宿慧 1.5B → 193")
|
||||
a.eq(PrestigeModel.suihui_gain(1.25e7, 1e6, 5.0, 0.0, 0.0), 17, "宿慧 12.5M → 17")
|
||||
a.eq(PrestigeModel.suihui_gain(1.5e9, 1e6, 5.0, 0.0, 0.3), 135, "宿慧 30% 削减 → 135")
|
||||
a.eq(PrestigeModel.suihui_gain(1.5e9, 1e6, 5.0, 0.45, 0.0), 279, "宿慧 m03×3 → 279")
|
||||
a.eq(PrestigeModel.suihui_gain(0.0, 1e6, 5.0, 0.0, 0.0), 0, "零累计 → 0 宿慧")
|
||||
a.eq(PrestigeModel.wrath_layer_cost(1, 8.0, 1.8), 8, "怨煞层 1 成本 8")
|
||||
a.eq(PrestigeModel.wrath_layer_cost(2, 8.0, 1.8), 28, "怨煞层 2 成本 28")
|
||||
a.eq(PrestigeModel.wrath_layer_cost(22, 8.0, 1.8), 2087, "怨煞层 22 成本 2087")
|
||||
a.near(PrestigeModel.wrath_penalty(10, 0.03, 0.3, 0.0), 0.3, 1e-9, "冤气削减封顶 30%")
|
||||
a.near(PrestigeModel.wrath_penalty(10, 0.03, 0.3, 0.15), 0.15, 1e-9, "m07 改 15%")
|
||||
a.near(PrestigeModel.wrath_penalty(5, 0.03, 0.3, 0.0), 0.15, 1e-9, "5 层 = 15%")
|
||||
a.eq(PrestigeModel.skip_count(23, 5), 4, "skip 23/5 = 4")
|
||||
a.eq(PrestigeModel.skip_count(23, 4), 5, "skip 23/4 = 5(m04)")
|
||||
a.near(PrestigeModel.restart_target(0), 1.0, 1e-9, "重开曲线 R1")
|
||||
a.near(PrestigeModel.restart_target(3), 0.3, 1e-9, "重开曲线 R4")
|
||||
a.near(PrestigeModel.restart_target(4), 0.25, 1e-9, "重开曲线 R5 触底")
|
||||
a.true_(PrestigeModel.enthrone_available(2, 2), "敕封:转世 2 可")
|
||||
a.true_(not PrestigeModel.enthrone_available(1, 2), "敕封:转世 1 不可")
|
||||
|
||||
# ---- OfflineModel 分带 + 72h 封顶 + 时钟回拨 ----
|
||||
var r1: Dictionary = OfflineModel.settle(3600.0, 10.0, 1.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
|
||||
a.near(r1["effective_hours"], 1.0, 1e-9, "离线 1h = 1h 等效")
|
||||
a.near(r1["merit"], 36000.0, 1e-6, "离线 1h × 10/s")
|
||||
var r8: Dictionary = OfflineModel.settle(8.0 * 3600.0, 10.0, 1.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
|
||||
a.near(r8["effective_hours"], 6.2, 1e-9, "离线 8h = 6.2h 等效(P-8)")
|
||||
a.near(r8["merit"], 223200.0, 1e-6, "离线 8h 收益")
|
||||
var r100: Dictionary = OfflineModel.settle(100.0 * 3600.0, 10.0, 1.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
|
||||
a.near(r100["effective_hours"], 17.4, 1e-9, "离线 100h → 72h 封顶 = 17.4h 等效")
|
||||
var rneg: Dictionary = OfflineModel.settle(-5.0, 10.0, 1.0, 2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1, 72.0)
|
||||
a.near(rneg["merit"], 0.0, 1e-9, "时钟回拨 → 0")
|
||||
a.near(OfflineModel.ratio_8h_over_1h(2.0, 1.0, 8.0, 0.7, 24.0, 0.4, 0.1), 6.2, 1e-9,
|
||||
"门 #9 比率 6.2(契约 [1.5,2.5] 预计 FAIL,P-8)")
|
||||
|
||||
# ---- BigNumber 红线 ----
|
||||
a.true_(BigNumber.assert_within(1e13, "test"), "1e13 不过红线")
|
||||
a.true_(not BigNumber.assert_within(1e15, "test"), "1e15 触红线")
|
||||
@@ -0,0 +1,159 @@
|
||||
extends RefCounted
|
||||
|
||||
# 用例:EconomyState 状态机(点击/购买/殿门/冤气/prestige/敕封)
|
||||
|
||||
func run(a, data) -> void:
|
||||
_test_first_purchase(a, data)
|
||||
_test_hall_gate(a, data)
|
||||
_test_upgrades_and_meta(a, data)
|
||||
_test_wrath(a, data)
|
||||
_test_prestige(a, data)
|
||||
_test_enthrone(a, data)
|
||||
_test_event_and_offline(a, data)
|
||||
|
||||
|
||||
# ---- 首购循环:15 点击 → 买 gen1 → 产出 0.1/s(GDD demo 验证点)----
|
||||
func _test_first_purchase(a, data) -> void:
|
||||
var e := EconomyState.new(data)
|
||||
a.near(e.merit, 0.0, 1e-9, "初始阴德 0")
|
||||
a.near(e.output_per_sec(), 0.0, 1e-9, "初始产出 0")
|
||||
for _i in 15:
|
||||
e.click()
|
||||
a.near(e.merit, 15.0, 1e-9, "15 次点击 = 15 阴德")
|
||||
a.near(e.click_value(), 1.0, 1e-9, "点击价值 = 1")
|
||||
var r: Dictionary = e.buy_generator(0, 1)
|
||||
a.true_(bool(r.get("ok", false)), "15 阴德可买游魂×1")
|
||||
a.eq(e.gen_levels[0], 1, "游魂 1 级")
|
||||
a.near(e.merit, 0.0, 1e-9, "买后阴德 0")
|
||||
a.near(e.output_per_sec(), 0.1, 1e-9, "产出 0.1/s")
|
||||
var r2: Dictionary = e.buy_generator(0, 1)
|
||||
a.true_(not bool(r2.get("ok", false)), "0 阴德再买失败")
|
||||
e.merit = 100.0
|
||||
var r3: Dictionary = e.buy_upgrade("up_click_1")
|
||||
a.true_(bool(r3.get("ok", false)), "买指诀·倍力 I(50)")
|
||||
a.near(e.click_value(), 2.0, 1e-9, "点击价值 ×2")
|
||||
|
||||
|
||||
# ---- 殿门单计数器闸门 ----
|
||||
func _test_hall_gate(a, data) -> void:
|
||||
var e := EconomyState.new(data)
|
||||
a.false_(e.generator_unlocked(2), "gen3 初始锁定")
|
||||
e.merit_run_total = 1999.0
|
||||
e.tick(0.1)
|
||||
a.eq(e.halls_passed, 0, "1999 不过 H1")
|
||||
e.merit_run_total = 2000.0
|
||||
e.tick(0.1)
|
||||
a.eq(e.halls_passed, 1, "2000 过 H1(单计数器闸门)")
|
||||
a.true_(e.upgrade_visible(data.upgrade("up_eff_gen_03_guizu_1")), "H1 后 gen3 效率可见")
|
||||
a.true_(e.upgrade_visible(data.upgrade("up_gate_guizu")), "H1 后入职文书可见")
|
||||
a.false_(e.generator_unlocked(2), "过殿但未买文书 → gen3 仍锁")
|
||||
e.merit = 1000.0
|
||||
var r: Dictionary = e.buy_upgrade("up_gate_guizu")
|
||||
a.true_(bool(r.get("ok", false)), "买鬼卒班入职文书(800)")
|
||||
a.true_(e.generator_unlocked(2), "双闸齐 → gen3 解锁")
|
||||
var r2: Dictionary = e.buy_generator(2, 1)
|
||||
a.true_(bool(r2.get("ok", false)), "gen3 可购")
|
||||
|
||||
|
||||
# ---- 升级/宿慧商店 ----
|
||||
func _test_upgrades_and_meta(a, data) -> void:
|
||||
var e := EconomyState.new(data)
|
||||
e.suihui = 10
|
||||
var r: Dictionary = e.buy_meta("meta_01")
|
||||
a.true_(bool(r.get("ok", false)), "买枕旧梦(3 宿慧)")
|
||||
a.eq(e.suihui, 7, "扣 3 宿慧")
|
||||
a.eq(int(e.meta_ranks.get("meta_01", 0)), 1, "meta_01 阶 1")
|
||||
var r2: Dictionary = e.buy_meta("meta_01")
|
||||
a.true_(not bool(r2.get("ok", false)), "meta_01 一阶限购")
|
||||
e.suihui = 100
|
||||
var r3: Dictionary = e.buy_meta("meta_03")
|
||||
a.true_(bool(r3.get("ok", false)), "买宿慧通透(8)")
|
||||
# 效率升级进班底区
|
||||
e.merit = 100000.0
|
||||
e.gen_levels[0] = 10
|
||||
var r4: Dictionary = e.buy_upgrade("up_eff_gen_01_youhun_1")
|
||||
a.true_(bool(r4.get("ok", false)), "买游魂操练 I(83)")
|
||||
a.near(e.gen_mult(0), 2.0, 1e-9, "班底区 ×2(+100%)")
|
||||
|
||||
|
||||
# ---- 冤气线 ----
|
||||
func _test_wrath(a, data) -> void:
|
||||
var e := EconomyState.new(data)
|
||||
e.devour(100.0)
|
||||
a.near(e.wrath, 100.0, 1e-9, "吞噬 +100 冤气")
|
||||
a.eq(e.devour_count, 1, "吞噬计数")
|
||||
a.eq(e.wrath_layer_cost(), 8, "第 1 层成本 8")
|
||||
var r: Dictionary = e.buy_wrath_layer()
|
||||
a.true_(bool(r.get("ok", false)), "买第 1 层怨煞")
|
||||
a.eq(e.wrath_layers, 1, "1 层")
|
||||
a.near(e.global_mult(), 1.25, 1e-9, "全局 ×1.25(每层 +25%)")
|
||||
a.near(e.wrath_penalty(), 0.03, 1e-9, "宿慧削减 3%")
|
||||
e.wrath = 0.0
|
||||
var r2: Dictionary = e.buy_wrath_layer()
|
||||
a.true_(not bool(r2.get("ok", false)), "冤气不足买不了")
|
||||
e.wrath = 1e6
|
||||
for _i in 21:
|
||||
e.buy_wrath_layer()
|
||||
a.eq(e.wrath_layers, 22, "22 层上限")
|
||||
var r3: Dictionary = e.buy_wrath_layer()
|
||||
a.true_(not bool(r3.get("ok", false)), "满层后再买失败")
|
||||
|
||||
|
||||
# ---- 轮回转世 ----
|
||||
func _test_prestige(a, data) -> void:
|
||||
var e := EconomyState.new(data)
|
||||
a.false_(e.prestige_available(), "初始不可轮回")
|
||||
e.merit_run_total = 1.5e9
|
||||
a.true_(e.prestige_available(), "H10 门达成 → 可轮回")
|
||||
a.eq(e.suihui_gain(), 193, "1.5B → 193 宿慧")
|
||||
e.gen_levels[0] = 50
|
||||
e.merit = 123.0
|
||||
var r: Dictionary = e.do_prestige()
|
||||
a.true_(bool(r.get("ok", false)), "执行轮回")
|
||||
a.eq(e.suihui, 193, "宿慧入账")
|
||||
a.eq(e.rebirths, 1, "转世 1 次")
|
||||
a.near(e.merit, 0.0, 1e-9, "阴德清零")
|
||||
a.eq(e.gen_levels[0], 950, "跳过机制:193/5=38 ×25 = 950 级")
|
||||
a.eq(e.halls_passed, 0, "殿门进度重置")
|
||||
a.eq(e.bought.size(), 0, "升级清空")
|
||||
# 第二轮更快(宿慧全局 +3%)
|
||||
a.near(e.global_mult(), 1.0 + 193 * 0.03, 1e-9, "宿慧全局加成")
|
||||
|
||||
|
||||
# ---- 阴司敕封 + gen12 愿景档 ----
|
||||
func _test_enthrone(a, data) -> void:
|
||||
var e := EconomyState.new(data)
|
||||
e.rebirths = 2
|
||||
e.suihui = 100
|
||||
a.true_(e.enthrone_ready(), "转世 2 + 宿慧 100 → 敕封就绪")
|
||||
e.merit_run_total = 1.5e9
|
||||
e.merit = 1e12
|
||||
var r: Dictionary = e.buy_upgrade("up_gate_tianzi")
|
||||
a.true_(bool(r.get("ok", false)), "买敕封诏书(800B)")
|
||||
a.true_(e.enthrone_available(), "受敕可用")
|
||||
a.false_(e.generator_unlocked(11), "未受敕 → gen12 仍锁(P-12)")
|
||||
var r2: Dictionary = e.do_enthrone()
|
||||
a.true_(bool(r2.get("ok", false)), "执行受敕")
|
||||
a.true_(e.enthroned, "enthroned 旗标")
|
||||
a.true_(e.generator_unlocked(11), "受敕 → gen12 解锁")
|
||||
# 全局区 = 1 + 宿慧100×3% + 敕封 25% = 4.25
|
||||
a.near(e.global_mult(), 4.25, 1e-9, "全局 ×4.25(宿慧+敕封)")
|
||||
# gen12 产出接入
|
||||
e.gen_levels[11] = 1
|
||||
a.near(e.output_per_sec(), 1073741824.0 * 4.25, 1.0, "gen12 1 级产出")
|
||||
|
||||
|
||||
# ---- 事件瞬时区 + 离线倍率 ----
|
||||
func _test_event_and_offline(a, data) -> void:
|
||||
var e := EconomyState.new(data)
|
||||
e.gen_levels[0] = 10
|
||||
var base_out := e.output_per_sec()
|
||||
e.set_event_mult(5.0)
|
||||
a.near(e.output_per_sec(), base_out * 5.0, 1e-9, "事件 ×5 瞬时区")
|
||||
e.set_event_mult(1.0)
|
||||
a.near(e.offline_mult(), 1.0, 1e-9, "无长明灯 → ×1")
|
||||
e.halls_passed = 4 # 离线升级出现条件
|
||||
e.merit = 1e9
|
||||
var r: Dictionary = e.buy_upgrade("up_offline_1")
|
||||
a.true_(bool(r.get("ok", false)), "买长明灯 I")
|
||||
a.near(e.offline_mult(), 1.15, 1e-9, "离线 ×1.15(P-13 乘性链)")
|
||||
@@ -0,0 +1,19 @@
|
||||
extends RefCounted
|
||||
|
||||
# 用例:NumberFormat(core/numbers/number_format.gd)
|
||||
|
||||
func run(a, _data) -> void:
|
||||
a.eq(NumberFormat.short(999.0), "999", "short 999")
|
||||
a.eq(NumberFormat.short(1000.0), "1.00K", "short 1K")
|
||||
a.eq(NumberFormat.short(1234.0), "1.23K", "short 1234")
|
||||
a.eq(NumberFormat.short(1.5e9), "1.50B", "short 1.5B")
|
||||
a.eq(NumberFormat.short(1.5e12), "1.50T", "short 1.5T")
|
||||
a.eq(NumberFormat.short_int(1500.0), "2K", "short_int 1500 → 2K")
|
||||
a.eq(NumberFormat.short_int(1400.0), "1K", "short_int 1400 → 1K")
|
||||
a.eq(NumberFormat.duration(42.0), "42s", "duration 42s")
|
||||
a.eq(NumberFormat.duration(90.0), "1m 30s", "duration 90s")
|
||||
a.eq(NumberFormat.duration(3600.0), "1h", "duration 1h")
|
||||
a.eq(NumberFormat.duration(5100.0), "1h 25m", "duration 1h25m")
|
||||
a.eq(NumberFormat.minutes(25.0), "25m", "minutes 25")
|
||||
a.eq(NumberFormat.minutes(180.0), "3h", "minutes 180")
|
||||
a.eq(NumberFormat.minutes(125.0), "2h 5m", "minutes 125")
|
||||
@@ -0,0 +1,78 @@
|
||||
extends SceneTree
|
||||
|
||||
# ============================================================================
|
||||
# test_runner.gd —— core 层无头单测入口(GUT 未装前的自包含方案;W3 换 GUT)
|
||||
#
|
||||
# 运行:godot --headless --path . -s res://tests/unit/test_runner.gd
|
||||
# 退出码:0 = 全过;1 = 有失败;2 = 数据/环境错误。
|
||||
# 每个用例文件 = tests/unit/cases/*.gd,契约:func run(a) -> void(a = TestAssert)。
|
||||
# ============================================================================
|
||||
|
||||
class TestAssert extends RefCounted:
|
||||
var failures: Array[String] = []
|
||||
var checks := 0
|
||||
|
||||
func check(cond: bool, msg: String) -> void:
|
||||
checks += 1
|
||||
if not cond:
|
||||
failures.append(msg)
|
||||
|
||||
func eq(got: Variant, want: Variant, msg: String) -> void:
|
||||
checks += 1
|
||||
if got != want:
|
||||
failures.append("%s:got %s want %s" % [msg, str(got), str(want)])
|
||||
|
||||
func near(got: float, want: float, tol: float, msg: String) -> void:
|
||||
checks += 1
|
||||
if absf(float(got) - float(want)) > tol:
|
||||
failures.append("%s:got %.6g want %.6g(tol %g)" % [msg, got, want, tol])
|
||||
|
||||
func true_(cond: bool, msg: String) -> void:
|
||||
check(cond, msg)
|
||||
|
||||
func false_(cond: bool, msg: String) -> void:
|
||||
check(not cond, msg)
|
||||
|
||||
|
||||
const CASE_FILES: Array[String] = [
|
||||
"res://tests/unit/cases/test_number_format.gd",
|
||||
"res://tests/unit/cases/test_economy_formulas.gd",
|
||||
"res://tests/unit/cases/test_balance_data.gd",
|
||||
"res://tests/unit/cases/test_economy_state.gd",
|
||||
]
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
var data := BalanceData.load_from_dir("res://data/build/")
|
||||
if not data.load_errors.is_empty():
|
||||
for e in data.load_errors:
|
||||
printerr("test_runner:数据错误:%s" % e)
|
||||
quit(2)
|
||||
return
|
||||
var total_checks := 0
|
||||
var total_fail: Array[String] = []
|
||||
for path in CASE_FILES:
|
||||
var script: Variant = load(path)
|
||||
if script == null:
|
||||
printerr("test_runner:用例缺失 %s" % path)
|
||||
quit(2)
|
||||
return
|
||||
var case_obj: Variant = script.new()
|
||||
if not (case_obj is RefCounted) or not case_obj.has_method("run"):
|
||||
printerr("test_runner:用例契约不符 %s" % path)
|
||||
quit(2)
|
||||
return
|
||||
var a := TestAssert.new()
|
||||
case_obj.run(a, data)
|
||||
total_checks += a.checks
|
||||
for f in a.failures:
|
||||
total_fail.append("%s → %s" % [path.get_file(), f])
|
||||
print("test_runner:%s:%d 检查,%d 失败" % [path.get_file(), a.checks, a.failures.size()])
|
||||
if total_fail.is_empty():
|
||||
print("test_runner:PASS(%d 检查全过)" % total_checks)
|
||||
quit(0)
|
||||
return
|
||||
print("test_runner:FAIL(%d/%d)" % [total_fail.size(), total_checks])
|
||||
for f in total_fail:
|
||||
printerr(" ✗ %s" % f)
|
||||
quit(1)
|
||||
Reference in new issue
Block a user