extends SceneTree const EntryShell = preload("res://entry/entry_shell.gd") const InitialCompanyArt = preload("res://entry/initial_company_art.gd") const SettingsStore = preload("res://entry/settings_store.gd") const DraftService = preload("res://entry/initial_company_draft_service.gd") const DRAFT_PATH := "user://dev2_initial_company_choice_test.json" const ERROR_PATH := "user://dev2_initial_company_choice_error.json" const SEED := "89abcdef0123456776543210fedcba98" var failures: Array[String] = [] func _initialize() -> void: call_deferred("run_test") func run_test() -> void: _cleanup() verify_profession_art_registry() await verify_choice_inspect_compare_selection_and_restart() await verify_corrupt_draft_error_and_back() _cleanup() if failures.is_empty(): print("ABG_DEV2_CHOICE_OK title=true offers=4 inspect=true compare=true selected=0,1,2 third_blocked=true review_gate=true restart=true error=true back=true") quit(0) else: for failure in failures: push_error(failure) quit(1) func verify_choice_inspect_compare_selection_and_restart() -> void: var shell = await _shell(DRAFT_PATH) shell.show_title() shell.open_new_game_boundary() await _frames(3) var page = shell.initial_company_page expect(shell.current_screen == "initial_company", "Title New Game opens Initial Company") expect(page.find_child("CandidateRow", true, false).get_child_count() == 4, "choice page renders exactly four equal offer columns") expect(page.find_child("SelectedCount", true, false).text.contains("0/2"), "choice begins at 0/2") expect(page.find_child("ReviewCompany", true, false).disabled, "Review is disabled at 0/2") var original_ids := _offer_ids(page.draft) verify_candidate_stickers(page) page.inspect_candidate(2) await _frames(2) expect(page.mode == "inspect" and page.find_child("InspectBody", true, false) != null and page.find_child("InspectPortraitStagePortrait", true, false) != null, "Inspect opens complete portrait-led candidate detail") expect(page.draft.selected_offer_ids.is_empty(), "Inspect does not change selection") page.set_compare_a() await _frames(2) expect(page.compare_a_index == 2 and page.mode == "choice", "inspected candidate can be assigned to Compare A") page.inspect_candidate(0) page.set_compare_b() await _frames(2) expect(page.compare_b_index == 0 and not page.find_child("OpenCompare", true, false).disabled, "a different inspected candidate enables Compare") page.show_compare() await _frames(2) expect(page.mode == "compare" and page.find_child("ComparePortraitAPortrait", true, false) != null and page.find_child("ComparePortraitBPortrait", true, false) != null, "Compare renders two Recruit stickers together") expect(page.draft.selected_offer_ids.is_empty(), "Compare does not change selection") page.request_back() await _frames(2) page.toggle_candidate(0) await _frames(2) expect(page.draft.selected_offer_ids == [original_ids[0]] and page.find_child("ReviewCompany", true, false).disabled, "one selection persists and keeps Review disabled") page.toggle_candidate(1) await _frames(2) expect(page.draft.selected_offer_ids == [original_ids[0], original_ids[1]], "second independent selection persists") expect(not page.find_child("ReviewCompany", true, false).disabled and page.find_child("SelectedCount", true, false).text.contains("2/2"), "exactly 2/2 enables Review") page.toggle_candidate(2) await _frames(2) expect(page.draft.selected_offer_ids == [original_ids[0], original_ids[1]], "third selection attempt leaves the selected pair unchanged") expect(not page.notice.is_empty(), "third selection attempt gives a visible reason") page.request_review() await _frames(2) expect(page.mode == "review" and page.find_child("ReviewSelectedPortrait_0Portrait", true, false) != null and page.find_child("ReviewSelectedPortrait_1Portrait", true, false) != null and page.find_child("ReviewUnchosenPortrait_0", true, false) != null, "enabled Review shows selected and unchosen Recruit stickers") page.revise_selection() await _frames(2) expect(page.mode == "choice" and page.draft.selected_offer_ids.size() == 2, "Revise returns to the same draft and pair") page.request_back() await _frames(2) expect(shell.current_screen == "title", "choice Back returns to Title") shell.queue_free() await _frames(3) var restarted = await _shell(DRAFT_PATH) restarted.show_initial_company() await _frames(3) var restored = restarted.initial_company_page expect(_offer_ids(restored.draft) == original_ids, "restart restores the same four IDs and positions") expect(restored.draft.selected_offer_ids == [original_ids[0], original_ids[1]], "restart restores the selected pair") expect(not restored.find_child("ReviewCompany", true, false).disabled, "restart restores 2/2 Review gating") restarted.queue_free() await _frames(3) func verify_corrupt_draft_error_and_back() -> void: _write(ERROR_PATH, "{broken") _write("%s.bak" % ERROR_PATH, "{also broken") var shell = await _shell(ERROR_PATH) shell.show_initial_company() await _frames(3) var page = shell.initial_company_page expect(page.find_child("DraftErrorCode", true, false) != null and page.find_child("DraftErrorCode", true, false).text.contains("DRAFT_CORRUPT"), "corrupt replicas show the exact safe error") expect(page.find_child("DraftErrorRetry", true, false) != null and page.find_child("DraftErrorBack", true, false) != null, "error state provides Retry and Back") page.request_back() await _frames(2) expect(shell.current_screen == "title", "error Back returns to Title") shell.queue_free() await _frames(3) func _shell(draft_path: String): var shell = EntryShell.new() shell.auto_start = false shell.initial_company_service.path = draft_path shell.initial_company_service.company_path = "%s.company" % draft_path root.add_child(shell) await _frames(2) shell.settings = SettingsStore.new().defaults() shell.settings.setup_completed = true shell.settings.locale = "en" if draft_path == DRAFT_PATH: var service = DraftService.new() service.path = draft_path service.company_path = "%s.company" % draft_path service.begin_or_load(SEED) return shell func _offer_ids(draft: Dictionary) -> Array[String]: var result: Array[String] = [] for offer in draft.offers: result.append(String(offer.offer_id)) return result func verify_profession_art_registry() -> void: var paths: Array[String] = [] for index in range(1, 13): var profession_id := "PF-B%02d" % index var texture: Texture2D = InitialCompanyArt.texture_for({"profession_id": profession_id}) expect(texture != null and not texture.resource_path.is_empty(), "%s has a runtime Recruit sticker" % profession_id) paths.append(texture.resource_path) expect(paths.duplicate().size() == 12 and _unique(paths).size() == 12, "all 12 base Professions use one-to-one Recruit stickers") func verify_candidate_stickers(page: Control) -> void: var paths: Array[String] = [] for index in range(4): var portrait := page.find_child("CandidatePortrait_%d" % index, true, false) as TextureRect var expected: Texture2D = InitialCompanyArt.texture_for(page.draft.offers[index]) expect(portrait != null and portrait.texture == expected, "candidate %d is a person-bearing control with the matching Profession sticker" % index) if portrait != null and portrait.texture != null: paths.append(portrait.texture.resource_path) expect(_unique(paths).size() == 4, "the four visible candidates do not reuse one character image") func _unique(values: Array[String]) -> Array[String]: var result: Array[String] = [] for value in values: if value not in result: result.append(value) return result func _write(file_path: String, text: String) -> void: var file := FileAccess.open(file_path, FileAccess.WRITE) file.store_string(text) file.close() func _cleanup() -> void: for base in [DRAFT_PATH, ERROR_PATH]: for suffix in ["", ".bak", ".candidate", ".bak.candidate", ".corrupt"]: var file_path := "%s%s" % [base, suffix] if FileAccess.file_exists(file_path): DirAccess.remove_absolute(file_path) var company_base := "%s.company" % base for suffix in ["", ".bak", ".candidate", ".bak.candidate", ".corrupt"]: var company_file := "%s%s" % [company_base, suffix] if FileAccess.file_exists(company_file): DirAccess.remove_absolute(company_file) func _frames(count: int) -> void: for frame in range(count): await process_frame func expect(condition: bool, message: String) -> void: if not condition: failures.append("DEV-2 Recruit choice: %s" % message)