extends SceneTree const CapabilityScript := preload("res://world/targets/WorldTargetCapability.gd") const DescriptorScript := preload("res://world/targets/WorldTargetDescriptor.gd") const RegistryScript := preload("res://world/targets/WorldTargetRegistry.gd") const ActionCommandScript := preload("res://simulation/commands/ActionCommand.gd") const ActionResultScript := preload("res://simulation/commands/ActionResult.gd") const ActionOfferScript := preload("res://simulation/commands/ActionOffer.gd") const InteractionServiceScript := preload("res://simulation/commands/InteractionService.gd") const ActionCommandServiceScript := preload("res://simulation/commands/ActionCommandService.gd") var failures: Array[String] = [] func _initialize() -> void: _test_canonical_lookup_and_cross_kind_uniqueness() _test_deterministic_iteration_and_capability_updates() _test_transient_handle_lifecycle() _test_two_world_isolation() _test_descriptors_and_commands_are_non_authoritative_values() _finish() func _test_canonical_lookup_and_cross_kind_uniqueness() -> void: var registry := RegistryScript.new(&"jajce") var descriptor: WorldTargetDescriptor = _descriptor( &"shared_target", &"resource", [&"gather_food"], Vector3(2.0, 0.0, 3.0) ) var handle = registry.register_target(descriptor) _check(handle != null, "A valid target should register") _check(registry.size() == 1, "The registry should contain one canonical target") _check( registry.get_descriptor(&"shared_target").get_target_kind() == &"resource", "Canonical lookup should return the registered descriptor" ) var conflicting: WorldTargetDescriptor = _descriptor( &"shared_target", &"storage", [&"deposit_food"] ) _check( registry.register_target(conflicting) == null, "One target ID must not register under a second kind in the same context" ) _check( registry.last_error.contains("already registered as kind 'resource'"), "A cross-kind collision should expose a useful non-diagnostic error" ) _check(registry.size() == 1, "A rejected collision must not replace the canonical entry") func _test_deterministic_iteration_and_capability_updates() -> void: var registry := RegistryScript.new(&"ordered_world") registry.register_target(_descriptor(&"target_z", &"resource", [&"gather_food"])) var middle_handle = registry.register_target( _descriptor(&"target_m", &"activity", [&"rest", &"socialize"]) ) registry.register_target(_descriptor(&"target_a", &"resource", [&"gather_food"])) _check( registry.get_target_ids() == [&"target_a", &"target_m", &"target_z"], "Iteration should be stable-ID ordered regardless of registration order" ) _check( registry.get_target_ids(&"resource") == [&"target_a", &"target_z"], "Kind-filtered iteration should remain deterministic" ) _check( registry.get_target_ids(&"", &"gather_food") == [&"target_a", &"target_z"], "Capability-filtered iteration should remain deterministic" ) var updated: WorldTargetDescriptor = _descriptor( &"target_m", &"activity", [&"trade"], Vector3(8.0, 0.0, -2.0) ) _check(registry.update_target(middle_handle, updated), "A live handle should update facts") _check( registry.get_target_ids(&"", &"socialize").is_empty(), "Updating capabilities should remove old capability-index membership" ) _check( registry.get_target_ids(&"", &"trade") == [&"target_m"], "Updating capabilities should add new capability-index membership" ) _check( registry.resolve_handle(middle_handle).get_local_position() == Vector3(8.0, 0.0, -2.0), "A target update should preserve handle identity while replacing transient facts" ) func _test_transient_handle_lifecycle() -> void: var registry := RegistryScript.new(&"lifecycle_world") var first_provider := Node.new() var first_handle = registry.register_target( _descriptor(&"workbench", &"activity", [&"craft"]), first_provider ) _check( registry.is_handle_valid(first_handle, true), "A newly registered provider handle should resolve" ) _check( registry.get_provider(first_handle) == first_provider, "A handle should resolve its provider" ) _check( registry.unregister_target(first_handle), "The current handle should unregister its target" ) _check( not registry.is_handle_valid(first_handle), "Unregistration should invalidate the handle" ) var second_provider := Node.new() var second_handle = registry.register_target( _descriptor(&"workbench", &"activity", [&"craft"]), second_provider ) _check( second_handle.get_generation() > first_handle.get_generation(), "Re-registration should advance the transient generation" ) _check( not registry.unregister_target(first_handle), "A stale provider must not unregister a newer canonical target" ) _check( registry.is_handle_valid(second_handle, true), "Rejecting a stale handle should leave the newer target intact" ) second_provider.free() _check( registry.prune_invalid_providers() == [&"workbench"], "Dead weak providers should be pruned deterministically" ) _check(not registry.is_handle_valid(second_handle), "Pruning should invalidate its handle") first_provider.free() func _test_two_world_isolation() -> void: var first_world := RegistryScript.new(&"world_one") var second_world := RegistryScript.new(&"world_two") var first_handle = first_world.register_target( _descriptor(&"village_pantry", &"storage", [&"withdraw_food"]) ) var second_handle = second_world.register_target( _descriptor(&"village_pantry", &"landmark", [&"inspect"]) ) _check( first_handle != null and second_handle != null, "Two contexts may reuse a local target ID" ) _check( first_world.resolve_handle(second_handle) == null, "A handle from another registry must never resolve, even with the same target ID" ) _check( second_world.resolve_handle(first_handle) == null, "Registry ownership should isolate handles in both directions" ) _check( first_world.unregister_target(first_handle), "The first world should unregister independently" ) _check( second_world.is_handle_valid(second_handle), "Unloading one context must not affect a second context's canonical target" ) _check( second_world.get_descriptor(&"village_pantry").get_target_kind() == &"landmark", "Each context should retain its own target facts" ) func _test_descriptors_and_commands_are_non_authoritative_values() -> void: var attributes := {"amounts": [1, 2]} var metadata := {"tags": ["village"]} var capability := CapabilityScript.new(&"inspect", attributes) var descriptor := DescriptorScript.new( &"notice_board", &"activity", [capability], Vector3.ZERO, "Notice board", metadata ) attributes["amounts"][0] = 99 metadata["tags"].append("mutated") var registry := RegistryScript.new(&"command_world") var handle = registry.register_target(descriptor) var stored := registry.get_descriptor(&"notice_board") _check( stored.get_capability(&"inspect").get_attribute(&"amounts") == [1, 2], "Capability attributes should be isolated from caller mutation" ) _check( stored.get_metadata_value(&"tags") == ["village"], "Target metadata should be isolated from caller mutation" ) var offer_parameters := {"page": 1} var offer := ActionOfferScript.new( &"inspect_board", &"inspect", handle, "Read notices", true, "", offer_parameters, 2.0 ) offer_parameters["page"] = 9 _check(offer.is_valid(), "A well-formed advisory action offer should be valid") _check(offer.get_parameters()["page"] == 1, "An offer should copy its parameter value") var command_parameters := {"page": 1} var command := ActionCommandScript.new( &"command_1", &"person_7", offer.get_action_id(), offer.get_target(), command_parameters ) command_parameters["page"] = 5 _check(command.is_valid(), "A command should carry a well-formed transient target intent") _check(command.get_parameters()["page"] == 1, "A command should copy its parameter value") _check(registry.unregister_target(handle), "The offered target should be removable") _check( command.is_valid() and not registry.is_handle_valid(command.get_target()), "Command shape validity must not make a stale target authoritative" ) var accepted := ActionResultScript.accepted(&"command_1", {"queued": true}) var rejected := ActionResultScript.rejected(&"command_2", &"stale_target", "Try again") _check(accepted.is_valid() and accepted.is_accepted(), "Accepted results should be explicit") _check( rejected.is_valid() and rejected.is_terminal() and not rejected.is_accepted(), "Rejected results should carry a terminal, non-success status" ) _check( ( InteractionServiceScript . new() . get_action_offers(&"person_7", command.get_target()) . is_empty() ), "The manager-independent interaction interface should have no implicit offers" ) _check( ActionCommandServiceScript.new().submit_command(command) == null, "The manager-independent command interface should have no implicit authority" ) func _descriptor( target_id: StringName, target_kind: StringName, capability_ids: Array[StringName], position: Vector3 = Vector3.ZERO ) -> WorldTargetDescriptor: var capabilities: Array = [] for capability_id in capability_ids: capabilities.append(CapabilityScript.new(capability_id)) return DescriptorScript.new(target_id, target_kind, capabilities, position) func _check(condition: bool, message: String) -> void: if not condition: failures.append(message) func _finish() -> void: if failures.is_empty(): print("[TEST] World target registry passed: scoped canonical IDs, handles, and commands") quit(0) return for failure in failures: push_error("[TEST] " + failure) quit(1)