using NeonSprawl.Server.Game.Items; namespace NeonSprawl.Server.Tests.Game.Items; public class ItemDefinitionRegistryTests { private static ItemDefinitionRegistry CreateRegistryFromRows(IReadOnlyDictionary byId) { var catalog = new ItemDefinitionCatalog("/tmp/catalog", byId, catalogJsonFileCount: 1); return new ItemDefinitionRegistry(catalog); } [Fact] public void TryGetDefinition_ShouldReturnTrueAndExpectedMetadata_WhenIdExists() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { ["scrap_metal_bulk"] = new ItemDefRow( "scrap_metal_bulk", "Scrap Metal (Bulk)", "material", StackMax: 999, InventorySlotKind: "bag", Rarity: null, BindPolicy: null, DurabilityMax: null), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryGetDefinition("scrap_metal_bulk", out var def); // Assert Assert.True(found); Assert.NotNull(def); Assert.Equal("material", def.PrototypeRole); Assert.Equal("Scrap Metal (Bulk)", def.DisplayName); Assert.Equal(999, def.StackMax); Assert.Equal("bag", def.InventorySlotKind); } [Fact] public void TryGetDefinition_ShouldReturnFalse_WhenItemIdIsNull() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { ["scrap_metal_bulk"] = new ItemDefRow( "scrap_metal_bulk", "Scrap Metal (Bulk)", "material", StackMax: 999, InventorySlotKind: "bag", Rarity: null, BindPolicy: null, DurabilityMax: null), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryGetDefinition(null, out var def); // Assert Assert.False(found); Assert.Null(def); } [Fact] public void TryGetDefinition_ShouldReturnFalse_WhenIdUnknown() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { ["scrap_metal_bulk"] = new ItemDefRow( "scrap_metal_bulk", "Scrap Metal (Bulk)", "material", StackMax: 999, InventorySlotKind: "bag", Rarity: null, BindPolicy: null, DurabilityMax: null), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryGetDefinition("not_a_real_item", out var def); // Assert Assert.False(found); Assert.Null(def); } [Fact] public void GetDefinitionsInIdOrder_ShouldListAllRowsOrderedById_WhenMultipleItems() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { ["survey_drone_kit"] = new ItemDefRow( "survey_drone_kit", "Survey Drone Kit", "utility", StackMax: 1, InventorySlotKind: "bag", Rarity: null, BindPolicy: null, DurabilityMax: null), ["scrap_metal_bulk"] = new ItemDefRow( "scrap_metal_bulk", "Scrap Metal (Bulk)", "material", StackMax: 999, InventorySlotKind: "bag", Rarity: null, BindPolicy: null, DurabilityMax: null), ["prototype_armor_shell"] = new ItemDefRow( "prototype_armor_shell", "Prototype Armor Shell", "equip_stub", StackMax: 1, InventorySlotKind: "equipment", Rarity: null, BindPolicy: null, DurabilityMax: null), }; var registry = CreateRegistryFromRows(rows); // Act var list = registry.GetDefinitionsInIdOrder(); // Assert Assert.Equal(3, list.Count); Assert.Equal("prototype_armor_shell", list[0].Id); Assert.Equal("scrap_metal_bulk", list[1].Id); Assert.Equal("survey_drone_kit", list[2].Id); } [Fact] public void TryGetDefinition_ShouldMatchLoaderCatalog_WhenUsingPrototypeFixture() { // Arrange var root = Directory.CreateTempSubdirectory("neon-sprawl-item-registry-loader-"); try { var itemsDir = Path.Combine(root.FullName, "content", "items"); var schemaDir = Path.Combine(root.FullName, "content", "schemas"); Directory.CreateDirectory(itemsDir); Directory.CreateDirectory(schemaDir); var schemaPath = Path.Combine(schemaDir, "item-def.schema.json"); File.Copy(ItemCatalogTestPaths.DiscoverRepoItemDefSchemaPath(), schemaPath, overwrite: true); File.Copy( Path.Combine(ItemCatalogTestPaths.DiscoverRepoItemsDirectory(), "prototype_items.json"), Path.Combine(itemsDir, "prototype_items.json"), overwrite: true); var loaded = ItemDefinitionCatalogLoader.Load(itemsDir, schemaPath, NullLogger.Instance); var registry = new ItemDefinitionRegistry(loaded); // Act var ok = registry.TryGetDefinition("prototype_armor_shell", out var equipStub); // Assert Assert.True(ok); Assert.NotNull(equipStub); Assert.Equal("equip_stub", equipStub.PrototypeRole); Assert.Equal("equipment", equipStub.InventorySlotKind); Assert.Equal(1, equipStub.StackMax); } finally { try { Directory.Delete(root.FullName, recursive: true); } catch (IOException) { // Best-effort: transient lock or race on some hosts; temp dir is unique per run. } } } [Fact] public async Task Host_ShouldResolveRegistryFromDi_WhenStartupSucceeds() { // Arrange await using var factory = new InMemoryWebApplicationFactory(); using var client = factory.CreateClient(); _ = await client.GetAsync("/health"); // Act var registry = factory.Services.GetRequiredService(); var found = registry.TryGetDefinition("scrap_metal_bulk", out var scrap); // Assert Assert.True(found); Assert.NotNull(scrap); Assert.Equal("material", scrap.PrototypeRole); Assert.Equal(999, scrap.StackMax); } }