Reconstruct the approved contained 16:9 commitment page with engine-owned risk facts, frozen Party actors, transparent hit areas and explicit confirmation before the idempotent Battle Opening handoff. Add focused responsive behavior coverage and update the battle UI fixture for the confirmation boundary.
209 lines
9.4 KiB
GDScript
209 lines
9.4 KiB
GDScript
extends SceneTree
|
|
|
|
const EntryShell = preload("res://entry/entry_shell.gd")
|
|
const SettingsStore = preload("res://entry/settings_store.gd")
|
|
const DraftService = preload("res://entry/initial_company_draft_service.gd")
|
|
const ContractService = preload("res://entry/guild_contract_service.gd")
|
|
const FormationService = preload("res://entry/formation_risk_service.gd")
|
|
const BattleService = preload("res://entry/battle_service.gd")
|
|
|
|
const DRAFT_PATH := "user://rsk002_runtime_draft.json"
|
|
const COMPANY_PATH := "user://rsk002_runtime_company.json"
|
|
const SEED := "2468ace013579bdffedcba9876543210"
|
|
const CONTRACT_OP := "11112222333344445555666677778888"
|
|
const HIRE_OP_1 := "aaaabbbbccccddddeeeeffff00001111"
|
|
const HIRE_OP_2 := "99998888777766665555444433332222"
|
|
const ORDER_OP := "0123456789abcdef0123456789abcdef"
|
|
const READY_OP := "fedcba9876543210fedcba9876543210"
|
|
|
|
var failures: Array[String] = []
|
|
var parsed_touches := 0
|
|
var capture_root := ""
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
capture_root = OS.get_environment("ABG_RSK002_CAPTURE_DIR")
|
|
_cleanup()
|
|
root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
|
|
root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND
|
|
for viewport_size in [Vector2i(760, 360), Vector2i(844, 390), Vector2i(1280, 720)]:
|
|
root.size = viewport_size
|
|
for locale in ["zh_CN", "en"]:
|
|
_cleanup()
|
|
var company := _create_prepared_company()
|
|
if not company.is_empty():
|
|
await _verify_page(company, locale, viewport_size)
|
|
else:
|
|
failures.append("RSK-002 Runtime: fixture creation failed at %s %s" % [locale, viewport_size])
|
|
_cleanup()
|
|
if failures.is_empty():
|
|
print("ABG_RSK002_COMMITMENT_OK explicit_confirmation=true precommit_receipts=0 receipt_count=1 idempotent=true battle_handoff=true actors=4 facts=6 targets=48px locales=zh_CN,en viewports=760x360,844x390,1280x720 text_100=true parsed_touch=%d" % parsed_touches)
|
|
quit()
|
|
return
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
return
|
|
|
|
|
|
func _verify_page(company: Dictionary, locale: String, viewport_size: Vector2i) -> void:
|
|
var settings := SettingsStore.new().defaults()
|
|
settings.setup_completed = true
|
|
settings.locale = locale
|
|
settings.text_scale = 1.0
|
|
var viewport := SubViewport.new()
|
|
viewport.size = viewport_size
|
|
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
|
root.add_child(viewport)
|
|
var shell := EntryShell.new()
|
|
shell.auto_start = false
|
|
shell.initial_company_service.path = DRAFT_PATH
|
|
shell.initial_company_service.company_path = COMPANY_PATH
|
|
viewport.add_child(shell)
|
|
await _frames(3)
|
|
shell.settings = settings
|
|
shell.setup_draft = settings.duplicate(true)
|
|
shell.risk_selected_id = String(company.active_contract.formation.risk_options[1].risk_option_id)
|
|
var before: Dictionary = _draft_service().load_company()
|
|
var before_hash := String(before.company.company_hash)
|
|
shell.show_risk_commitment(company)
|
|
await _frames(3)
|
|
await _capture(shell, "%dx%d-%s-before" % [viewport_size.x, viewport_size.y, locale])
|
|
expect(shell.current_screen == "risk_commitment", "%s %s enters commitment page" % [locale, viewport_size])
|
|
expect(shell.find_child("RiskCommitmentStaticMaster", true, false) != null, "%s static master is present" % locale)
|
|
expect(shell.find_child("RiskFrozenMembers", true, false).get_child_count() == 4, "%s exact four frozen members" % locale)
|
|
expect(shell.find_child("RiskConsequenceFact0", true, false) != null and shell.find_child("RiskConsequenceFact5", true, false) != null, "%s six consequence facts" % locale)
|
|
var begin := shell.find_child("RiskBeginBattle", true, false) as Button
|
|
var acknowledge := shell.find_child("RiskCommitmentAcknowledge", true, false) as Button
|
|
var settings_button := shell.find_child("RiskCommitmentSettings", true, false) as Button
|
|
expect(begin != null and begin.disabled, "%s Begin Battle is disabled before acknowledgement" % locale)
|
|
expect(acknowledge != null and not acknowledge.disabled, "%s acknowledgement is available" % locale)
|
|
var precommit: Dictionary = _draft_service().load_company()
|
|
expect(not Dictionary(precommit.company.active_contract).has("battle_receipts"), "%s no receipt before acknowledgement" % locale)
|
|
expect(String(_draft_service().load_company().company.company_hash) == before_hash, "%s precommit state is unchanged" % locale)
|
|
for control in [settings_button, acknowledge, begin, shell.find_child("RiskCommitmentCancel", true, false) as Button]:
|
|
if control != null:
|
|
expect(control.get_global_rect().size.x >= 48.0 and control.get_global_rect().size.y >= 48.0, "%s command target meets 48px" % locale)
|
|
await _touch(acknowledge)
|
|
await _capture(shell, "%dx%d-%s-ready" % [viewport_size.x, viewport_size.y, locale])
|
|
expect(shell.find_child("RiskCommitmentAcknowledge", true, false).get_meta("confirmed", false), "%s acknowledgement state is explicit" % locale)
|
|
begin = shell.find_child("RiskBeginBattle", true, false) as Button
|
|
expect(begin != null and not begin.disabled, "%s Begin Battle enables only after acknowledgement" % locale)
|
|
await _touch(begin)
|
|
expect(shell.current_screen == "battle", "%s acknowledgement hands off to BAT-001" % locale)
|
|
var started: Dictionary = _draft_service().load_company()
|
|
expect(started.ok and Array(started.company.active_contract.get("battle_receipts", [])).size() == 1, "%s exactly one battle receipt" % locale)
|
|
var battle: Dictionary = started.company.active_contract.battle_state
|
|
var snapshot: Dictionary = company.active_contract.formation.accepted_party_snapshot
|
|
expect(Array(battle.front_to_rear_ids) == Array(snapshot.front_to_rear_ids), "%s handoff preserves Party order" % locale)
|
|
expect(String(battle.snapshot_hash) == String(snapshot.snapshot_hash), "%s handoff preserves Party snapshot" % locale)
|
|
shell._invalidate_battle_playback()
|
|
shell.begin_battle()
|
|
await _frames(3)
|
|
var duplicate: Dictionary = _draft_service().load_company()
|
|
expect(Array(duplicate.company.active_contract.get("battle_receipts", [])).size() == 1, "%s duplicate input remains idempotent" % locale)
|
|
expect(String(duplicate.company.active_contract.battle_state.operation_id) == String(battle.operation_id), "%s duplicate returns original operation" % locale)
|
|
shell.queue_free()
|
|
viewport.queue_free()
|
|
await _frames(10)
|
|
|
|
|
|
func _create_prepared_company() -> Dictionary:
|
|
var draft: Dictionary = _draft_service().begin_or_load(SEED)
|
|
if not draft.ok:
|
|
return {}
|
|
_draft_service().set_selection([String(draft.draft.offers[0].offer_id), String(draft.draft.offers[2].offer_id)])
|
|
var committed: Dictionary = _draft_service().commit_company()
|
|
if not committed.ok:
|
|
return {}
|
|
var created: Dictionary = _contract_service().create_contract(CONTRACT_OP, "CTR-R1-01", "standard")
|
|
if not created.ok:
|
|
return {}
|
|
var offers: Array = created.company.active_contract.market_board.recruit_offers
|
|
_contract_service().hire_recruit(HIRE_OP_1, String(offers[0].source_offer_id), 14)
|
|
var hired: Dictionary = _contract_service().hire_recruit(HIRE_OP_2, String(offers[1].source_offer_id), 14)
|
|
if not hired.ok:
|
|
return {}
|
|
var begun: Dictionary = _formation_service().begin_formation()
|
|
var saved: Dictionary = _formation_service().save_order(ORDER_OP, begun.formation.base_front_to_rear_ids)
|
|
var ready: Dictionary = _formation_service().accept_readiness(READY_OP, String(saved.receipt.order_hash))
|
|
return ready.company if ready.ok else {}
|
|
|
|
|
|
func _draft_service() -> RefCounted:
|
|
var service := DraftService.new()
|
|
service.path = DRAFT_PATH
|
|
service.company_path = COMPANY_PATH
|
|
return service
|
|
|
|
|
|
func _contract_service() -> RefCounted:
|
|
var service := ContractService.new()
|
|
service.company_path = COMPANY_PATH
|
|
return service
|
|
|
|
|
|
func _formation_service() -> RefCounted:
|
|
var service := FormationService.new()
|
|
service.company_path = COMPANY_PATH
|
|
return service
|
|
|
|
|
|
func _touch(control: Control) -> void:
|
|
if control == null:
|
|
expect(false, "touch target exists")
|
|
return
|
|
var center := control.get_global_rect().get_center()
|
|
var press := InputEventScreenTouch.new()
|
|
press.position = center
|
|
press.pressed = true
|
|
press.index = 0
|
|
control.get_viewport().push_input(press)
|
|
var mouse_press := InputEventMouseButton.new()
|
|
mouse_press.position = center
|
|
mouse_press.button_index = MOUSE_BUTTON_LEFT
|
|
mouse_press.pressed = true
|
|
control.get_viewport().push_input(mouse_press)
|
|
await _frames(2)
|
|
var release := InputEventScreenTouch.new()
|
|
release.position = center
|
|
release.pressed = false
|
|
release.index = 0
|
|
control.get_viewport().push_input(release)
|
|
var mouse_release := InputEventMouseButton.new()
|
|
mouse_release.position = center
|
|
mouse_release.button_index = MOUSE_BUTTON_LEFT
|
|
mouse_release.pressed = false
|
|
control.get_viewport().push_input(mouse_release)
|
|
parsed_touches += 1
|
|
await _frames(5)
|
|
|
|
|
|
func _frames(count: int) -> void:
|
|
for _index in range(count):
|
|
await process_frame
|
|
|
|
|
|
func _capture(shell: Control, name: String) -> void:
|
|
if capture_root.is_empty() or not is_instance_valid(shell):
|
|
return
|
|
DirAccess.make_dir_recursive_absolute(capture_root)
|
|
await RenderingServer.frame_post_draw
|
|
var image := shell.get_viewport().get_texture().get_image()
|
|
image.save_png(capture_root.path_join(name + ".png"))
|
|
|
|
|
|
func _cleanup() -> void:
|
|
for path in [DRAFT_PATH, "%s.bak" % DRAFT_PATH, "%s.candidate" % DRAFT_PATH, "%s.bak.candidate" % DRAFT_PATH, COMPANY_PATH, "%s.bak" % COMPANY_PATH, "%s.candidate" % COMPANY_PATH, "%s.bak.candidate" % COMPANY_PATH, "%s.corrupt" % COMPANY_PATH]:
|
|
if FileAccess.file_exists(path):
|
|
DirAccess.remove_absolute(path)
|
|
|
|
|
|
func expect(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append("RSK-002 Runtime: %s" % message)
|