101 lines
4.9 KiB
GDScript
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)
|