144 lines
8.3 KiB
GDScript
144 lines
8.3 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 DRAFT_PATH := "user://hub001_layered_draft.json"
|
|
const COMPANY_PATH := "user://hub001_layered_company.json"
|
|
const SEED := "abcdef0123456789abcdef0123456789"
|
|
const SIZES := [Vector2i(760, 360), Vector2i(844, 390), Vector2i(1280, 720)]
|
|
|
|
var failures: Array[String] = []
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
_cleanup()
|
|
var company := _create_company()
|
|
var viewport := SubViewport.new()
|
|
viewport.size = SIZES[0]
|
|
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 = "zh_CN"
|
|
settings.text_scale = 1.3
|
|
shell.settings = settings
|
|
shell.show_guild_handoff(company)
|
|
await _frames(4)
|
|
for viewport_size in SIZES:
|
|
viewport.size = viewport_size
|
|
await _frames(3)
|
|
_verify_layered_page(shell, viewport_size)
|
|
shell.queue_free()
|
|
await _frames(3)
|
|
_cleanup()
|
|
if failures.is_empty():
|
|
print("ABG_HUB001_LAYERED_OK sizes=760x360,844x390,1280x720 composite=false layers=world,rails,actors,board fixed_caps=true center_stretch=true touch_min=48 text=engine")
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func _verify_layered_page(shell: Control, viewport_size: Vector2i) -> void:
|
|
expect(shell.find_child("GuildMasterBComposite", true, false) == null, "%s removes the coordinate-master composite" % viewport_size)
|
|
for node_name in [
|
|
"GuildMasterLayeredWorld", "GuildTopRail", "GuildTopRailLeft",
|
|
"GuildTopRailCenter", "GuildTopRailRight", "GuildBottomRail",
|
|
"GuildBottomRailLeft", "GuildBottomRailCenter", "GuildBottomRailRight",
|
|
"GuildMasterKioskTexture", "GuildMemberPortraitTexture_0",
|
|
"GuildMemberPortraitTexture_1", "GuildKioskCopyArea",
|
|
"GuildProgressStatusIcon", "GuildCoinStatusIcon", "GuildAnchorCompanyStatusIcon",
|
|
]:
|
|
expect(shell.find_child(node_name, true, false) != null, "%s has layered node %s" % [viewport_size, node_name])
|
|
var top_left := shell.find_child("GuildTopRailLeft", true, false) as TextureRect
|
|
var top_center := shell.find_child("GuildTopRailCenter", true, false) as TextureRect
|
|
var top_right := shell.find_child("GuildTopRailRight", true, false) as TextureRect
|
|
var bottom_left := shell.find_child("GuildBottomRailLeft", true, false) as TextureRect
|
|
var bottom_center := shell.find_child("GuildBottomRailCenter", true, false) as TextureRect
|
|
var bottom_right := shell.find_child("GuildBottomRailRight", true, false) as TextureRect
|
|
if top_left != null and top_center != null and top_right != null and bottom_left != null and bottom_center != null and bottom_right != null:
|
|
expect(top_left.stretch_mode == TextureRect.STRETCH_KEEP_ASPECT_CENTERED and top_right.stretch_mode == TextureRect.STRETCH_KEEP_ASPECT_CENTERED, "%s top caps keep aspect" % viewport_size)
|
|
expect(bottom_left.stretch_mode == TextureRect.STRETCH_KEEP_ASPECT_CENTERED and bottom_right.stretch_mode == TextureRect.STRETCH_KEEP_ASPECT_CENTERED, "%s bottom caps keep aspect" % viewport_size)
|
|
expect(top_center.stretch_mode == TextureRect.STRETCH_SCALE and bottom_center.stretch_mode == TextureRect.STRETCH_SCALE, "%s only clean centers stretch" % viewport_size)
|
|
expect(top_center.anchor_left <= 0.056 and top_center.anchor_right >= 0.953 and is_equal_approx(top_center.anchor_right, top_right.anchor_left), "%s top center meets both native-width fixed caps" % viewport_size)
|
|
expect(bottom_center.anchor_right >= 0.90 and bottom_right.anchor_left >= 0.90, "%s bottom stretch center meets the fixed Compass endcap" % viewport_size)
|
|
for button_name in ["GuildTitle", "GuildRosterButton", "GuildEquipment", "GuildParty", "GuildRisk", "GuildSettings"]:
|
|
var button := shell.find_child(button_name, true, false) as Button
|
|
expect(button != null, "%s has %s" % [viewport_size, button_name])
|
|
if button != null:
|
|
var rect := button.get_global_rect()
|
|
expect(rect.size.x >= 47.9 and rect.size.y >= 47.9, "%s %s meets 48px touch minimum: %s" % [viewport_size, button_name, rect.size])
|
|
if button_name in ["GuildRosterButton", "GuildEquipment", "GuildParty", "GuildRisk"]:
|
|
expect(rect.size.x <= 76.1 and rect.size.y <= 76.1, "%s %s stays inside the 76px responsive cap: %s" % [viewport_size, button_name, rect.size])
|
|
var chrome := button.find_child("Chrome", true, false) as Control
|
|
if button_name == "GuildTitle":
|
|
expect(chrome == null and String(button.get_meta("art_owned_control", "")) == "GuildTopRailLeft", "%s GuildTitle reuses the approved crest instead of adding a fifth bottom medallion" % viewport_size)
|
|
else:
|
|
expect(chrome != null, "%s %s has an authored semantic icon" % [viewport_size, button_name])
|
|
if chrome != null:
|
|
var expected_variant := "guild_status_icon" if button_name == "GuildSettings" else "guild_nav_icon"
|
|
expect(String(chrome.get("variant")) == expected_variant, "%s %s uses %s instead of shared icon geometry" % [viewport_size, button_name, expected_variant])
|
|
var nav_buttons := ["GuildRosterButton", "GuildEquipment", "GuildParty", "GuildRisk"]
|
|
for index in range(nav_buttons.size() - 1):
|
|
var left_button := shell.find_child(nav_buttons[index], true, false) as Button
|
|
var right_button := shell.find_child(nav_buttons[index + 1], true, false) as Button
|
|
if left_button != null and right_button != null:
|
|
var spacing := right_button.get_global_rect().position.x - left_button.get_global_rect().end.x
|
|
expect(spacing >= 3.9 and spacing <= 8.1, "%s bottom nav spacing remains compact: %.2f" % [viewport_size, spacing])
|
|
for label_name in ["GuildAnchorTitle", "GuildProgressStatus", "GuildCoinStatus", "GuildAnchorCompanyStatus", "GuildKioskText", "GuildContractReason", "GuildMarketReason"]:
|
|
expect(shell.find_child(label_name, true, false) is Label, "%s engine-renders %s" % [viewport_size, label_name])
|
|
for status_name in ["GuildProgressStatus", "GuildCoinStatus", "GuildAnchorCompanyStatus"]:
|
|
expect(shell.find_child("%sPill" % status_name, true, false) is Panel, "%s %s uses an inlaid value pill" % [viewport_size, status_name])
|
|
expect(shell.find_child("%sFrame" % status_name, true, false) == null, "%s %s has no opaque outer resource card" % [viewport_size, status_name])
|
|
var title_plate := shell.find_child("GuildTitlePlate", true, false) as Panel
|
|
var design_canvas := shell.find_child("GuildMasterDesignCanvas", true, false) as Control
|
|
if title_plate != null and design_canvas != null:
|
|
expect(title_plate.get_global_rect().size.x <= design_canvas.size.x * 0.151, "%s Guild identity stays within the approved compact width" % viewport_size)
|
|
for command_label in ["GuildTitleCommandLabel", "GuildRosterCommandLabel", "GuildEquipmentCommandLabel", "GuildPartyCommandLabel", "GuildRouteStatusLabel"]:
|
|
var label := shell.find_child(command_label, true, false) as Label
|
|
expect(label != null and not label.visible, "%s %s stays tooltip-owned instead of overlaying the approved icon rail" % [viewport_size, command_label])
|
|
var title := shell.find_child("GuildAnchorTitle", true, false) as Label
|
|
if title != null:
|
|
var title_size := title.get_theme_font_size("font_size")
|
|
expect(title_size >= (19 if viewport_size.y >= 700 else 11), "%s Guild title follows canvas-aware typography: %d" % [viewport_size, title_size])
|
|
|
|
|
|
func _create_company() -> Dictionary:
|
|
var service := DraftService.new()
|
|
service.path = DRAFT_PATH
|
|
service.company_path = COMPANY_PATH
|
|
var draft: Dictionary = service.begin_or_load(SEED)
|
|
service.set_selection([String(draft.draft.offers[0].offer_id), String(draft.draft.offers[2].offer_id)])
|
|
return service.commit_company().company
|
|
|
|
|
|
func _cleanup() -> void:
|
|
for base in [DRAFT_PATH, COMPANY_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)
|
|
|
|
|
|
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("HUB-001 layered reconstruction: %s" % message)
|