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://m09_market_runtime_draft.json" const COMPANY_PATH := "user://m09_market_runtime_company.json" const SEED := "0f1e2d3c4b5a69788796a5b4c3d2e1f0" const CONTRACT_OPERATION := "abcdef0123456789abcdef0123456789" var failures: Array[String] = [] var parsed_touches := 0 func _initialize() -> void: call_deferred("run_test") func run_test() -> void: root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND root.content_scale_size = Vector2i(760, 360) root.size = Vector2i(760, 360) _cleanup() var company := _create_company() if company.is_empty(): _finish() return 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 shell.show_market(company) await _frames(5) var canvas := shell.find_child("MarketMasterCanvas", true, false) as Control var master := shell.find_child("MarketStaticMaster", true, false) as TextureRect expect(shell.current_screen == "market", "Market runtime opens on the active Contract") expect(canvas != null and master != null, "contained canvas and clean static master are present") if canvas != null: var canvas_rect := canvas.get_global_rect() expect(is_equal_approx(canvas_rect.size.x / canvas_rect.size.y, 16.0 / 9.0), "Market canvas preserves 16:9") expect(Rect2(Vector2.ZERO, Vector2(760, 360)).encloses(canvas_rect), "Market canvas remains inside the viewport") var offer_list := shell.find_child("MarketOfferList", true, false) as Control expect(offer_list != null and offer_list.get_child_count() == 3, "three equal Recruit offers are rendered") if offer_list != null: for offer_button in offer_list.get_children(): var button := offer_button as Control if button == null: continue expect(button.get_global_rect().size.y >= 48.0, "%s keeps a 48px logical target" % button.name) expect(shell.find_child("MarketNoSelection", true, false) != null, "opening state has no auto-selected offer") expect(shell.find_child("MarketCompanyStatus", true, false) != null and shell.find_child("MarketCoinStatus", true, false) != null, "Company/Line and Coin remain engine-owned visible facts") expect(shell.find_child("MarketCategoryEquipment", true, false) != null and shell.find_child("MarketCategoryBattle", true, false) != null, "equipment and route modes remain reachable") var authority_hash := String(_load_company().company.company_hash) var recruit_id := String(company.active_contract.market_board.recruit_offers[0].source_offer_id) await _touch(shell.find_child("MarketOffer%s" % recruit_id, true, false)) expect(shell.market_selected_kind == "recruit" and shell.market_selected_offer_id == recruit_id, "Recruit selection is local and source-ID bound") expect(String(_load_company().company.company_hash) == authority_hash, "list selection does not mutate Company") await _touch(shell.find_child("MarketReviewRecruit", true, false)) expect(shell.current_screen == "recruit_review", "Review action opens the owning Recruit review boundary") await _touch(shell.find_child("RecruitReviewCancel", true, false)) var returned := shell.find_child("MarketOffer%s" % recruit_id, true, false) as Button expect(shell.current_screen == "market" and shell.market_selected_offer_id == recruit_id and returned != null and returned.has_focus(), "cancel returns to the same offer and restores focus") await _touch(shell.find_child("MarketCategoryEquipment", true, false)) var equipment_list := shell.find_child("MarketOfferList", true, false) as Control expect(shell.market_category == "equipment" and equipment_list != null and equipment_list.get_child_count() == 4, "equipment mode exposes four inspectable offers") var equipment_id := String(company.active_contract.market_board.equipment_offers[0].offer_id) await _touch(shell.find_child("MarketOffer%s" % equipment_id, true, false)) expect(shell.market_selected_kind == "equipment" and shell.find_child("MarketReviewRecruit", true, false) == null, "equipment selection cannot trigger Recruit hire") await _touch(shell.find_child("MarketCategoryBattle", true, false)) var battle_list := shell.find_child("MarketOfferList", true, false) as Control expect(shell.market_category == "battle" and battle_list != null and battle_list.get_child_count() == 3, "route mode exposes three inspectable routes") var battle_id := String(company.active_contract.market_board.battle_offers[0].offer_id) await _touch(shell.find_child("MarketOffer%s" % battle_id, true, false)) expect(shell.market_selected_kind == "battle" and shell.find_child("MarketReviewRecruit", true, false) == null, "route selection remains inspection-only") expect(String(_load_company().company.company_hash) == authority_hash, "all Market inspections preserve authoritative Company state") shell.queue_free() await _frames(3) _finish() func _create_company() -> Dictionary: var draft_service := DraftService.new() draft_service.path = DRAFT_PATH draft_service.company_path = COMPANY_PATH var draft: Dictionary = draft_service.begin_or_load(SEED) if not draft.ok: expect(false, "fixture creates Initial Company draft") 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: expect(false, "fixture commits Initial Company") return {} var contract_service := ContractService.new() contract_service.company_path = COMPANY_PATH var created: Dictionary = contract_service.create_contract(CONTRACT_OPERATION, "CTR-R1-01", "standard") expect(created.ok, "fixture creates first Contract") 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 := root.get_final_transform() * 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 _cleanup() -> void: for base in [DRAFT_PATH, COMPANY_PATH]: for suffix in ["", ".bak", ".candidate", ".bak.candidate", ".corrupt"]: var path := "%s%s" % [base, suffix] if FileAccess.file_exists(path): DirAccess.remove_absolute(path) func _frames(count: int) -> void: for _frame in range(count): await process_frame func _finish() -> void: _cleanup() if failures.is_empty(): print("ABG_M09_MARKET_RUNTIME_OK canvas=16:9 offers=3 equipment=4 routes=3 inspect_only=true review_boundary=true company_unchanged=true parsed_touch=%d" % parsed_touches) quit(0) else: for failure in failures: push_error(failure) quit(1) func expect(condition: bool, message: String) -> void: if not condition: failures.append("M09 Market Runtime: %s" % message)