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 FIXTURES := [ {"width": 760, "height": 360, "locale": "zh_CN", "scale": 1.0}, {"width": 844, "height": 390, "locale": "en", "scale": 1.0}, {"width": 1280, "height": 720, "locale": "zh_CN", "scale": 1.0}, {"width": 1280, "height": 720, "locale": "en", "scale": 1.0}, ] const SEED := "13579bdf02468ace13579bdf02468ace" var failures: Array[String] = [] var output_root := "" func _initialize() -> void: call_deferred("run_capture") func run_capture() -> void: output_root = OS.get_environment("ABG_EVIDENCE_DIR") if output_root.is_empty(): output_root = "/tmp/abg-m19-contract-choice-captures" DirAccess.make_dir_recursive_absolute(output_root) var requested := OS.get_environment("ABG_CAPTURE_FIXTURE_INDEX") var indexes := range(FIXTURES.size()) if not requested.is_empty(): var index := requested.to_int() if index < 0 or index >= FIXTURES.size() or str(index) != requested: push_error("invalid ABG_CAPTURE_FIXTURE_INDEX=%s" % requested) quit(2) return indexes = [index] for index in indexes: await _capture(index, FIXTURES[index]) if failures.is_empty(): print("ABG_M19_CONTRACT_CHOICE_CAPTURE_OK frames=%d state=contract_choice matrix=760x360,844x390,1280x720:zh_CN,en:100 layout=inside renderer=normal" % indexes.size()) quit(0) else: for failure in failures: push_error(failure) quit(1) func _capture(index: int, fixture: Dictionary) -> void: var draft_path := "user://m19_contract_capture_%d.json" % index var company_path := "%s.company" % draft_path _cleanup_path(draft_path) var company := _create_company(draft_path, company_path) if company.is_empty(): failures.append("fixture %d could not create Company" % index) return var viewport := SubViewport.new() viewport.size = Vector2i(int(fixture.width), int(fixture.height)) 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) var settings := SettingsStore.new().defaults() settings.setup_completed = true settings.locale = String(fixture.locale) settings.text_scale = float(fixture.scale) shell.settings = settings shell.setup_draft = settings.duplicate(true) shell.show_contract_choice() await _frames(6) _verify(shell, viewport.size, index) await RenderingServer.frame_post_draw var image := viewport.get_texture().get_image() if image.is_empty() or image.get_width() != int(fixture.width) or image.get_height() != int(fixture.height): failures.append("fixture %d did not produce a complete frame" % index) else: var file_name := "contract-choice-%dx%d-%s-100.png" % [int(fixture.width), int(fixture.height), String(fixture.locale)] if image.save_png(output_root.path_join(file_name)) != OK: failures.append("fixture %d capture could not be saved" % index) shell.queue_free() viewport.queue_free() await _frames(4) _cleanup_path(draft_path) func _verify(shell: Control, viewport_size: Vector2i, index: int) -> void: expect(shell.current_screen == "contract_choice", "fixture %d opens Contract Choice" % index) expect(shell.contract_choice_view_data.get("page_id", "") == "contract_choice", "fixture %d stores controller view data" % index) for name in ["ContractCompanyMember_0", "ContractCompanyMember_1", "ContractDifficultySegments", "ContractDifficultyWayfinder", "ContractDifficultyStandard", "ContractDifficultyStormbound", "ContractDifficultyIronOath", "ContractDifficultyCopy", "ContractCreationFacts", "ContractConfirm"]: expect(shell.find_child(name, true, false) != null, "fixture %d includes %s" % [index, name]) var bounds := Rect2(Vector2.ZERO, Vector2(viewport_size)) for node in _all_controls(shell): if not node.visible or node is TextureRect or node is ColorRect or node is Container: continue var rect := node.get_global_rect() if rect.size.x <= 0.0 or rect.size.y <= 0.0: continue if not bounds.encloses(rect): failures.append("fixture %d %s outside viewport: %s" % [index, node.name, rect]) func _all_controls(node: Node) -> Array[Control]: var result: Array[Control] = [] if node is Control: result.append(node) for child in node.get_children(): result.append_array(_all_controls(child)) return result func _create_company(draft_path: String, company_path: String) -> Dictionary: var service := DraftService.new() service.path = draft_path service.company_path = company_path var draft := service.begin_or_load(SEED) if not draft.ok: return {} service.set_selection([String(draft.draft.offers[0].offer_id), String(draft.draft.offers[2].offer_id)]) var committed := service.commit_company() return committed.company if committed.ok else {} func _cleanup_path(base: String) -> void: for suffix in ["", ".bak", ".candidate", ".bak.candidate", ".corrupt"]: for path in ["%s%s" % [base, suffix], "%s.company%s" % [base, suffix]]: if FileAccess.file_exists(path): DirAccess.remove_absolute(path) func _frames(count: int) -> void: for _index in range(count): await process_frame func expect(condition: bool, message: String) -> void: if not condition: failures.append("M19 Contract Choice capture: %s" % message)