253 lines
9.8 KiB
C#
253 lines
9.8 KiB
C#
using System.Collections.Frozen;
|
|
using NeonSprawl.Server.Game.Crafting;
|
|
using NeonSprawl.Server.Game.Items;
|
|
|
|
namespace NeonSprawl.Server.Tests.Game.Crafting;
|
|
|
|
public class RecipeDefinitionRegistryTests
|
|
{
|
|
private static readonly FrozenSet<string> KnownItemIds = PrototypeSlice1ItemCatalogRules.ExpectedItemIds;
|
|
|
|
private static readonly FrozenSet<string> KnownSkillIds = FrozenSet.ToFrozenSet(
|
|
["salvage", "refine", "intrusion"],
|
|
StringComparer.Ordinal);
|
|
|
|
private static RecipeDefinitionRegistry CreateRegistryFromRows(IReadOnlyDictionary<string, RecipeDefRow> byId)
|
|
{
|
|
var catalog = new RecipeDefinitionCatalog("/tmp/recipes", byId, catalogJsonFileCount: 1);
|
|
return new RecipeDefinitionRegistry(catalog);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGetDefinition_ShouldReturnTrueAndExpectedMetadata_WhenRefineRecipeExists()
|
|
{
|
|
// Arrange
|
|
var rows = new Dictionary<string, RecipeDefRow>(StringComparer.Ordinal)
|
|
{
|
|
["refine_scrap_standard"] = new RecipeDefRow(
|
|
"refine_scrap_standard",
|
|
"Refine Scrap (Standard)",
|
|
"process",
|
|
"refine",
|
|
[new RecipeIoRow("scrap_metal_bulk", 5)],
|
|
[new RecipeIoRow("refined_plate_stock", 1)],
|
|
RequiredSkillLevel: null,
|
|
StationTag: null),
|
|
};
|
|
var registry = CreateRegistryFromRows(rows);
|
|
// Act
|
|
var found = registry.TryGetDefinition("refine_scrap_standard", out var def);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.NotNull(def);
|
|
Assert.Equal("process", def.RecipeKind);
|
|
Assert.Equal("refine", def.RequiredSkillId);
|
|
Assert.Equal("Refine Scrap (Standard)", def.DisplayName);
|
|
Assert.Single(def.Inputs);
|
|
Assert.Equal("scrap_metal_bulk", def.Inputs[0].ItemId);
|
|
Assert.Equal(5, def.Inputs[0].Quantity);
|
|
Assert.Single(def.Outputs);
|
|
Assert.Equal("refined_plate_stock", def.Outputs[0].ItemId);
|
|
Assert.Equal(1, def.Outputs[0].Quantity);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGetDefinition_ShouldReturnTrueAndExpectedMetadata_WhenMakeRecipeExists()
|
|
{
|
|
// Arrange
|
|
var rows = new Dictionary<string, RecipeDefRow>(StringComparer.Ordinal)
|
|
{
|
|
["make_field_stim_mk0"] = new RecipeDefRow(
|
|
"make_field_stim_mk0",
|
|
"Make Field Stim Mk0",
|
|
"make",
|
|
"refine",
|
|
[
|
|
new RecipeIoRow("refined_plate_stock", 2),
|
|
new RecipeIoRow("scrap_metal_bulk", 1),
|
|
],
|
|
[new RecipeIoRow("field_stim_mk0", 1)],
|
|
RequiredSkillLevel: null,
|
|
StationTag: null),
|
|
};
|
|
var registry = CreateRegistryFromRows(rows);
|
|
// Act
|
|
var found = registry.TryGetDefinition("make_field_stim_mk0", out var def);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.NotNull(def);
|
|
Assert.Equal("make", def.RecipeKind);
|
|
Assert.Equal(2, def.Inputs.Count);
|
|
Assert.Equal("refined_plate_stock", def.Inputs[0].ItemId);
|
|
Assert.Equal("scrap_metal_bulk", def.Inputs[1].ItemId);
|
|
Assert.Single(def.Outputs);
|
|
Assert.Equal("field_stim_mk0", def.Outputs[0].ItemId);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGetDefinition_ShouldReturnFalse_WhenRecipeIdIsNull()
|
|
{
|
|
// Arrange
|
|
var rows = new Dictionary<string, RecipeDefRow>(StringComparer.Ordinal)
|
|
{
|
|
["refine_scrap_standard"] = new RecipeDefRow(
|
|
"refine_scrap_standard",
|
|
"Refine Scrap (Standard)",
|
|
"process",
|
|
"refine",
|
|
[new RecipeIoRow("scrap_metal_bulk", 5)],
|
|
[new RecipeIoRow("refined_plate_stock", 1)],
|
|
RequiredSkillLevel: null,
|
|
StationTag: 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<string, RecipeDefRow>(StringComparer.Ordinal)
|
|
{
|
|
["refine_scrap_standard"] = new RecipeDefRow(
|
|
"refine_scrap_standard",
|
|
"Refine Scrap (Standard)",
|
|
"process",
|
|
"refine",
|
|
[new RecipeIoRow("scrap_metal_bulk", 5)],
|
|
[new RecipeIoRow("refined_plate_stock", 1)],
|
|
RequiredSkillLevel: null,
|
|
StationTag: null),
|
|
};
|
|
var registry = CreateRegistryFromRows(rows);
|
|
// Act
|
|
var found = registry.TryGetDefinition("not_a_real_recipe", out var def);
|
|
// Assert
|
|
Assert.False(found);
|
|
Assert.Null(def);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetDefinitionsInIdOrder_ShouldListAllRowsOrderedById_WhenMultipleRecipes()
|
|
{
|
|
// Arrange
|
|
var rows = new Dictionary<string, RecipeDefRow>(StringComparer.Ordinal)
|
|
{
|
|
["make_field_stim_mk0"] = new RecipeDefRow(
|
|
"make_field_stim_mk0",
|
|
"Make Field Stim Mk0",
|
|
"make",
|
|
"refine",
|
|
[new RecipeIoRow("refined_plate_stock", 2)],
|
|
[new RecipeIoRow("field_stim_mk0", 1)],
|
|
RequiredSkillLevel: null,
|
|
StationTag: null),
|
|
["refine_scrap_efficient"] = new RecipeDefRow(
|
|
"refine_scrap_efficient",
|
|
"Refine Scrap (Efficient)",
|
|
"process",
|
|
"refine",
|
|
[new RecipeIoRow("scrap_metal_bulk", 10)],
|
|
[new RecipeIoRow("refined_plate_stock", 2)],
|
|
RequiredSkillLevel: null,
|
|
StationTag: null),
|
|
["refine_scrap_standard"] = new RecipeDefRow(
|
|
"refine_scrap_standard",
|
|
"Refine Scrap (Standard)",
|
|
"process",
|
|
"refine",
|
|
[new RecipeIoRow("scrap_metal_bulk", 5)],
|
|
[new RecipeIoRow("refined_plate_stock", 1)],
|
|
RequiredSkillLevel: null,
|
|
StationTag: null),
|
|
};
|
|
var registry = CreateRegistryFromRows(rows);
|
|
// Act
|
|
var list = registry.GetDefinitionsInIdOrder();
|
|
// Assert
|
|
Assert.Equal(3, list.Count);
|
|
Assert.Equal("make_field_stim_mk0", list[0].Id);
|
|
Assert.Equal("refine_scrap_efficient", list[1].Id);
|
|
Assert.Equal("refine_scrap_standard", list[2].Id);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGetDefinition_ShouldMatchLoaderCatalog_WhenUsingPrototypeFixture()
|
|
{
|
|
// Arrange
|
|
var root = Directory.CreateTempSubdirectory("neon-sprawl-recipe-registry-loader-");
|
|
try
|
|
{
|
|
var recipesDir = Path.Combine(root.FullName, "content", "recipes");
|
|
var schemaDir = Path.Combine(root.FullName, "content", "schemas");
|
|
Directory.CreateDirectory(recipesDir);
|
|
Directory.CreateDirectory(schemaDir);
|
|
var recipeDefSchemaPath = Path.Combine(schemaDir, "recipe-def.schema.json");
|
|
var recipeIoRowSchemaPath = Path.Combine(schemaDir, "recipe-io-row.schema.json");
|
|
File.Copy(RecipeCatalogTestPaths.DiscoverRepoRecipeDefSchemaPath(), recipeDefSchemaPath, overwrite: true);
|
|
File.Copy(RecipeCatalogTestPaths.DiscoverRepoRecipeIoRowSchemaPath(), recipeIoRowSchemaPath, overwrite: true);
|
|
File.Copy(
|
|
Path.Combine(RecipeCatalogTestPaths.DiscoverRepoRecipesDirectory(), "prototype_recipes.json"),
|
|
Path.Combine(recipesDir, "prototype_recipes.json"),
|
|
overwrite: true);
|
|
var loaded = RecipeDefinitionCatalogLoader.Load(
|
|
recipesDir,
|
|
recipeDefSchemaPath,
|
|
recipeIoRowSchemaPath,
|
|
KnownItemIds,
|
|
KnownSkillIds,
|
|
NullLogger.Instance);
|
|
var registry = new RecipeDefinitionRegistry(loaded);
|
|
// Act
|
|
var ok = registry.TryGetDefinition("refine_scrap_standard", out var refine);
|
|
var list = registry.GetDefinitionsInIdOrder();
|
|
// Assert
|
|
Assert.True(ok);
|
|
Assert.NotNull(refine);
|
|
Assert.Equal("process", refine.RecipeKind);
|
|
Assert.Equal("refine", refine.RequiredSkillId);
|
|
Assert.Equal(8, list.Count);
|
|
Assert.Equal("make_armor_quick", list[0].Id);
|
|
Assert.Equal("refine_scrap_standard", list[^1].Id);
|
|
}
|
|
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<IRecipeDefinitionRegistry>();
|
|
var found = registry.TryGetDefinition("refine_scrap_standard", out var refine);
|
|
var unknown = registry.TryGetDefinition("not_a_real_recipe", out var missing);
|
|
var list = registry.GetDefinitionsInIdOrder();
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.NotNull(refine);
|
|
Assert.Equal("process", refine.RecipeKind);
|
|
Assert.False(unknown);
|
|
Assert.Null(missing);
|
|
Assert.Equal(8, list.Count);
|
|
Assert.Contains(list, r => r.Id == "make_field_stim_mk0" && r.RecipeKind == "make");
|
|
}
|
|
}
|