# tests/unit/data_config/rng_service_test.gd — 统一随机流单元测试:单盐派生确定性/计数器账本/标签词表封闭 # 运行:godot --headless --path game --script res://tests/unit/data_config/rng_service_test.gd # 红线:零自建 RNG——本测试只经 RngService 统一流取数(确定性契约:同种子逐位复现)。 # 测试种子为夹具基建值(非玩法数值),与冒烟黄金向量锚(smoke_all m=42 scope 0-4)分工:本文件测 # 「同种子两实例逐位一致」的相对确定性,绝对向量锚归冒烟单点,避免双处维护同一常量。 extends SceneTree const RngServiceScript := preload("res://core/rng_service.gd") const TEST_SEED := 20260928 # 夹具种子(任意固定值;语义 = 可复现性,非玩法数值) var _failures := 0 var _checks := 0 func _init() -> void: _test_derive_determinism() _test_counter_ledger() _test_stream_draw_determinism() _test_negative_seed_normalization() if _failures > 0: push_error("[rng_service_test] %d/%d 项失败" % [_failures, _checks]) quit(1) return print("[rng_service_test] all green (%d checks)" % _checks) quit(0) func _check(desc: String, ok: bool) -> void: _checks += 1 if ok: print(" [PASS] " + desc) else: _failures += 1 push_error(" [FAIL] " + desc) func _fresh_service(): var rng = RngServiceScript.new() rng.set_master_seed(TEST_SEED) return rng # 单盐派生纯函数:两全新实例同种子逐位一致(derive_at 不推计数器——纯函数契约) func _test_derive_determinism() -> void: var a = _fresh_service() var b = _fresh_service() var same := true for scope in range(8): if a.derive_at(scope) != b.derive_at(scope): same = false _check("同种子两实例 derive_at(0..7) 逐位一致", same) var a2 = _fresh_service() var before: int = a2.counter() a2.derive_at(0) _check("derive_at 为纯函数不推计数器", a2.counter() == before) # 全局取数计数器:唯一账本——open_stream 逐次 +1(scope 单调) func _test_counter_ledger() -> void: var rng = _fresh_service() var c0: int = rng.counter() rng.open_stream("armor_roll") var c1: int = rng.counter() rng.open_stream("armor_roll") var c2: int = rng.counter() _check("open_stream 逐次推进全局计数器(+1/次)", c1 == c0 + 1 and c2 == c0 + 2) # 用途标签只进事件日志不参与派生——同 scope 同派生种子(ADR-0007 裁丙口径) var rng_x = _fresh_service() var rng_y = _fresh_service() var s1: int = int(rng_x.open_stream("board_gen").seed) var s2: int = int(rng_y.open_stream("reward_roll").seed) _check("同 scope 异用途标签派生种子一致(标签不参与派生)", s1 == s2) # 同种子两实例同标签流的实际取数序列逐位一致(回放确定性契约——存档快照=主种子+计数器的前提) func _test_stream_draw_determinism() -> void: var faces := 20 # d20 探针面数(夹具值,非玩法表值——只用于产生可比较序列) var a = _fresh_service() var b = _fresh_service() var same := true for i in range(12): var ra: int = a.open_stream("armor_roll").randi_range(1, faces) var rb: int = b.open_stream("armor_roll").randi_range(1, faces) if ra != rb: same = false _check("同种子两实例同标签流取数 12 次逐位一致", same) # 负输入 abs 归一化(警告通道)——|−s| 与 s 同派生 func _test_negative_seed_normalization() -> void: var pos = _fresh_service() var neg = RngServiceScript.new() neg.set_master_seed(-TEST_SEED) _check("负种子 abs 归一化后派生与正种子一致", pos.derive_at(0) == neg.derive_at(0))