extends GutTest func test_core_catalog_enumerates_new_authoring_domains_deterministically() -> void: var catalog := ContentCatalog.create_core() assert_true(catalog.is_valid(), "%s" % [catalog.get_errors()]) assert_eq( _tag_ids(catalog.get_capability_tags()), [&"item.food", &"item.medicine", &"item.wood", &"resource.harvestable", &"storage.village"] ) assert_eq( _resource_ids(catalog.get_resources()), [&"resource_berry_patch", &"resource_herb_patch", &"resource_tree"] ) assert_eq( _storage_ids(catalog.get_storages()), [&"village_apothecary", &"village_pantry", &"village_woodpile"] ) var report := catalog.get_authoring_report() assert_true(report["valid"]) assert_eq(report["resources"], _resource_ids(catalog.get_resources())) assert_eq(report["storages"], _storage_ids(catalog.get_storages())) assert_false(report.has("presentation_assets")) var returned_resources := catalog.get_resources() returned_resources.clear() assert_eq(catalog.get_resources().size(), 3) func test_herb_route_is_data_only_and_legacy_routes_remain_stable() -> void: var catalog := ContentCatalog.create_core() var routing := StorageRoutingPolicy.new(catalog) var herb_source := catalog.get_resource(&"resource_herb_patch") assert_not_null(herb_source) assert_eq(herb_source.item_id, &"herb") assert_eq(herb_source.extraction_action_id, SimulationIds.ACTION_GATHER_FOOD) assert_eq(routing.resolve_definition(herb_source.item_id).storage_id, &"village_apothecary") assert_eq( routing.resolve_definition(SimulationIds.RESOURCE_FOOD).storage_id, SimulationIds.STORAGE_VILLAGE_PANTRY ) assert_eq( routing.resolve_definition(SimulationIds.RESOURCE_WOOD).storage_id, SimulationIds.STORAGE_VILLAGE_WOODPILE ) assert_null(routing.resolve_definition(&"unknown_item")) var apothecary := catalog.get_storage(&"village_apothecary") var nearly_full := apothecary.create_state({"herb": 39.0}) var states: Array[StorageStateRecord] = [nearly_full] assert_same(routing.resolve_state(&"herb", 1.0, states), nearly_full) assert_null(routing.resolve_state(&"herb", 2.0, states)) func test_routes_rank_priority_then_stable_storage_id() -> void: var core := load(ContentCatalog.CORE_PACK_PATH) as SimulationContentPack var addon := _pack(&"routing_addon") addon.required_pack_ids = [&"core"] var early := _storage(&"a_medicine_store", &"item.medicine", 100) var low_priority := _storage(&"field_medicine_store", &"item.medicine", 10) addon.storages = [low_priority, early] var packs: Array[SimulationContentPack] = [addon, core] var catalog := ContentCatalog.new() assert_true(catalog.rebuild(packs).is_empty(), "%s" % [catalog.get_errors()]) var candidates := StorageRoutingPolicy.new(catalog).get_candidates(&"herb") assert_eq( _storage_ids(candidates), [&"a_medicine_store", &"village_apothecary", &"field_medicine_store"] ) func test_catalog_rejects_duplicate_content_ids_without_publishing_overrides() -> void: var first := _complete_minimal_pack(&"first") var second := _complete_minimal_pack(&"second") var packs: Array[SimulationContentPack] = [second, first] var catalog := ContentCatalog.new() var duplicated_cues: Array[StringName] = [&"known.cue", &"known.cue"] var errors := catalog.rebuild(packs, [], duplicated_cues) for expected in [ "Duplicate action_id 'shared_action'", "Duplicate item_id 'shared_item'", "Duplicate tag_id 'shared_tag'", "Duplicate resource_id 'shared_resource'", "Duplicate storage_id 'shared_storage'", "Duplicate supported presentation cue 'known.cue'", ]: assert_true(_has_error(errors, expected), "%s missing from %s" % [expected, errors]) assert_false(catalog.is_valid()) assert_true(catalog.get_items().is_empty()) assert_null(catalog.get_storage(&"shared_storage")) func test_catalog_rejects_unknown_action_item_tag_handler_and_cue_references() -> void: var pack := _pack(&"broken") var item := _item(&"broken_item", &"unknown_item_tag") item.presentation_cue_id = &"unknown.item.cue" var action := _action(&"broken_action") action.actor_capability_tags = [&"unknown_actor_tag"] action.target_capability_tags = [&"unknown_target_tag"] action.completion_handler_id = &"unknown_handler" action.presentation_cue_id = &"unknown.action.cue" var effect := ActionEffect.new() effect.effect_id = &"broken_effect" effect.effect_kind = ActionEffect.KIND_SCHEDULE_ACTION effect.scheduled_action_id = &"unknown_scheduled_action" effect.item_id = &"unknown_effect_item" action.effects = [effect] var resource := _resource(&"broken_resource", &"unknown_resource_item", &"unknown_action") resource.capability_tag_ids = [&"unknown_resource_tag"] resource.presentation_cue_id = &"unknown.resource.cue" var storage := _storage(&"broken_storage", &"unknown_storage_item_tag", 1) storage.accepted_item_ids = [&"unknown_storage_item"] storage.capability_tag_ids = [&"unknown_storage_tag"] storage.deposit_action_id = &"unknown_deposit_action" storage.presentation_cue_id = &"unknown.storage.cue" pack.items = [item] pack.actions = [action] pack.resources = [resource] pack.storages = [storage] var packs: Array[SimulationContentPack] = [pack] var handlers: Array[StringName] = [&"known_handler"] var cues: Array[StringName] = [&"known.cue"] var errors := ContentCatalog.new().rebuild(packs, handlers, cues) for expected in [ "unknown tag 'unknown_item_tag'", "unknown presentation cue 'unknown.item.cue'", "unknown tag 'unknown_actor_tag'", "unknown tag 'unknown_target_tag'", "unknown completion handler 'unknown_handler'", "unknown action 'unknown_scheduled_action'", "unknown item 'unknown_effect_item'", "unknown item 'unknown_resource_item'", "unknown action 'unknown_action'", "unknown tag 'unknown_resource_tag'", "unknown item 'unknown_storage_item'", "unknown tag 'unknown_storage_item_tag'", "unknown tag 'unknown_storage_tag'", "unknown action 'unknown_deposit_action'", "unknown presentation cue 'unknown.storage.cue'", ]: assert_true(_has_error(errors, expected), "%s missing from %s" % [expected, errors]) func _complete_minimal_pack(pack_id: StringName) -> SimulationContentPack: var pack := _pack(pack_id) var tag := CapabilityTagDefinition.new() tag.tag_id = &"shared_tag" tag.display_name = "Shared tag" tag.domain = CapabilityTagDefinition.DOMAIN_ITEM var item := _item(&"shared_item", tag.tag_id) var action := _action(&"shared_action") action.target_type = SimulationIds.TARGET_RESOURCE action.resource_action_id = action.action_id var resource := _resource(&"shared_resource", item.item_id, action.action_id) var storage := _storage(&"shared_storage", tag.tag_id, 1) pack.capability_tags = [tag] pack.items = [item] pack.actions = [action] pack.resources = [resource] pack.storages = [storage] return pack func _pack(pack_id: StringName) -> SimulationContentPack: var pack := SimulationContentPack.new() pack.pack_id = pack_id pack.display_name = String(pack_id).capitalize() return pack func _item(item_id: StringName, tag_id: StringName) -> ItemDefinition: var item := ItemDefinition.new() item.item_id = item_id item.display_name = String(item_id).capitalize() item.category = ItemDefinition.CATEGORY_RESOURCE item.capability_tag_ids = [tag_id] return item func _action(action_id: StringName) -> ActionDefinition: var action := ActionDefinition.new() action.action_id = action_id action.display_name = String(action_id).capitalize() action.target_type = SimulationIds.TARGET_ACTIVITY return action func _resource( resource_id: StringName, item_id: StringName, action_id: StringName ) -> ResourceDefinition: var resource := ResourceDefinition.new() resource.resource_id = resource_id resource.display_name = String(resource_id).capitalize() resource.item_id = item_id resource.extraction_action_id = action_id return resource func _storage( storage_id: StringName, accepted_item_tag_id: StringName, priority: int ) -> StorageDefinition: var storage := StorageDefinition.new() storage.storage_id = storage_id storage.display_name = String(storage_id).capitalize() storage.accepted_item_tag_ids = [accepted_item_tag_id] storage.routing_priority = priority return storage func _tag_ids(definitions: Array[CapabilityTagDefinition]) -> Array[StringName]: var ids: Array[StringName] = [] for definition in definitions: ids.append(definition.tag_id) return ids func _resource_ids(definitions: Array[ResourceDefinition]) -> Array[StringName]: var ids: Array[StringName] = [] for definition in definitions: ids.append(definition.resource_id) return ids func _storage_ids(definitions: Array[StorageDefinition]) -> Array[StringName]: var ids: Array[StringName] = [] for definition in definitions: ids.append(definition.storage_id) return ids func _has_error(errors: Array[String], fragment: String) -> bool: for error in errors: if fragment in error: return true return false