using NeonSprawl.Server.Game.Gathering; namespace NeonSprawl.Server.Tests.Game.Gathering; public class ResourceNodeDefinitionRegistryTests { private static ResourceNodeDefinitionRegistry CreateRegistryFromRows( IReadOnlyDictionary nodesById, IReadOnlyDictionary yieldsByNodeDefId) { var catalog = new ResourceNodeCatalog( "/tmp/resource-nodes", nodesById, yieldsByNodeDefId, nodeCatalogJsonFileCount: 1, yieldCatalogJsonFileCount: 1); return new ResourceNodeDefinitionRegistry(catalog); } [Fact] public void TryGetDefinition_ShouldReturnTrueAndExpectedMetadata_WhenNodeDefIdExists() { // Arrange const string nodeDefId = "prototype_resource_node_alpha"; var nodes = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceNodeDefRow( nodeDefId, "Prototype Salvage Heap", "consumer_salvage", MaxGathers: 10), }; var yields = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceYieldRow(nodeDefId, "scrap_metal_bulk", Quantity: 1), }; var registry = CreateRegistryFromRows(nodes, yields); // Act var found = registry.TryGetDefinition(nodeDefId, out var def); // Assert Assert.True(found); Assert.NotNull(def); Assert.Equal("Prototype Salvage Heap", def.DisplayName); Assert.Equal("consumer_salvage", def.GatherLens); Assert.Equal(10, def.MaxGathers); } [Fact] public void TryGetYield_ShouldReturnTrueAndExpectedMetadata_WhenNodeDefIdExists() { // Arrange const string nodeDefId = "prototype_resource_node_alpha"; var nodes = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceNodeDefRow( nodeDefId, "Prototype Salvage Heap", "consumer_salvage", MaxGathers: 10), }; var yields = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceYieldRow(nodeDefId, "scrap_metal_bulk", Quantity: 1), }; var registry = CreateRegistryFromRows(nodes, yields); // Act var found = registry.TryGetYield(nodeDefId, out var yield); // Assert Assert.True(found); Assert.NotNull(yield); Assert.Equal("scrap_metal_bulk", yield.ItemId); Assert.Equal(1, yield.Quantity); } [Fact] public void TryGetDefinition_ShouldReturnFalse_WhenNodeDefIdIsNull() { // Arrange const string nodeDefId = "prototype_resource_node_alpha"; var nodes = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceNodeDefRow( nodeDefId, "Prototype Salvage Heap", "consumer_salvage", MaxGathers: 10), }; var yields = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceYieldRow(nodeDefId, "scrap_metal_bulk", Quantity: 1), }; var registry = CreateRegistryFromRows(nodes, yields); // Act var found = registry.TryGetDefinition(null, out var def); // Assert Assert.False(found); Assert.Null(def); } [Fact] public void TryGetYield_ShouldReturnFalse_WhenNodeDefIdIsNull() { // Arrange const string nodeDefId = "prototype_resource_node_alpha"; var nodes = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceNodeDefRow( nodeDefId, "Prototype Salvage Heap", "consumer_salvage", MaxGathers: 10), }; var yields = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceYieldRow(nodeDefId, "scrap_metal_bulk", Quantity: 1), }; var registry = CreateRegistryFromRows(nodes, yields); // Act var found = registry.TryGetYield(null, out var yield); // Assert Assert.False(found); Assert.Null(yield); } [Fact] public void TryGetDefinition_ShouldReturnFalse_WhenNodeDefIdUnknown() { // Arrange const string nodeDefId = "prototype_resource_node_alpha"; var nodes = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceNodeDefRow( nodeDefId, "Prototype Salvage Heap", "consumer_salvage", MaxGathers: 10), }; var yields = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceYieldRow(nodeDefId, "scrap_metal_bulk", Quantity: 1), }; var registry = CreateRegistryFromRows(nodes, yields); // Act var found = registry.TryGetDefinition("not_a_real_node", out var def); // Assert Assert.False(found); Assert.Null(def); } [Fact] public void TryGetYield_ShouldReturnFalse_WhenNodeDefIdUnknown() { // Arrange const string nodeDefId = "prototype_resource_node_alpha"; var nodes = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceNodeDefRow( nodeDefId, "Prototype Salvage Heap", "consumer_salvage", MaxGathers: 10), }; var yields = new Dictionary(StringComparer.Ordinal) { [nodeDefId] = new ResourceYieldRow(nodeDefId, "scrap_metal_bulk", Quantity: 1), }; var registry = CreateRegistryFromRows(nodes, yields); // Act var found = registry.TryGetYield("not_a_real_node", out var yield); // Assert Assert.False(found); Assert.Null(yield); } [Fact] public void GetDefinitionsInIdOrder_ShouldListAllRowsOrderedByNodeDefId_WhenMultipleNodes() { // Arrange var nodes = new Dictionary(StringComparer.Ordinal) { ["prototype_urban_bulk_delta"] = new ResourceNodeDefRow( "prototype_urban_bulk_delta", "Prototype Urban Bulk", "urban_bulk", MaxGathers: 10), ["prototype_bio_mat_gamma"] = new ResourceNodeDefRow( "prototype_bio_mat_gamma", "Prototype Bio Mat", "bio", MaxGathers: 10), ["prototype_resource_node_alpha"] = new ResourceNodeDefRow( "prototype_resource_node_alpha", "Prototype Salvage Heap", "consumer_salvage", MaxGathers: 10), ["prototype_subsurface_vein_beta"] = new ResourceNodeDefRow( "prototype_subsurface_vein_beta", "Prototype Subsurface Vein", "subsurface", MaxGathers: 10), }; var yields = new Dictionary(StringComparer.Ordinal) { ["prototype_urban_bulk_delta"] = new ResourceYieldRow( "prototype_urban_bulk_delta", "scrap_metal_bulk", Quantity: 5), ["prototype_bio_mat_gamma"] = new ResourceYieldRow( "prototype_bio_mat_gamma", "scrap_metal_bulk", Quantity: 3), ["prototype_resource_node_alpha"] = new ResourceYieldRow( "prototype_resource_node_alpha", "scrap_metal_bulk", Quantity: 1), ["prototype_subsurface_vein_beta"] = new ResourceYieldRow( "prototype_subsurface_vein_beta", "scrap_metal_bulk", Quantity: 2), }; var registry = CreateRegistryFromRows(nodes, yields); // Act var list = registry.GetDefinitionsInIdOrder(); // Assert Assert.Equal(4, list.Count); Assert.Equal("prototype_bio_mat_gamma", list[0].NodeDefId); Assert.Equal("prototype_resource_node_alpha", list[1].NodeDefId); Assert.Equal("prototype_subsurface_vein_beta", list[2].NodeDefId); Assert.Equal("prototype_urban_bulk_delta", list[3].NodeDefId); } [Fact] public void TryGetDefinition_ShouldMatchLoaderCatalog_WhenUsingPrototypeFixture() { // Arrange var root = Directory.CreateTempSubdirectory("neon-sprawl-resource-node-registry-loader-"); try { var resourceNodesDir = Path.Combine(root.FullName, "content", "resource-nodes"); var schemaDir = Path.Combine(root.FullName, "content", "schemas"); Directory.CreateDirectory(resourceNodesDir); Directory.CreateDirectory(schemaDir); var nodeSchemaPath = Path.Combine(schemaDir, "resource-node-def.schema.json"); var yieldSchemaPath = Path.Combine(schemaDir, "resource-yield-row.schema.json"); File.Copy(ResourceNodeCatalogTestPaths.DiscoverRepoResourceNodeDefSchemaPath(), nodeSchemaPath, overwrite: true); File.Copy(ResourceNodeCatalogTestPaths.DiscoverRepoResourceYieldRowSchemaPath(), yieldSchemaPath, overwrite: true); File.Copy( Path.Combine(ResourceNodeCatalogTestPaths.DiscoverRepoResourceNodesDirectory(), "prototype_resource_nodes.json"), Path.Combine(resourceNodesDir, "prototype_resource_nodes.json"), overwrite: true); File.Copy( Path.Combine(ResourceNodeCatalogTestPaths.DiscoverRepoResourceNodesDirectory(), "prototype_resource_yields.json"), Path.Combine(resourceNodesDir, "prototype_resource_yields.json"), overwrite: true); var itemIds = new HashSet(StringComparer.Ordinal) { "scrap_metal_bulk" }; var loaded = ResourceNodeCatalogLoader.Load( resourceNodesDir, nodeSchemaPath, yieldSchemaPath, itemIds, NullLogger.Instance); var registry = new ResourceNodeDefinitionRegistry(loaded); // Act var ok = registry.TryGetDefinition("prototype_resource_node_alpha", out var node); var yieldOk = registry.TryGetYield("prototype_resource_node_alpha", out var yield); // Assert Assert.True(ok); Assert.NotNull(node); Assert.Equal("consumer_salvage", node.GatherLens); Assert.Equal(10, node.MaxGathers); Assert.True(yieldOk); Assert.NotNull(yield); Assert.Equal("scrap_metal_bulk", yield.ItemId); Assert.Equal(1, yield.Quantity); } 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("prototype_resource_node_alpha", out var node); var yieldFound = registry.TryGetYield("prototype_resource_node_alpha", out var yield); // Assert Assert.True(found); Assert.NotNull(node); Assert.Equal("consumer_salvage", node.GatherLens); Assert.Equal(10, node.MaxGathers); Assert.True(yieldFound); Assert.NotNull(yield); Assert.Equal("scrap_metal_bulk", yield.ItemId); Assert.Equal(1, yield.Quantity); } }