196 lines
10 KiB
GDScript
196 lines
10 KiB
GDScript
extends SceneTree
|
|
|
|
const BattleService = preload("res://p10_3/deep_channels_battle_service.gd")
|
|
const Controller = preload("res://p10_3/runtime_controller.gd")
|
|
const Fixture = preload("res://tests/p10_3/deep_channels_fixture.gd")
|
|
const GrowthService = preload("res://p10_3/growth_service.gd")
|
|
const PreparationService = preload("res://p10_3/deep_channels_preparation_service.gd")
|
|
const ResolutionService = preload("res://p10_3/deep_channels_resolution_service.gd")
|
|
|
|
var capture_root := ""
|
|
var captures := 0
|
|
var experience
|
|
var failures: Array[String] = []
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
capture_root = OS.get_environment("ABG_P10_3_LAYOUT_CAPTURE_ROOT")
|
|
if not capture_root.is_empty():
|
|
DirAccess.make_dir_recursive_absolute(capture_root)
|
|
await fixture("01-market5-small-zh", Fixture.new().migrated_snapshot(), Vector2i(760, 360), "zh_CN", 1.0, false, false, Controller.P103_SCREEN_MARKET)
|
|
await fixture("02-market6-reference-en130", Fixture.new().progressed_market_snapshot(6), Vector2i(844, 390), "en", 1.3, false, false, Controller.P103_SCREEN_MARKET)
|
|
await fixture("03-plan-large-zh", Fixture.new().prepared_service(6, 2).state.snapshot(), Vector2i(1280, 720), "zh_CN", 1.0, false, false, Controller.P103_SCREEN_PLAN)
|
|
await battle_fixture("04-battle-reference-en", Vector2i(844, 390), "en", 1.0, false, false, 28)
|
|
await result_fixture("05-result-small-zh130", Vector2i(760, 360), "zh_CN", 1.3)
|
|
await fixture("06-artifact-reference-zh", Fixture.new().market_7_snapshot(true), Vector2i(844, 390), "zh_CN", 1.0, false, false, Controller.P103_SCREEN_ARTIFACT)
|
|
await fixture("07-promotion-large-en130", promotion_snapshot(), Vector2i(1280, 720), "en", 1.3, false, false, Controller.P103_SCREEN_PROMOTION)
|
|
await fixture("08-recovery-reference-zh", recovery_snapshot(), Vector2i(844, 390), "zh_CN", 1.0, false, false, Controller.P103_SCREEN_RECOVERY)
|
|
await fixture("09-market8-large-reduced", market_eight_snapshot(), Vector2i(1280, 720), "zh_CN", 1.0, true, false, Controller.P103_SCREEN_MARKET_8)
|
|
await settings_fixture("10-settings-reference-en130", Fixture.new().migrated_snapshot(), Vector2i(844, 390), "en", 1.3)
|
|
await fixture("11-market-low-power", Fixture.new().progressed_market_snapshot(6), Vector2i(844, 390), "zh_CN", 1.0, false, true, Controller.P103_SCREEN_MARKET)
|
|
await fixture("12-portrait-guidance", Fixture.new().migrated_snapshot(), Vector2i(390, 844), "zh_CN", 1.0, false, false, Controller.P103_SCREEN_MARKET, true)
|
|
if is_instance_valid(experience):
|
|
experience.queue_free()
|
|
await settle_frames(45)
|
|
if failures.is_empty():
|
|
print("ABG_P10_3_LAYOUT_ACCESSIBILITY_OK fixtures=12 states=market5,market6,plan,battle,result,artifact,promotion,recovery,market8,settings,low_power,rotate viewports=760x360,844x390,1280x720,390x844 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: Dictionary, viewport: Vector2i, locale: String, scale: float, reduced: bool, low_power: bool, expected_screen: String, portrait := false) -> void:
|
|
await mount(snapshot, viewport, locale, scale, reduced, low_power)
|
|
expect(experience.screen == expected_screen, "%s restores %s; got %s" % [label, expected_screen, experience.screen])
|
|
verify_current(label, viewport, portrait)
|
|
await capture(label)
|
|
|
|
|
|
func battle_fixture(label: String, viewport: Vector2i, locale: String, scale: float, reduced: bool, low_power: bool, ticks: int) -> void:
|
|
var prepared = Fixture.new().prepared_service(6, 1)
|
|
await mount(prepared.state.snapshot(), viewport, locale, scale, reduced, low_power)
|
|
var route_id := String(prepared.state.current_run.pending_encounter.route_id)
|
|
experience.choose_region_plan(String(BattleService.PREFERRED_PLAN[route_id]))
|
|
experience.advance_region_battle_ticks(ticks)
|
|
await settle_frames()
|
|
expect(experience.screen == Controller.P103_SCREEN_BATTLE and not experience.region_battle_complete, "%s shows live battle" % label)
|
|
expect(not experience.find_children("P101BattleActor_*", "TextureRect", true, false).is_empty(), "%s shows the Company line" % label)
|
|
expect(not experience.find_children("P101BattleEnemy_*", "TextureRect", true, false).is_empty(), "%s shows entered enemies" % label)
|
|
verify_current(label, viewport, false)
|
|
await capture(label)
|
|
|
|
|
|
func result_fixture(label: String, viewport: Vector2i, locale: String, scale: float) -> void:
|
|
var prepared = Fixture.new().prepared_service(5, 0)
|
|
await mount(prepared.state.snapshot(), viewport, locale, scale, false, false)
|
|
var route_id := String(prepared.state.current_run.pending_encounter.route_id)
|
|
experience.choose_region_plan(String(BattleService.PREFERRED_PLAN[route_id]))
|
|
experience.advance_region_battle_ticks(999)
|
|
await settle_frames()
|
|
expect(experience.region_battle_complete and experience.find_child("P101BattleResultBand", true, false) != null, "%s shows the terminal result" % label)
|
|
var header := Rect2(Vector2.ZERO, Vector2(viewport.x, 50))
|
|
for node in experience.find_children("P101MotionDamage_*", "Label", true, false):
|
|
var damage := node as Label
|
|
expect(not header.intersects(damage.get_global_rect()), "%s damage feedback %s stays below the header; got %s" % [label, damage.name, damage.get_global_rect()])
|
|
verify_current(label, viewport, false)
|
|
await capture(label)
|
|
|
|
|
|
func settings_fixture(label: String, snapshot: Dictionary, viewport: Vector2i, locale: String, scale: float) -> void:
|
|
await mount(snapshot, viewport, locale, scale, true, false)
|
|
experience.toggle_settings()
|
|
await settle_frames()
|
|
expect(experience.find_child("P100SettingsBand", true, false) != null, "%s exposes inherited settings" % label)
|
|
verify_current(label, viewport, false)
|
|
await capture(label)
|
|
|
|
|
|
func promotion_snapshot() -> Dictionary:
|
|
var growth := GrowthService.new(Fixture.new().market_7_snapshot(true))
|
|
var selected := growth.select_artifact("layout-artifact", growth.state.revision, String(growth.state.current_run.artifact_draft.draft_hash), "AR-012")
|
|
if not selected.ok:
|
|
return {}
|
|
var opened := growth.open_promotion_draft("layout-promotion-open", growth.state.revision)
|
|
return growth.state.snapshot() if opened.ok else {}
|
|
|
|
|
|
func recovery_snapshot() -> Dictionary:
|
|
var prepared = Fixture.new().prepared_service(7, 2, "AR-012")
|
|
var battle: Dictionary = BattleService.new(prepared.state.snapshot()).run_to_terminal("focus_source")
|
|
var resolver := ResolutionService.new(prepared.state.snapshot())
|
|
var settled := resolver.settle("layout-recovery", resolver.state.revision, battle.snapshot)
|
|
return resolver.state.snapshot() if settled.ok else {}
|
|
|
|
|
|
func market_eight_snapshot() -> Dictionary:
|
|
var growth := GrowthService.new(Fixture.new().market_7_snapshot(true))
|
|
var selected := growth.select_artifact("layout-market8-artifact", growth.state.revision, String(growth.state.current_run.artifact_draft.draft_hash), "AR-012")
|
|
if not selected.ok:
|
|
return {}
|
|
var opened := growth.open_promotion_draft("layout-market8-promotion-open", growth.state.revision)
|
|
if not opened.ok:
|
|
return {}
|
|
var draft: Dictionary = growth.state.current_run.promotion_draft
|
|
var promoted := growth.confirm_promotion("layout-market8-promotion", growth.state.revision, String(draft.draft_hash), String(draft.recruit_id), String(draft.current_profession_id), "PF-A13")
|
|
if not promoted.ok:
|
|
return {}
|
|
var preparation := PreparationService.new(growth.state.snapshot())
|
|
var route: Dictionary = preparation.state.current_run.market_board.battle_offers[2]
|
|
var prepared := preparation.commit_route("layout-market8-route", preparation.state.revision, String(route.offer_id), String(preparation.state.current_run.market_board.board_hash))
|
|
if not prepared.ok:
|
|
return {}
|
|
var battle := BattleService.new(preparation.state.snapshot()).run_to_terminal(String(BattleService.PREFERRED_PLAN[String(route.route_id)]))
|
|
if not battle.ok:
|
|
return {}
|
|
var resolver := ResolutionService.new(preparation.state.snapshot())
|
|
var settled := resolver.settle("layout-market8-settle", resolver.state.revision, battle.snapshot)
|
|
return resolver.state.snapshot() if settled.ok else {}
|
|
|
|
|
|
func mount(snapshot: Dictionary, viewport: Vector2i, locale: String, scale: float, reduced: bool, low_power: 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.persistence_enabled = false
|
|
experience.battle_auto_advance = false
|
|
experience.locale = locale
|
|
experience.text_scale = scale
|
|
experience.reduced_motion = reduced
|
|
experience.muted = true
|
|
experience.low_power = low_power
|
|
experience.size = Vector2(viewport)
|
|
experience.configure_entry(snapshot)
|
|
root.add_child(experience)
|
|
await settle_frames()
|
|
|
|
|
|
func verify_current(label: String, viewport: Vector2i, portrait: bool) -> void:
|
|
var bounds := Rect2(Vector2.ZERO, Vector2(viewport))
|
|
if portrait:
|
|
expect(experience.find_child("P97RotateNotice", true, false) != null, "%s shows landscape guidance" % label)
|
|
return
|
|
expect(experience.find_child("P97RotateNotice", true, false) == null, "%s renders the landscape world" % label)
|
|
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 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("P10.3 layout: %s" % message)
|