# 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 Kit := preload("res://tests/unit/test_kit.gd") # T6 收口:_check/汇总退出样板单点 const TEST_SEED := 20260928 # 夹具种子(任意固定值;语义 = 可复现性,非玩法数值) func _init() -> void: # 判据出处: design/gdd/systems/表现与支撑/数据配置.md:201 黄金向量:登记向量逐个复算(装载组) _test_derive_determinism() _test_counter_ledger() _test_stream_draw_determinism() _test_negative_seed_normalization() quit(Kit.finish("rng_service_test")) func _fresh_service(): var rng = RngServiceScript.new() rng.set_master_seed(TEST_SEED) return rng # 单盐派生纯函数:两全新实例同种子逐位一致(derive_at 不推计数器——纯函数契约) func _test_derive_determinism() -> void: # 判据出处: design/gdd/systems/表现与支撑/数据配置.md:201 黄金向量:随机派生纯函数对登记向量逐个复算相等、同输入恒同输出(派生确定性组) 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 Kit.check("同种子两实例 derive_at(0..7) 逐位一致", same) var a2 = _fresh_service() var before: int = a2.counter() a2.derive_at(0) Kit.check("derive_at 为纯函数不推计数器", a2.counter() == before) # 全局取数计数器:唯一账本——open_stream 逐次 +1(scope 单调) func _test_counter_ledger() -> void: # 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 计数器纪律:连续取号跨模拟关卡切换单调不重置(计数账本组) 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() Kit.check("open_stream 逐次推进全局计数器(+1/次)", c1 == c0 + 1 and c2 == c0 + 2) # 用途标签只进事件日志不参与派生——同 scope 同派生种子(统一流口径) 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) Kit.check("同 scope 异用途标签派生种子一致(标签不参与派生)", s1 == s2) # 同种子两实例同标签流的实际取数序列逐位一致(回放确定性契约——存档快照=主种子+计数器的前提) func _test_stream_draw_determinism() -> void: # 判据出处: design/gdd/systems/表现与支撑/数据配置.md:201 同输入恒同输出:流取号确定性(流取号组) 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 Kit.check("同种子两实例同标签流取数 12 次逐位一致", same) # 负输入 abs 归一化(警告通道)——|−s| 与 s 同派生 func _test_negative_seed_normalization() -> void: # 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」RngService 行 RngService:master_seed 与各流 scope 计数器单点(种子规约组) var pos = _fresh_service() var neg = RngServiceScript.new() neg.set_master_seed(-TEST_SEED) Kit.check("负种子 abs 归一化后派生与正种子一致", pos.derive_at(0) == neg.derive_at(0))