156 lines
6.7 KiB
GDScript
156 lines
6.7 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 DRAFT_PATH := "user://m10_review_draft.json"
|
|
const COMPANY_PATH := "user://m10_review_company.json"
|
|
const SEED := "0123456789abcdeffedcba9876543210"
|
|
const CONTRACT_OP := "abcdefabcdefabcdefabcdefabcdefab"
|
|
const HIRE_OP := "11112222333344445555666677778888"
|
|
|
|
var failures: Array[String] = []
|
|
var parsed_touches := 0
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
_cleanup()
|
|
root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
|
|
root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND
|
|
root.size = Vector2i(844, 390)
|
|
var company := _create_company()
|
|
expect(not company.is_empty(), "fixture creates a valid Company and stable Market board")
|
|
if not company.is_empty():
|
|
await _verify_review(company)
|
|
_cleanup()
|
|
if failures.is_empty():
|
|
print("ABG_M10_RECRUIT_REVIEW_OK stable_offer=true facts=profession,trait,attributes,item,history,price,impact cancel=same_offer_focus_restored hire=one_receipt duplicate=original company=2->3 line=4 coin=52->38 resize=true parsed_touch=%d" % parsed_touches)
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func _verify_review(company: Dictionary) -> void:
|
|
var offer: Dictionary = company.active_contract.market_board.recruit_offers[0]
|
|
var offer_id := String(offer.source_offer_id)
|
|
var before_hash := String(company.company_hash)
|
|
var settings := SettingsStore.new().defaults()
|
|
settings.setup_completed = true
|
|
settings.locale = "zh_CN"
|
|
settings.text_scale = 1.0
|
|
var shell := EntryShell.new()
|
|
shell.auto_start = false
|
|
shell.initial_company_service.path = DRAFT_PATH
|
|
shell.initial_company_service.company_path = COMPANY_PATH
|
|
root.add_child(shell)
|
|
await _frames(3)
|
|
shell.settings = settings.duplicate(true)
|
|
shell.show_recruit_review(offer_id)
|
|
await _frames(4)
|
|
expect(shell.current_screen == "recruit_review", "review opens from a stable source_offer_id")
|
|
for node_name in ["RecruitReviewProfession", "RecruitReviewTrait", "RecruitReviewAttributes", "RecruitReviewItem", "RecruitReviewHistory", "RecruitReviewImpact", "RecruitReviewPrice"]:
|
|
var node := shell.find_child(node_name, true, false) as Label
|
|
expect(node != null and not node.text.is_empty(), "%s is engine-owned and visible" % node_name)
|
|
expect(shell.find_child("RecruitReviewPortraitTexture", true, false) != null, "review keeps a complete person-bearing portrait")
|
|
expect(String(shell.find_child("RecruitReviewImpact", true, false).text).contains("2 → 3"), "impact distinguishes Company growth")
|
|
expect(String(shell.find_child("RecruitReviewImpact", true, false).text).contains("4"), "impact keeps Line capacity separate")
|
|
expect(String(_load_company().company.company_hash) == before_hash, "review inspection does not mutate Company")
|
|
for control_name in ["RecruitReviewCancel", "RecruitHire"]:
|
|
var button := shell.find_child(control_name, true, false) as Button
|
|
expect(button != null and button.get_global_rect().size.x >= 48.0 and button.get_global_rect().size.y >= 48.0, "%s keeps a 48px target" % control_name)
|
|
var cancel := shell.find_child("RecruitReviewCancel", true, false) as Button
|
|
await _touch(cancel)
|
|
var returned := shell.find_child("MarketOffer%s" % offer_id, true, false) as Button
|
|
expect(shell.current_screen == "market" and shell.market_selected_offer_id == offer_id, "Cancel returns to the same offer")
|
|
expect(returned != null and returned.has_focus(), "Cancel restores focus to the invoking offer")
|
|
# Exercise live resize while the local selection is retained.
|
|
root.size = Vector2i(760, 360)
|
|
await _frames(3)
|
|
root.size = Vector2i(844, 390)
|
|
await _frames(3)
|
|
shell.show_recruit_review(offer_id)
|
|
await _frames(3)
|
|
var hire := shell.find_child("RecruitHire", true, false) as Button
|
|
expect(hire != null and not hire.disabled, "Hire is enabled only at the owning review boundary")
|
|
await _touch(hire)
|
|
var after := _load_company()
|
|
expect(after.ok and int(after.company.owned_recruits.size()) == 3, "Hire commits one Recruit")
|
|
if after.ok:
|
|
expect(int(after.company.active_contract.coin) == 38, "Hire spends the exact sourced price")
|
|
expect(after.company.active_contract.hire_receipts.size() == 1, "Hire writes one receipt")
|
|
var receipt: Dictionary = after.company.active_contract.hire_receipts[0]
|
|
var service := ContractService.new()
|
|
service.company_path = COMPANY_PATH
|
|
var duplicate := service.hire_recruit(String(receipt.operation_id), offer_id, int(offer.list_price))
|
|
expect(duplicate.ok and duplicate.code == "already_hired" and duplicate.company.active_contract.hire_receipts.size() == 1 and int(duplicate.company.active_contract.coin) == 38, "duplicate Hire returns original receipt without a second charge")
|
|
shell.queue_free()
|
|
await _frames(3)
|
|
|
|
|
|
func _create_company() -> Dictionary:
|
|
var draft_service := DraftService.new()
|
|
draft_service.path = DRAFT_PATH
|
|
draft_service.company_path = COMPANY_PATH
|
|
var draft := 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[1].offer_id)])
|
|
var committed := draft_service.commit_company()
|
|
if not committed.ok:
|
|
return {}
|
|
var contract := ContractService.new()
|
|
contract.company_path = COMPANY_PATH
|
|
var created := contract.create_contract(CONTRACT_OP, "CTR-R1-01", "standard")
|
|
return created.company if created.ok else {}
|
|
|
|
|
|
func _load_company() -> Dictionary:
|
|
var service := DraftService.new()
|
|
service.path = DRAFT_PATH
|
|
service.company_path = COMPANY_PATH
|
|
return service.load_company()
|
|
|
|
|
|
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
|
|
Input.parse_input_event(press)
|
|
await _frames(2)
|
|
var release := InputEventScreenTouch.new()
|
|
release.position = center
|
|
release.pressed = false
|
|
release.index = 0
|
|
Input.parse_input_event(release)
|
|
parsed_touches += 1
|
|
await _frames(5)
|
|
|
|
|
|
func _frames(count: int) -> void:
|
|
for _index in range(count):
|
|
await process_frame
|
|
|
|
|
|
func _cleanup() -> void:
|
|
for path in [DRAFT_PATH, COMPANY_PATH, "%s.bak" % DRAFT_PATH, "%s.bak" % COMPANY_PATH, "%s.candidate" % DRAFT_PATH, "%s.candidate" % COMPANY_PATH, "%s.bak.candidate" % DRAFT_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("M10 SHP-002: %s" % message)
|