extends SceneTree ## Asset-free lifecycle, ownership, dependency and timing regression for the ## lightweight-WMO render Resource cache state. const CACHE_STATE_SCRIPT := preload( "res://src/render/wmo/wmo_render_resource_cache_state.gd" ) const CACHE_STATE_PATH := "res://src/render/wmo/wmo_render_resource_cache_state.gd" const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd" func _initialize() -> void: var failures: Array[String] = [] _verify_invalid_and_request_state(failures) _verify_validated_resource_completion(failures) _verify_missing_completion_and_exclusivity(failures) _verify_transient_and_full_clear(failures) _verify_detached_sorted_diagnostics(failures) _verify_ownership_boundaries(failures) var elapsed_milliseconds := _verify_bounded_timing(failures) if not failures.is_empty(): for failure in failures: push_error("WMO_RENDER_RESOURCE_CACHE_STATE: %s" % failure) quit(1) return print( "WMO_RENDER_RESOURCE_CACHE_STATE PASS cases=10 iterations=100 elapsed_ms=%.3f" % elapsed_milliseconds ) quit(0) func _verify_invalid_and_request_state(failures: Array[String]) -> void: var cache_state: RefCounted = CACHE_STATE_SCRIPT.new() _expect_false( cache_state.call("remember_request", "", "res://cache.res"), "empty normalized path rejected", failures ) _expect_false( cache_state.call("remember_request", "world/a.wmo", ""), "empty cache path rejected", failures ) _expect_true( cache_state.call("remember_request", "world/a.wmo", "res://cache/a.res"), "valid request accepted", failures ) _expect_true( cache_state.call("has_request", "world/a.wmo"), "pending request observable", failures ) _expect_false( cache_state.call("remember_request", "world/a.wmo", "res://cache/other.res"), "duplicate request rejected", failures ) var request_snapshot: Dictionary = cache_state.call("request_paths_snapshot") _expect_string_equal( String(request_snapshot.get("world/a.wmo", "")), "res://cache/a.res", "request cache path preserved", failures ) request_snapshot.clear() _expect_true( cache_state.call("has_request", "world/a.wmo"), "request snapshot detached", failures ) func _verify_validated_resource_completion(failures: Array[String]) -> void: var cache_state: RefCounted = CACHE_STATE_SCRIPT.new() var validated_resource := Resource.new() cache_state.call("remember_request", "world/b.wmo", "res://cache/b.res") _expect_false( cache_state.call("complete_request_with_resource", "world/b.wmo", null), "null completion rejected", failures ) _expect_true( cache_state.call( "complete_request_with_resource", "world/b.wmo", validated_resource ), "validated Resource completes request", failures ) _expect_false( cache_state.call("has_request", "world/b.wmo"), "successful completion removes request", failures ) _expect_true( cache_state.call("contains_resource", "world/b.wmo"), "successful completion cached", failures ) _expect_true( cache_state.call("resource_for", "world/b.wmo") == validated_resource, "cached Resource identity preserved", failures ) _expect_false( cache_state.call("remember_request", "world/b.wmo", "res://cache/b2.res"), "cached path rejects request", failures ) func _verify_missing_completion_and_exclusivity(failures: Array[String]) -> void: var cache_state: RefCounted = CACHE_STATE_SCRIPT.new() _expect_false( cache_state.call("complete_request_as_missing", "world/unknown.wmo"), "unknown completion rejected", failures ) cache_state.call("remember_request", "world/missing.wmo", "res://cache/missing.res") _expect_true( cache_state.call("complete_request_as_missing", "world/missing.wmo"), "failed request completes as missing", failures ) _expect_true( cache_state.call("is_missing", "world/missing.wmo"), "negative cache observable", failures ) _expect_false( cache_state.call("has_request", "world/missing.wmo"), "missing completion removes request", failures ) _expect_false( cache_state.call( "remember_request", "world/missing.wmo", "res://cache/retry.res" ), "negative cache rejects request", failures ) func _verify_transient_and_full_clear(failures: Array[String]) -> void: var cache_state: RefCounted = CACHE_STATE_SCRIPT.new() var retained_resource := Resource.new() cache_state.call("remember_request", "world/retained.wmo", "res://cache/retained.res") cache_state.call( "complete_request_with_resource", "world/retained.wmo", retained_resource ) cache_state.call("remember_request", "world/pending.wmo", "res://cache/pending.res") cache_state.call("remember_request", "world/missing.wmo", "res://cache/missing.res") cache_state.call("complete_request_as_missing", "world/missing.wmo") cache_state.call("clear_transient_state") _expect_true( cache_state.call("resource_for", "world/retained.wmo") == retained_resource, "transient clear retains validated Resource", failures ) _expect_equal( int(cache_state.call("pending_request_count")), 0, "transient clear removes requests", failures ) _expect_false( cache_state.call("is_missing", "world/missing.wmo"), "transient clear removes negative cache", failures ) cache_state.call("clear_all") cache_state.call("clear_all") _expect_false( cache_state.call("contains_resource", "world/retained.wmo"), "full clear idempotently releases Resource", failures ) func _verify_detached_sorted_diagnostics(failures: Array[String]) -> void: var cache_state: RefCounted = CACHE_STATE_SCRIPT.new() for normalized_path in ["world/z.wmo", "world/a.wmo"]: cache_state.call("remember_request", normalized_path, "res://cache/%s.res" % normalized_path) var snapshot: Dictionary = cache_state.call("diagnostic_snapshot") _expect_string_array( snapshot["request_paths"], ["world/a.wmo", "world/z.wmo"], "request diagnostics sorted", failures ) (snapshot["request_paths"] as Array).clear() var fresh_snapshot: Dictionary = cache_state.call("diagnostic_snapshot") _expect_equal( (fresh_snapshot["request_paths"] as Array).size(), 2, "diagnostics detached", failures ) func _verify_ownership_boundaries(failures: Array[String]) -> void: var loader_source := _read_text(LOADER_PATH, failures) var cache_state_source := _read_text(CACHE_STATE_PATH, failures) _expect_true( loader_source.contains("WMO_RENDER_RESOURCE_CACHE_STATE_SCRIPT.new()"), "loader composes cache state", failures ) for legacy_field in [ "var _wmo_render_cache:", "var _wmo_render_missing_cache:", "var _wmo_render_load_requests:", ]: _expect_false( loader_source.contains(legacy_field), "loader removes %s" % legacy_field, failures ) for loader_owned_token in [ "ResourceLoader.", "FileAccess.", "WMO_STREAMING_SCRIPT", "format_version", "Node3D", "RID", "Thread", "Mutex", "Semaphore", ]: _expect_false( cache_state_source.contains(loader_owned_token), "cache state omits %s dependency" % loader_owned_token, failures ) _expect_true( loader_source.contains("resource.get_script() == WMO_STREAMING_SCRIPT"), "loader retains script validation", failures ) _expect_true( loader_source.contains("WMO_STREAMING_SCRIPT.FORMAT_VERSION"), "loader retains cache format validation", failures ) func _verify_bounded_timing(failures: Array[String]) -> float: var cache_state: RefCounted = CACHE_STATE_SCRIPT.new() var started_microseconds := Time.get_ticks_usec() for iteration in range(100): for resource_index in range(256): var normalized_path := "world/object_%d.wmo" % resource_index cache_state.call( "remember_request", normalized_path, "res://cache/object_%d.res" % resource_index ) if resource_index % 2 == 0: cache_state.call( "complete_request_with_resource", normalized_path, Resource.new() ) else: cache_state.call("complete_request_as_missing", normalized_path) cache_state.call("clear_all") _expect_equal( int(cache_state.call("pending_request_count")), 0, "timing cycle %d clears" % iteration, failures ) var elapsed_milliseconds := float(Time.get_ticks_usec() - started_microseconds) / 1000.0 _expect_true( elapsed_milliseconds < 1000.0, "100 resource/request cycles remain bounded", failures ) return elapsed_milliseconds func _read_text(path: String, failures: Array[String]) -> String: var file := FileAccess.open(path, FileAccess.READ) if file == null: failures.append("cannot open %s" % path) return "" return file.get_as_text() func _expect_equal( actual_value: int, expected_value: int, label: String, failures: Array[String] ) -> void: if actual_value != expected_value: failures.append("%s expected %d, got %d" % [label, expected_value, actual_value]) func _expect_string_equal( actual_value: String, expected_value: String, label: String, failures: Array[String] ) -> void: if actual_value != expected_value: failures.append("%s expected %s, got %s" % [label, expected_value, actual_value]) func _expect_string_array( actual_values: Array, expected_values: Array, label: String, failures: Array[String] ) -> void: if actual_values != expected_values: failures.append("%s expected %s, got %s" % [label, expected_values, actual_values]) func _expect_true(actual_value: bool, label: String, failures: Array[String]) -> void: if not actual_value: failures.append("%s expected true" % label) func _expect_false(actual_value: bool, label: String, failures: Array[String]) -> void: if actual_value: failures.append("%s expected false" % label)