Files
aetherbound-guild/runtime/tests/p9_0_layout_test.gd
T

104 lines
3.4 KiB
GDScript

extends SceneTree
const MainScene = preload("res://main.tscn")
const FIXTURES := [
{"size": Vector2i(1280, 720), "locale": "zh_CN", "scale": 1.0},
{"size": Vector2i(844, 390), "locale": "en", "scale": 1.0},
{"size": Vector2i(390, 844), "locale": "zh_CN", "scale": 1.3},
]
const PAGES := ["boot", "title"]
var failures: Array[String] = []
var fixture_count := 0
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
for fixture in FIXTURES:
for page in PAGES:
await verify_fixture(fixture, page)
if failures.is_empty():
print("ABG_P9_0_LAYOUT_OK fixtures=%d viewports=3 pages=2 locales=2 text_130=true min_touch=44" % fixture_count)
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func verify_fixture(fixture: Dictionary, page_name: String) -> void:
var viewport := SubViewport.new()
viewport.size = fixture.size
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
root.add_child(viewport)
var game := MainScene.instantiate()
game.auto_boot = false
viewport.add_child(game)
await settle()
game.locale = fixture.locale
game.text_scale = fixture.scale
game.page = game.AppPage.BOOT if page_name == "boot" else game.AppPage.TITLE
game.boot_verified = page_name == "title"
game.render()
await settle()
fixture_count += 1
var label := "%sx%s/%s/%s/%s" % [fixture.size.x, fixture.size.y, fixture.locale, str(fixture.scale), page_name]
var bounds := Rect2(Vector2.ZERO, Vector2(fixture.size))
var screen_name := "BootScreen" if page_name == "boot" else "TitleScreen"
var screen := find_control(game, screen_name)
expect(screen != null, "%s missing %s" % [label, screen_name])
if screen != null:
expect(contains_rect(bounds, screen.get_global_rect()), "%s screen outside viewport: %s" % [label, screen.get_global_rect()])
if page_name == "boot":
expect(find_control(game, "StartNewGame") == null, "%s exposes Start before verification" % label)
else:
expect(find_control(game, "NoRunStatus") != null, "%s missing no-run state" % label)
expect(find_control(game, "StartNewGame") != null, "%s missing primary action" % label)
verify_interactive_bounds(game, bounds, label)
game.queue_free()
viewport.queue_free()
await drain_cleanup()
func verify_interactive_bounds(node: Node, bounds: Rect2, label: String) -> void:
if node is BaseButton and node.is_visible_in_tree():
var rect: Rect2 = node.get_global_rect()
expect(contains_rect(bounds, rect), "%s button %s outside viewport: %s" % [label, node.name, rect])
expect(rect.size.x >= 44.0 and rect.size.y >= 44.0, "%s button %s below 44pt: %s" % [label, node.name, rect.size])
for child in node.get_children():
verify_interactive_bounds(child, bounds, label)
func find_control(node: Node, node_name: String) -> Control:
if node.name == node_name and node is Control and not node.is_queued_for_deletion():
return node
for child in node.get_children():
var found := find_control(child, node_name)
if found != null:
return found
return null
func contains_rect(outer: Rect2, inner: Rect2) -> bool:
return inner.position.x >= -0.5 and inner.position.y >= -0.5 and inner.end.x <= outer.end.x + 0.5 and inner.end.y <= outer.end.y + 0.5
func settle() -> void:
for frame in range(6):
await process_frame
func drain_cleanup() -> void:
for frame in range(30):
await process_frame
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("P9.0 layout: %s" % message)