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.
63 lines
4.2 KiB
GDScript
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}
|