neon-sprawl/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionRegistryTest...

165 lines
6.3 KiB
C#

namespace NeonSprawl.Server.Tests.Game.Skills;
public class SkillDefinitionRegistryTests
{
private static SkillDefinitionRegistry CreateRegistryFromRows(IReadOnlyDictionary<string, SkillDefRow> byId)
{
var catalog = new SkillDefinitionCatalog("/tmp/catalog", byId, catalogJsonFileCount: 1);
return new SkillDefinitionRegistry(catalog);
}
[Fact]
public void TryGetDefinition_ShouldReturnTrueAndExpectedXpKinds_WhenIdExists()
{
// Arrange
var rows = new Dictionary<string, SkillDefRow>(StringComparer.Ordinal)
{
["intrusion"] = new SkillDefRow(
"intrusion",
"tech",
"Intrusion",
["activity", "mission_reward", "book_or_item"]),
};
var registry = CreateRegistryFromRows(rows);
// Act
var found = registry.TryGetDefinition("intrusion", out var def);
// Assert
Assert.True(found);
Assert.NotNull(def);
Assert.Equal("tech", def.Category);
Assert.Equal("Intrusion", def.DisplayName);
Assert.Contains("activity", def.AllowedXpSourceKinds, StringComparer.Ordinal);
Assert.Contains("book_or_item", def.AllowedXpSourceKinds, StringComparer.Ordinal);
}
[Fact]
public void TryGetDefinition_ShouldReturnFalse_WhenSkillIdIsNull()
{
// Arrange
var rows = new Dictionary<string, SkillDefRow>(StringComparer.Ordinal)
{
["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", ["activity"]),
};
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<string, SkillDefRow>(StringComparer.Ordinal)
{
["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", ["activity"]),
};
var registry = CreateRegistryFromRows(rows);
// Act
var found = registry.TryGetDefinition("not_a_real_skill", out var def);
// Assert
Assert.False(found);
Assert.Null(def);
}
[Fact]
public void GetDefinitionsInIdOrder_ShouldListAllRowsOrderedById_WhenMultipleSkills()
{
// Arrange
var rows = new Dictionary<string, SkillDefRow>(StringComparer.Ordinal)
{
["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", ["activity", "mission_reward"]),
["refine"] = new SkillDefRow("refine", "process", "Refine", ["activity"]),
["intrusion"] = new SkillDefRow("intrusion", "tech", "Intrusion", ["trainer"]),
};
var registry = CreateRegistryFromRows(rows);
// Act
var list = registry.GetDefinitionsInIdOrder();
// Assert
Assert.Equal(3, list.Count);
Assert.Equal("intrusion", list[0].Id);
Assert.Equal("refine", list[1].Id);
Assert.Equal("salvage", list[2].Id);
}
[Fact]
public void TryGetDefinition_ShouldMatchLoaderCatalog_WhenUsingPrototypeFixture()
{
// Arrange
var root = Directory.CreateTempSubdirectory("neon-sprawl-registry-loader-");
try
{
var skillsDir = Path.Combine(root.FullName, "content", "skills");
var schemaDir = Path.Combine(root.FullName, "content", "schemas");
Directory.CreateDirectory(skillsDir);
Directory.CreateDirectory(schemaDir);
var schemaPath = Path.Combine(schemaDir, "skill-def.schema.json");
File.Copy(SkillCatalogTestPaths.DiscoverRepoSkillDefSchemaPath(), schemaPath, overwrite: true);
const string json = """
{
"skills": [
{
"id": "salvage",
"category": "gather",
"displayName": "Salvage",
"allowedXpSourceKinds": ["activity", "mission_reward"]
},
{
"id": "refine",
"category": "process",
"displayName": "Refine",
"allowedXpSourceKinds": ["activity", "mission_reward", "trainer"]
},
{
"id": "intrusion",
"category": "tech",
"displayName": "Intrusion",
"allowedXpSourceKinds": ["activity", "mission_reward", "book_or_item"]
}
]
}
""";
File.WriteAllText(Path.Combine(skillsDir, "prototype_skills.json"), json, Encoding.UTF8);
var loaded = SkillDefinitionCatalogLoader.Load(skillsDir, schemaPath, NullLogger.Instance);
var registry = new SkillDefinitionRegistry(loaded);
// Act
var ok = registry.TryGetDefinition("refine", out var refine);
// Assert
Assert.True(ok);
Assert.NotNull(refine);
Assert.Equal("process", refine.Category);
Assert.Contains("trainer", refine.AllowedXpSourceKinds, StringComparer.Ordinal);
}
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<ISkillDefinitionRegistry>();
var found = registry.TryGetDefinition("salvage", out var salvage);
// Assert
Assert.True(found);
Assert.NotNull(salvage);
Assert.Contains("activity", salvage.AllowedXpSourceKinds, StringComparer.Ordinal);
}
}