Files
aetherbound-guild/runtime/tests/fg4/rg04_activation_test.gd
T

101 lines
4.9 KiB
GDScript

extends SceneTree
const Activation = preload("res://fg4/rg04_activation_service.gd")
const Fixture = preload("res://tests/fg4/contract1_fixture.gd")
const State = preload("res://fg4/run_state.gd")
var failures: Array[String] = []
var rejected_cases := 0
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
verify_exact_activation_and_preservation()
verify_activation_boundaries()
if failures.is_empty():
print("ABG_FG4_RG04_ACTIVATION_OK source=CLEAR-RG03-C01,CLEAR-RG03-C02 region=RG-04 contract=CTR-R4-01 phase=rg04_market market=1 board=3,4,3 prior_routes=48 company,growth,hp,equipment,economy,artifact,records,receipts=exact duplicate=true save_version=11 rejected_cases=%d" % rejected_cases)
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func verify_exact_activation_and_preservation() -> void:
var before := Fixture.new().region_closed_snapshot()
expect(not before.is_empty(), "RG-03 close fixture exists")
var service := Activation.new(before)
expect(service.valid and service.state.current_run.phase == "region_closed", "exact RG-03 close restores")
if not service.valid:
return
var result_hash := String(service.state.current_run.market_board.result_hash)
var revision_before := service.state.revision
var preserved_before := preserved_projection(service.state.snapshot())
var activated := service.activate_region("fg4-rg04-activate", revision_before, result_hash)
expect(activated.ok and not activated.duplicate, "RG-04 activates exactly once")
if not activated.ok:
return
var run: Dictionary = service.state.current_run
expect(run.region_id == "RG-04" and run.contract_id == "CTR-R4-01" and run.phase == "rg04_market", "RG-04 identity and phase are exact")
expect(run.market_index == 1 and run.round_index == 1 and run.cleared_rounds == 48, "Market and campaign lineage are exact")
expect(run.market_board.recruit_slots.size() == 3 and run.market_board.equipment_offers.size() == 4 and run.market_board.battle_offers.size() == 3, "Market 1 has exact 3/4/3 board")
expect(run.market_board.archive_clause.kind in ["repeat", "alternate", "preserve"], "archive clause is disclosed before commitment")
expect(not String(run.market_board.copy_disclosure.source_rule).is_empty(), "copy source is disclosed before commitment")
expect(preserved_projection(service.state.snapshot()) == preserved_before, "activation preserves all carried consequences byte-equivalent")
var duplicate := service.activate_region("fg4-rg04-activate", revision_before, result_hash)
expect(duplicate.ok and duplicate.duplicate and duplicate.revision == activated.revision, "duplicate activation is inert")
var roundtrip := State.new()
expect(roundtrip.restore_snapshot(service.state.snapshot()) and roundtrip.snapshot() == service.state.snapshot(), "activated RG-04 state roundtrips exactly")
func verify_activation_boundaries() -> void:
var before := Fixture.new().region_closed_snapshot()
if before.is_empty():
return
var service := Activation.new(before)
var original := service.state.snapshot()
expect_rejected(service.activate_region("fg4-rg04-stale", service.state.revision - 1, String(service.state.current_run.market_board.result_hash)), "stale revision", "stale_revision")
expect_rejected(service.activate_region("fg4-rg04-bad-hash", service.state.revision, "0".repeat(64)), "result hash tamper", "result_hash_mismatch")
expect(service.state.snapshot() == original, "rejected activation does not mutate state")
var invalid := before.duplicate(true)
invalid.current_run.market_board.result_hash = "0".repeat(64)
expect(not State.new().restore_snapshot(invalid), "tampered source state rejects before activation")
rejected_cases += 1
var wrong_phase := Fixture.new().contract2_market_1_snapshot()
var wrong_service := Activation.new(wrong_phase)
expect_rejected(wrong_service.activate_region("fg4-rg04-wrong-phase", wrong_service.state.revision, "0".repeat(64)), "nonterminal source", "rg03_region_closed_required")
func preserved_projection(snapshot_value: Dictionary) -> Dictionary:
var run: Dictionary = snapshot_value.current_run
return {
"run_id": run.run_id,
"run_seed": run.run_seed,
"company": run.company,
"deployed": run.deployed_recruit_ids,
"reserve": run.reserve_recruit_ids,
"recruit_records": run.recruit_records,
"inventory": run.inventory,
"equipped": run.equipped_by_recruit,
"coin": run.coin,
"credit": run.replacement_credit,
"artifacts": run.active_artifact_ids,
"history": run.route_history,
"guild_profile": snapshot_value.guild_profile,
}
func expect_rejected(result: Dictionary, label: String, code: String) -> void:
var rejected := not bool(result.get("ok", false)) and String(result.get("code", "")) == code
expect(rejected, "%s rejects with %s; got %s" % [label, code, str(result)])
if rejected:
rejected_cases += 1
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("FG-4 RG-04 activation: %s" % message)