using NeonSprawl.Server.Game.Encounters; namespace NeonSprawl.Server.Tests.Game.Encounters; public class RewardTableDefinitionRegistryTests { private const string PrototypeCombatPocketClear = "prototype_combat_pocket_clear"; private static RewardTableDefinitionRegistry CreateRegistryFromRows(IReadOnlyDictionary byId) { var catalog = new RewardTableDefinitionCatalog("/tmp/reward-tables", byId, catalogJsonFileCount: 1); return new RewardTableDefinitionRegistry(catalog); } private static RewardTableDefRow CreatePrototypeCombatPocketClearRow() => new( PrototypeCombatPocketClear, "Prototype Combat Pocket Clear", [ new RewardGrantRow("scrap_metal_bulk", 10), new RewardGrantRow("contract_handoff_token", 1), ]); [Fact] public void TryGetDefinition_ShouldReturnTrueAndExpectedMetadata_WhenIdExists() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { [PrototypeCombatPocketClear] = CreatePrototypeCombatPocketClearRow(), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryGetDefinition(PrototypeCombatPocketClear, out var def); // Assert Assert.True(found); Assert.NotNull(def); Assert.Equal("Prototype Combat Pocket Clear", def!.DisplayName); Assert.Equal(10, def.FixedGrants.First(g => g.ItemId == "scrap_metal_bulk").Quantity); Assert.Equal(1, def.FixedGrants.First(g => g.ItemId == "contract_handoff_token").Quantity); } [Fact] public void TryGetDefinition_ShouldReturnFalse_WhenRewardTableIdIsNull() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { [PrototypeCombatPocketClear] = CreatePrototypeCombatPocketClearRow(), }; 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) { [PrototypeCombatPocketClear] = CreatePrototypeCombatPocketClearRow(), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryGetDefinition("not_a_real_reward_table", out var def); // Assert Assert.False(found); Assert.Null(def); } [Fact] public void TryNormalizeKnown_ShouldReturnTrueAndLowercaseId_WhenInputHasWhitespaceAndMixedCase() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { [PrototypeCombatPocketClear] = CreatePrototypeCombatPocketClearRow(), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryNormalizeKnown(" Prototype_Combat_Pocket_Clear ", out var normalized); // Assert Assert.True(found); Assert.Equal(PrototypeCombatPocketClear, normalized); } [Fact] public void TryNormalizeKnown_ShouldReturnFalse_WhenInputIsNull() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { [PrototypeCombatPocketClear] = CreatePrototypeCombatPocketClearRow(), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryNormalizeKnown(null, out var normalized); // Assert Assert.False(found); Assert.Equal(string.Empty, normalized); } [Fact] public void TryNormalizeKnown_ShouldReturnFalse_WhenInputIsWhitespaceOnly() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { [PrototypeCombatPocketClear] = CreatePrototypeCombatPocketClearRow(), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryNormalizeKnown(" ", out var normalized); // Assert Assert.False(found); Assert.Equal(string.Empty, normalized); } [Fact] public void TryNormalizeKnown_ShouldReturnFalse_WhenIdNotInCatalog() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { [PrototypeCombatPocketClear] = CreatePrototypeCombatPocketClearRow(), }; var registry = CreateRegistryFromRows(rows); // Act var found = registry.TryNormalizeKnown("prototype_unknown", out var normalized); // Assert Assert.False(found); Assert.Equal("prototype_unknown", normalized); } [Fact] public void GetDefinitionsInIdOrder_ShouldListAllRowsOrderedById_WhenMultipleRewardTables() { // Arrange var rows = new Dictionary(StringComparer.Ordinal) { ["z_table"] = new RewardTableDefRow("z_table", "Z", [new RewardGrantRow("scrap_metal_bulk", 1)]), [PrototypeCombatPocketClear] = CreatePrototypeCombatPocketClearRow(), ["a_table"] = new RewardTableDefRow("a_table", "A", [new RewardGrantRow("scrap_metal_bulk", 1)]), }; var registry = CreateRegistryFromRows(rows); // Act var list = registry.GetDefinitionsInIdOrder(); // Assert Assert.Equal(3, list.Count); Assert.Equal("a_table", list[0].Id); Assert.Equal(PrototypeCombatPocketClear, list[1].Id); Assert.Equal("z_table", list[2].Id); } [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(PrototypeCombatPocketClear, out var rewardTable); var unknown = registry.TryGetDefinition("not_a_real_reward_table", out var missing); var normalized = registry.TryNormalizeKnown(" Prototype_Combat_Pocket_Clear ", out var rewardTableId); var list = registry.GetDefinitionsInIdOrder(); // Assert Assert.True(found); Assert.NotNull(rewardTable); Assert.Equal(10, rewardTable!.FixedGrants.First(g => g.ItemId == "scrap_metal_bulk").Quantity); Assert.Equal(1, rewardTable.FixedGrants.First(g => g.ItemId == "contract_handoff_token").Quantity); Assert.False(unknown); Assert.Null(missing); Assert.True(normalized); Assert.Equal(PrototypeCombatPocketClear, rewardTableId); Assert.Single(list); Assert.Equal(PrototypeCombatPocketClear, list[0].Id); } }