Files
aetherbound-guild/runtime/tests/fg2/graybox_layout_test.gd
T

123 lines
5.7 KiB
GDScript

extends SceneTree
const Controller = preload("res://campaign/fg2_graybox_controller.gd")
const Fixture = preload("res://campaign/fg2_fixture.gd")
var failures: Array[String] = []
var experience
var capture_root := ""
var captures := 0
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
capture_root = OS.get_environment("ABG_FG2_CAPTURE_ROOT")
if not capture_root.is_empty():
DirAccess.make_dir_recursive_absolute(capture_root)
await fixture("01-market-small-zh", Fixture.canonical_market_state(), Vector2i(760, 360), "zh_CN", 1.0, Controller.SCREEN_MARKET, "380x180@2x")
await fixture("02-market-reference-en130", Fixture.canonical_market_state(), Vector2i(844, 390), "en", 1.3, Controller.SCREEN_MARKET, "422x195@2x")
await fixture("03-market-large-zh", Fixture.canonical_market_state(), Vector2i(1280, 720), "zh_CN", 1.0, Controller.SCREEN_MARKET, "320x180@4x")
await battle_fixture("04-battle-reference-zh", Vector2i(844, 390), "zh_CN", 1.0)
await fixture("05-reward-reference-en", Fixture.reward_market_state(), Vector2i(844, 390), "en", 1.0, Controller.SCREEN_REWARD, "422x195@2x")
await fixture("06-recovery-reference-zh130", Fixture.recovery_market_state(), Vector2i(844, 390), "zh_CN", 1.3, Controller.SCREEN_RECOVERY, "422x195@2x")
await reduced_fixture("07-battle-reduced-low-power", Vector2i(844, 390))
if is_instance_valid(experience):
experience.queue_free()
for _index in 45:
await process_frame
if failures.is_empty():
print("ABG_FG2_GRAYBOX_LAYOUT_OK fixtures=7 states=market,battle,reward,recovery grids=380x180@2x,422x195@2x,320x180@4x viewports=760x360,844x390,1280x720 locales=zh_CN,en text_130=true reduced_motion=true muted=true low_power=true controls=48 panels=0 cards=0 captures=%d" % captures)
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func fixture(label: String, snapshot_value: Dictionary, viewport: Vector2i, locale_value: String, scale_value: float, expected_screen: String, expected_grid: String) -> void:
await mount(snapshot_value, viewport, locale_value, scale_value, false, false)
expect(experience.screen == expected_screen, "%s restores %s" % [label, expected_screen])
expect(String(experience.get_meta("logical_grid", "")) == expected_grid, "%s uses %s" % [label, expected_grid])
verify_current(label, viewport)
await capture(label)
func battle_fixture(label: String, viewport: Vector2i, locale_value: String, scale_value: float) -> void:
await mount(Fixture.canonical_encounter_state(), viewport, locale_value, scale_value, false, false)
experience.advance_battle_ticks(96)
await settle_frames()
expect(experience.screen == Controller.SCREEN_BATTLE and not experience.view.battle.enemies.is_empty(), "%s shows the real Company and enemy together" % label)
verify_current(label, viewport)
await capture(label)
func reduced_fixture(label: String, viewport: Vector2i) -> void:
await mount(Fixture.canonical_encounter_state(), viewport, "zh_CN", 1.0, true, true)
experience.advance_battle_ticks(96)
await settle_frames()
expect(experience.reduced_motion and experience.low_power and experience.muted, "%s retains all resource variants" % label)
verify_current(label, viewport)
await capture(label)
func mount(snapshot_value: Dictionary, viewport: Vector2i, locale_value: String, scale_value: float, reduced: bool, low_power_value: bool) -> void:
if is_instance_valid(experience):
experience.queue_free()
await settle_frames(12)
root.size = viewport
root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND
root.content_scale_size = viewport
experience = Controller.new()
experience.battle_auto_advance = false
experience.locale = locale_value
experience.text_scale = scale_value
experience.reduced_motion = reduced
experience.low_power = low_power_value
experience.muted = true
experience.size = Vector2(viewport)
experience.configure_entry(snapshot_value)
root.add_child(experience)
await settle_frames(8)
func verify_current(label: String, viewport: Vector2i) -> void:
var bounds := Rect2(Vector2.ZERO, Vector2(viewport))
expect(float(experience.get_meta("visible_world_ratio", 0.0)) >= 0.80, "%s keeps world-first composition" % label)
expect(experience.find_children("*", "Panel", true, false).is_empty(), "%s adds no app Panel surfaces" % label)
for layer_name in ["BackgroundLayer", "MidgroundLayer", "ActorsLayer", "ForegroundLayer", "VfxLayer"]:
expect(experience.find_child(layer_name, true, false) != null, "%s retains %s" % [label, layer_name])
for node in experience.find_children("*", "Button", true, false):
var button := node as Button
if not button.visible or button.is_queued_for_deletion():
continue
expect(button.size.x >= 48 and button.size.y >= 48, "%s target %s is at least 48px" % [label, button.name])
expect(bounds.encloses(button.get_global_rect()), "%s target %s stays inside %s" % [label, button.name, viewport])
for node in experience.find_children("*", "Control", true, false):
var lowered := String(node.name).to_lower()
expect("card" not in lowered and "modal" not in lowered and "dialog" not in lowered, "%s has no card/modal surface: %s" % [label, node.name])
func capture(label: String) -> void:
if capture_root.is_empty():
return
await RenderingServer.frame_post_draw
var error := root.get_texture().get_image().save_png(capture_root.path_join(label + ".png"))
expect(error == OK, "%s capture writes" % label)
if error == OK:
captures += 1
await process_frame
func settle_frames(count := 5) -> void:
for _index in count:
await process_frame
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("FG-2 graybox layout: %s" % message)