Files
TheTree_mock/tests/helpers/ui_audio_fixture_cleanup.gd
T
Takeshi b84bade045 Save The Tree implementation and acceptance work in progress
Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
2026-10-11 15:58:00 +09:00

63 lines
4.2 KiB
GDScript

extends RefCounted
## QA ordinary Main destruction only; application/window close is separate QA.
## Reuse the existing four fixtures' real WeakRef/mixer drain without editing it.
const ExistingCleanup := preload("res://tests/helpers/ui_audio_teardown.gd")
const OWNER_META := &"_the_tree_ui_close_owners"
static func free_owner_and_wait(tree: SceneTree, owner: Node) -> Dictionary:
var owner_id: int = owner.get_instance_id() if is_instance_valid(owner) else 0
var controls_before: Dictionary = _controls(tree)
# ExistingCleanup captures weak audio targets synchronously before queue_free.
# Only weak targets cross its await. It neither changes Clock flags nor calls
# application close, and Main._exit_tree keeps the ordinary owner contract.
var audio: Dictionary = await ExistingCleanup.free_owner_and_wait(tree, owner, 500000)
var controls_after: Dictionary = _controls(tree)
var before_owners: Array = controls_before[&"owner_ids"]
var expected_remaining: Array = before_owners.duplicate()
expected_remaining.erase(owner_id)
var ordinary_release: bool = bool(controls_before[&"owner_meta_present"]) and not bool(controls_before[&"closing"]) and before_owners.has(owner_id)
if expected_remaining.is_empty():
ordinary_release = ordinary_release and not bool(controls_after[&"owner_meta_present"]) and bool(controls_after[&"auto_accept_quit"]) == bool(controls_before[&"original_auto_accept_quit"])
else:
ordinary_release = ordinary_release and bool(controls_after[&"owner_meta_present"]) and not bool(controls_after[&"closing"]) and controls_after[&"owner_ids"] == expected_remaining and not bool(controls_after[&"auto_accept_quit"])
var clock_unchanged: bool = controls_before[&"clock_process"] == controls_after[&"clock_process"] and controls_before[&"clock_physics_process"] == controls_after[&"clock_physics_process"] and controls_before[&"clock_process_mode"] == controls_after[&"clock_process_mode"]
var root_input_unchanged: bool = controls_before[&"root_gui_disable_input"] == controls_after[&"root_gui_disable_input"]
var report: Dictionary = {&"owned_engine_pid": OS.get_process_id(), &"owner_instance_id": owner_id,
&"before": controls_before, &"after": controls_after, &"expected_remaining_owner_ids": expected_remaining,
&"ordinary_owner_release_verified": ordinary_release, &"clock_process_flags_unchanged": clock_unchanged,
&"root_gui_input_flag_unchanged": root_input_unchanged, &"audio_teardown_passed": bool(audio.get(&"passed", false)),
&"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0,
&"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false,
&"application_close_called": false, &"SceneTree_quit_overridden": false,
&"WindowQuit_verified": false, &"formal_acceptance": false}
report[&"passed"] = bool(audio.get(&"passed", false)) and ordinary_release and clock_unchanged and root_input_unchanged
var path: String = OS.get_environment("THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF")
if path.is_empty() or not path.is_absolute_path() or FileAccess.file_exists(path):
report[&"passed"] = false
return report
var file: FileAccess = FileAccess.open(path, FileAccess.WRITE)
if file == null:
report[&"passed"] = false
return report
file.store_string(JSON.stringify(report, "\t") + "\n")
file.close()
return report
static func _controls(tree: SceneTree) -> Dictionary:
# Local strong Node/WeakRef.get_ref results are released on helper return.
var clock: Node = tree.root.get_node("GameClock")
var present: bool = tree.root.has_meta(OWNER_META)
var state: Dictionary = tree.root.get_meta(OWNER_META) if present else {}
var ids: Array = []
for reference: WeakRef in state.get(&"owners", []):
var node: Variant = reference.get_ref()
if is_instance_valid(node):
ids.append(node.get_instance_id())
ids.sort()
return {&"clock_process": clock.is_processing(), &"clock_physics_process": clock.is_physics_processing(),
&"clock_process_mode": clock.process_mode, &"root_gui_disable_input": tree.root.gui_disable_input,
&"auto_accept_quit": tree.auto_accept_quit, &"owner_meta_present": present,
&"original_auto_accept_quit": bool(state.get(&"original_auto_accept_quit", tree.auto_accept_quit)),
&"closing": bool(state.get(&"closing", false)), &"owner_ids": ids}