Files
aetherbound-guild/runtime/tests/p10_1/candidate_matrix_test.gd
T

158 lines
6.5 KiB
GDScript

extends SceneTree
const Controller = preload("res://p10_1/runtime_controller.gd")
const Fixture = preload("res://tests/p10_1/runtime_fixture.gd")
const SaveV7 = preload("res://p10_1/save_v7_service.gd")
const ResolutionService = preload("res://p10_1/first_crossing_resolution_service.gd")
const VIEWPORTS := [Vector2i(760, 360), Vector2i(844, 390), Vector2i(1280, 720), Vector2i(390, 844)]
const LOCALES := ["zh_CN", "en"]
const TEXT_SCALES := [1.0, 1.3]
const ACCESSIBILITY := [
{"reduced": false, "low_power": false},
{"reduced": true, "low_power": true},
]
var failures: Array[String] = []
var experience
var save_cases := 0
var layout_cases := 0
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND
verify_save_phase_matrix()
await verify_layout_matrix()
if is_instance_valid(experience):
experience.queue_free()
await settle_frames(45)
if failures.is_empty():
print("ABG_P10_1_CANDIDATE_MATRIX_OK save_cases=%d phases=market,prepared,recovery,market2,recovered layout_cases=%d viewports=760x360,844x390,1280x720,390x844 locales=zh_CN,en text=100,130 reduced_motion=true low_power=true mute=true controls=48 panels=0 cards=0 offline_rewards=0" % [save_cases, layout_cases])
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func verify_save_phase_matrix() -> void:
var recovery: Dictionary = Fixture.recovery_snapshot()
var resolver = ResolutionService.new(recovery)
var recovered: Dictionary = resolver.recover(
"candidate-matrix-recover",
resolver.state.revision,
String(resolver.state.current_run.last_battle_report.battle_hash),
int(resolver.state.current_run.recovery_cost)
)
expect(recovered.ok, "recovered Market fixture applies")
var cases := [
{"name": "market", "snapshot": Fixture.market_snapshot(), "phase": "market"},
{"name": "prepared", "snapshot": Fixture.prepared_snapshot(2), "phase": "prepared"},
{"name": "recovery", "snapshot": recovery, "phase": "recovery"},
{"name": "market2", "snapshot": Fixture.market_2_snapshot(), "phase": "market_2"},
{"name": "recovered", "snapshot": resolver.state.snapshot(), "phase": "market"},
]
for index in range(cases.size()):
var row: Dictionary = cases[index]
var sequence := 70 + index
var encoded: Dictionary = SaveV7.new().encode_snapshot(row.snapshot, sequence)
expect(encoded.ok, "%s Save-v7 encodes" % row.name)
if not encoded.ok:
continue
var decoded: Dictionary = SaveV7.new().decode_text(String(encoded.text), sequence)
expect(decoded.ok and decoded.snapshot == row.snapshot, "%s Save-v7 roundtrip is exact" % row.name)
expect(decoded.offline_delta == SaveV7.OFFLINE_ZERO, "%s reload grants zero offline value" % row.name)
expect(String(decoded.snapshot.current_run.phase) == String(row.phase), "%s reload preserves phase" % row.name)
save_cases += 1
func verify_layout_matrix() -> void:
var state_index := 0
for viewport in VIEWPORTS:
for locale in LOCALES:
for text_scale in TEXT_SCALES:
for access in ACCESSIBILITY:
var state_kind := state_index % 5
await mount(layout_snapshot(state_kind), viewport, locale, text_scale, bool(access.reduced), bool(access.low_power))
if state_kind == 4 and viewport.x > viewport.y:
experience.choose_region_plan("follow_tide")
experience.region_battle_paused = true
experience.advance_region_battle_ticks(52)
await settle_frames()
verify_layout(viewport, state_kind)
layout_cases += 1
state_index += 1
func layout_snapshot(state_kind: int) -> Dictionary:
match state_kind:
0:
return Fixture.market_snapshot()
1:
return Fixture.prepared_snapshot(2)
2:
return Fixture.recovery_snapshot()
3:
return Fixture.market_2_snapshot()
_:
return Fixture.prepared_snapshot(2)
func mount(snapshot: Dictionary, viewport: Vector2i, locale: String, text_scale: float, reduced: bool, low_power: bool) -> void:
if is_instance_valid(experience):
experience.queue_free()
await settle_frames(8)
root.size = viewport
root.content_scale_size = viewport
experience = Controller.new()
experience.persistence_enabled = false
experience.battle_auto_advance = false
experience.locale = locale
experience.text_scale = text_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_layout(viewport: Vector2i, state_kind: int) -> void:
var bounds := Rect2(Vector2.ZERO, Vector2(viewport))
if viewport.y > viewport.x:
expect(experience.find_child("P97RotateNotice", true, false) != null, "portrait matrix shows rotation guidance")
return
expect(experience.find_child("P97RotateNotice", true, false) == null, "landscape matrix renders the game world")
expect(float(experience.get_meta("visible_world_ratio", 0.0)) >= 0.80, "landscape matrix remains world-first")
expect(experience.find_children("*", "Panel", true, false).is_empty(), "matrix adds no app Panel surfaces")
for node in experience.find_children("*", "Control", true, false):
var control := node as Control
if not control.visible or control.is_queued_for_deletion():
continue
var lowered := String(control.name).to_lower()
expect("card" not in lowered and "modal" not in lowered and "dialog" not in lowered, "matrix adds no card/modal surface: %s" % control.name)
expect(is_finite(control.position.x) and is_finite(control.position.y) and control.size.x >= 0.0 and control.size.y >= 0.0, "matrix control %s has finite geometry" % control.name)
if control is Button:
expect(control.size.x >= 48.0 and control.size.y >= 48.0, "matrix button %s is at least 48px" % control.name)
expect(bounds.encloses(control.get_global_rect()), "matrix button %s remains inside %s" % [control.name, viewport])
if state_kind == 4:
expect(experience.screen == Controller.REGION_SCREEN_BATTLE, "battle matrix reaches the live battle")
expect(not experience.find_children("P101BattleActor_*", "TextureRect", true, false).is_empty(), "battle matrix renders Company motion actors")
expect(not experience.find_children("P101BattleEnemy_*", "TextureRect", true, false).is_empty(), "battle matrix renders staged enemies")
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.1 candidate matrix: %s" % message)