148 lines
4.6 KiB
GDScript
148 lines
4.6 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 STATES := ["contract", "offers", "market", "equipment", "order", "ready"]
|
|
|
|
var failures: Array[String] = []
|
|
var fixture_count := 0
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
for fixture in FIXTURES:
|
|
for state in STATES:
|
|
await verify_fixture(fixture, state)
|
|
if failures.is_empty():
|
|
print("ABG_P9_1_LAYOUT_OK fixtures=%d viewports=3 states=6 locales=2 text_130=true" % fixture_count)
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func verify_fixture(fixture: Dictionary, state: 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.boot_verified = true
|
|
game.page = game.AppPage.RUN
|
|
game.locale = fixture.locale
|
|
game.text_scale = fixture.scale
|
|
advance_to(game, state)
|
|
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), state]
|
|
var bounds := Rect2(Vector2.ZERO, Vector2(fixture.size))
|
|
for node_name in ["TopBar", "CurrentDecision", "Footer", "PrimaryAction"]:
|
|
var control := find_control(game, node_name)
|
|
expect(control != null, "%s missing %s" % [label, node_name])
|
|
if control != null:
|
|
expect(contains_rect(bounds, control.get_global_rect()), "%s %s outside viewport: %s" % [label, node_name, control.get_global_rect()])
|
|
var top := find_control(game, "TopBar")
|
|
var decision := find_control(game, "CurrentDecision")
|
|
var footer := find_control(game, "Footer")
|
|
if top != null and decision != null and footer != null:
|
|
expect(not top.get_global_rect().intersects(decision.get_global_rect()), "%s top overlaps decision" % label)
|
|
expect(not footer.get_global_rect().intersects(decision.get_global_rect()), "%s footer overlaps decision" % label)
|
|
verify_interactive_bounds(game, bounds, label)
|
|
game.queue_free()
|
|
viewport.queue_free()
|
|
await drain_cleanup()
|
|
|
|
|
|
func advance_to(game: Control, target: String) -> void:
|
|
if target == "contract":
|
|
return
|
|
game.run.select_contract()
|
|
game.run.select_difficulty("standard")
|
|
game.run.open_offers()
|
|
game.run.inspect_offer("OFF-03")
|
|
game.run.inspect_offer("OFF-04")
|
|
game.run.toggle_offer("OFF-03")
|
|
game.run.toggle_offer("OFF-04")
|
|
if target == "offers":
|
|
return
|
|
game.run.review_opening()
|
|
game.run.commit_opening()
|
|
game.run.open_market()
|
|
if target == "market":
|
|
return
|
|
game.run.hire("MKT-R1-01")
|
|
game.run.hire("MKT-R1-02")
|
|
if target == "equipment":
|
|
return
|
|
game.run.purchase_equipment()
|
|
game.run.equip_member("OFF-03")
|
|
if target == "order":
|
|
return
|
|
game.run.choose_order_unit("OFF-03")
|
|
game.run.choose_order_unit("MKT-R1-01")
|
|
game.run.commit_order()
|
|
|
|
|
|
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()
|
|
if inside_scroll(node):
|
|
expect(rect.position.x >= -0.5 and rect.end.x <= bounds.end.x + 0.5, "%s button %s has horizontal overflow: %s" % [label, node.name, rect])
|
|
else:
|
|
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 inside_scroll(node: Node) -> bool:
|
|
var current := node.get_parent()
|
|
while current != null:
|
|
if current is ScrollContainer:
|
|
return true
|
|
current = current.get_parent()
|
|
return false
|
|
|
|
|
|
func settle() -> void:
|
|
for frame in range(4):
|
|
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.1 layout: %s" % message)
|