107 lines
7.9 KiB
GDScript
107 lines
7.9 KiB
GDScript
extends SceneTree
|
|
|
|
const Service = preload("res://p10_0/market_service.gd")
|
|
|
|
var failures: Array[String] = []
|
|
var rejected = 0
|
|
var applied = 0
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
var service = created_service()
|
|
var recruit_id = String(service.state.current_run.available_recruit_offer_ids[0])
|
|
var equipment_id = String(service.state.current_run.available_equipment_offer_ids[0])
|
|
var battle_id = String(service.state.current_run.available_battle_offer_ids[0])
|
|
var revision = service.state.revision
|
|
check_reject(service, func(): return service.hire("", revision, recruit_id, 14, false), "operation_id_required")
|
|
check_reject(service, func(): return service.hire("bad-stale", revision + 1, recruit_id, 14, false), "stale_revision")
|
|
check_reject(service, func(): return service.hire("bad-price", revision, recruit_id, 15, false), "price_mismatch")
|
|
check_reject(service, func(): return service.hire("bad-offer", revision, "missing", 14, false), "recruit_offer_unavailable")
|
|
check_reject(service, func(): return service.buy_equipment("bad-equip-price", revision, equipment_id, 999), "price_mismatch")
|
|
check_reject(service, func(): return service.buy_equipment("bad-equip-offer", revision, "missing", 12), "equipment_offer_unavailable")
|
|
check_reject(service, func(): return service.sell_equipment("bad-sell", revision, "missing", 0), "equipment_unavailable")
|
|
check_reject(service, func(): return service.equip("bad-target", revision, "missing", "missing", ""), "equipment_target_invalid")
|
|
check_reject(service, func(): return service.unequip("bad-unequip", revision, String(service.state.current_run.company[0]), "missing"), "equipped_item_mismatch")
|
|
check_reject(service, func(): return service.set_offer_lock("bad-lock-price", revision, recruit_id, true, 3), "price_mismatch")
|
|
check_reject(service, func(): return service.set_offer_lock("bad-lock-kind", revision, battle_id, true, 2), "offer_not_lockable")
|
|
check_reject(service, func(): return service.refresh_market("bad-refresh-price", revision, 999), "price_mismatch")
|
|
check_reject(service, func(): return service.commit_deployment("bad-deploy-empty", revision, []), "deployment_invalid")
|
|
check_reject(service, func(): return service.commit_deployment("bad-deploy-dupe", revision, [service.state.current_run.company[0], service.state.current_run.company[0]]), "deployment_invalid")
|
|
check_reject(service, func(): return service.commit_deployment("bad-deploy-unknown", revision, ["missing"]), "deployment_invalid")
|
|
check_reject(service, func(): return service.confirm_dismissal("bad-dismiss", revision, "missing", 0, 2, ""), "recruit_unavailable")
|
|
check_reject(service, func(): return service.commit_battle_offer("bad-board", revision, battle_id, "bad"), "board_hash_mismatch")
|
|
check_reject(service, func(): return service.commit_battle_offer("bad-battle", revision, "missing", String(service.state.current_run.market_board.board_hash)), "battle_offer_unavailable")
|
|
var before_bad_restore: Dictionary = service.state.snapshot()
|
|
var duplicate_deployment := before_bad_restore.duplicate(true)
|
|
duplicate_deployment.current_run.deployed_recruit_ids.append(duplicate_deployment.current_run.deployed_recruit_ids[0])
|
|
expect(not service.restore_snapshot(duplicate_deployment) and service.state.snapshot() == before_bad_restore, "duplicate deployed member snapshot rejects without replacing active state")
|
|
var bad_wearer := before_bad_restore.duplicate(true)
|
|
var first_instance: String = String(bad_wearer.current_run.inventory.keys()[0])
|
|
bad_wearer.current_run.inventory[first_instance].wearer_id = "missing"
|
|
expect(not service.restore_snapshot(bad_wearer) and service.state.snapshot() == before_bad_restore, "unknown equipment wearer snapshot rejects without replacing active state")
|
|
|
|
var locked = service.set_offer_lock("atomic-lock", service.state.revision, recruit_id, true, 2)
|
|
check_applied(service, locked, revision + 1, "lock success")
|
|
var after_lock = service.state.snapshot()
|
|
var duplicate = service.set_offer_lock("atomic-lock", revision, recruit_id, true, 2)
|
|
expect(duplicate.ok and duplicate.duplicate and service.state.snapshot() == after_lock, "same operation returns stored applied receipt")
|
|
check_reject(service, func(): return service.set_offer_lock("atomic-lock", revision, equipment_id, true, 2), "operation_id_conflict")
|
|
|
|
var no_coin = service.state.snapshot()
|
|
no_coin.current_run.coin = 0
|
|
expect(service.restore_snapshot(no_coin), "zero-Coin fixture remains valid")
|
|
check_reject(service, func(): return service.hire("no-coin-hire", service.state.revision, recruit_id, 14, false), "insufficient_coin")
|
|
check_reject(service, func(): return service.buy_equipment("no-coin-buy", service.state.revision, equipment_id, int(service.inspect_equipment_offer(equipment_id).receipt.list_price)), "insufficient_coin")
|
|
check_reject(service, func(): return service.refresh_market("no-coin-refresh", service.state.revision, Service.refresh_cost(0, 1)), "insufficient_coin")
|
|
|
|
var encounter_service = created_service()
|
|
var encounter_battle = String(encounter_service.state.current_run.available_battle_offer_ids[0])
|
|
expect(encounter_service.commit_battle_offer("enter-battle", encounter_service.state.revision, encounter_battle, String(encounter_service.state.current_run.market_board.board_hash)).ok, "fixture enters Encounter")
|
|
check_reject(encounter_service, func(): return encounter_service.hire("battle-hire", encounter_service.state.revision, String(encounter_service.state.current_run.available_recruit_offer_ids[0]), 14, false), "market_required")
|
|
check_reject(encounter_service, func(): return encounter_service.refresh_market("battle-refresh", encounter_service.state.revision, 6), "market_required")
|
|
check_reject(encounter_service, func(): return encounter_service.commit_deployment("battle-deploy", encounter_service.state.revision, Array(encounter_service.state.current_run.deployed_recruit_ids).duplicate()), "market_required")
|
|
|
|
if failures.is_empty():
|
|
print("ABG_P10_0_TRANSACTION_ATOMICITY_OK applied=%d rejected=%d malformed_restore=2 public_snapshot=preserved internal_fields=preserved stale=true price=true capacity=true eligibility=true conflict=true duplicate=true encounter_lock=true" % [applied, rejected])
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func created_service():
|
|
var service = Service.new()
|
|
expect(service.begin_run_creation("fixture-begin", 0, "CTR-R1-01", "standard").ok, "fixture begin")
|
|
var draft_id = String(service.state.run_creation_draft.draft_id)
|
|
expect(service.materialize_opening_offers("fixture-materialize", service.state.revision, draft_id).ok, "fixture materialize")
|
|
var ids: Array[String] = []
|
|
for offer in service.state.run_creation_draft.opening_offers:
|
|
ids.append(String(offer.source_offer_id))
|
|
expect(service.set_opening_selection("fixture-select", service.state.revision, [ids[0], ids[1]]).ok, "fixture select")
|
|
expect(service.commit_run_creation("fixture-commit", service.state.revision, draft_id, 1, [ids[0], ids[1]], String(service.state.run_creation_draft.opening_offer_set_hash)).ok, "fixture commit")
|
|
return service
|
|
|
|
|
|
func check_reject(service, call: Callable, expected_code: String) -> void:
|
|
var before = service.state.snapshot()
|
|
var result: Dictionary = call.call()
|
|
expect(not result.ok and result.code == expected_code and service.state.snapshot() == before, "%s rejection preserves complete state; got %s" % [expected_code, str(result)])
|
|
if not result.ok and result.code == expected_code and service.state.snapshot() == before:
|
|
rejected += 1
|
|
|
|
|
|
func check_applied(service, result: Dictionary, expected_revision: int, label: String) -> void:
|
|
expect(result.ok and result.applied and service.state.revision == expected_revision, "%s increments exactly one revision" % label)
|
|
if result.ok and result.applied and service.state.revision == expected_revision:
|
|
applied += 1
|
|
|
|
|
|
func expect(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append("P10.0 atomicity: %s" % message)
|