NEO-67: address code review nits on recipe registry
Delegate TryGetDefinition to catalog.TryGetRecipe, cache ordered defs at construction, and assert unknown recipeId in host DI test.pull/101/head
parent
2fc3b8f750
commit
95d42803e1
|
|
@ -37,11 +37,11 @@ None.
|
||||||
|
|
||||||
## Nits
|
## Nits
|
||||||
|
|
||||||
- Nit: `RecipeDefinitionRegistry.TryGetDefinition` reads `catalog.ById` directly instead of delegating to `catalog.TryGetRecipe` — consistent with `ItemDefinitionRegistry` (NEO-52), but both bypass the catalog’s public lookup helper; harmless for immutable data.
|
- ~~Nit: `RecipeDefinitionRegistry.TryGetDefinition` reads `catalog.ById` directly instead of delegating to `catalog.TryGetRecipe` — consistent with `ItemDefinitionRegistry` (NEO-52), but both bypass the catalog’s public lookup helper; harmless for immutable data.~~ **Done.** Registry now delegates to `catalog.TryGetRecipe`.
|
||||||
|
|
||||||
- Nit: `GetDefinitionsInIdOrder()` allocates a new sorted list on every call — acceptable for prototype HTTP/craft volume; optional future optimization is to cache the ordered list at catalog/registry construction time if hot-path profiling warrants it (same as item registry).
|
- ~~Nit: `GetDefinitionsInIdOrder()` allocates a new sorted list on every call — acceptable for prototype HTTP/craft volume; optional future optimization is to cache the ordered list at catalog/registry construction time if hot-path profiling warrants it (same as item registry).~~ **Done.** Ordered list built once in `RecipeDefinitionRegistry` constructor.
|
||||||
|
|
||||||
- Nit: `Host_ShouldResolveRegistryFromDi_WhenStartupSucceeds` asserts a known id and enumeration count but not an unknown id in the host context — unit tests cover unknown/null; host test could add one line for symmetry with E3M2-03 acceptance wording (“distinguishable from valid ids in tests”).
|
- ~~Nit: `Host_ShouldResolveRegistryFromDi_WhenStartupSucceeds` asserts a known id and enumeration count but not an unknown id in the host context — unit tests cover unknown/null; host test could add one line for symmetry with E3M2-03 acceptance wording (“distinguishable from valid ids in tests”).~~ **Done.** Host test asserts unknown `recipeId` returns false without throw.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -243,11 +243,14 @@ public class RecipeDefinitionRegistryTests
|
||||||
// Act
|
// Act
|
||||||
var registry = factory.Services.GetRequiredService<IRecipeDefinitionRegistry>();
|
var registry = factory.Services.GetRequiredService<IRecipeDefinitionRegistry>();
|
||||||
var found = registry.TryGetDefinition("refine_scrap_standard", out var refine);
|
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();
|
var list = registry.GetDefinitionsInIdOrder();
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(found);
|
Assert.True(found);
|
||||||
Assert.NotNull(refine);
|
Assert.NotNull(refine);
|
||||||
Assert.Equal("process", refine.RecipeKind);
|
Assert.Equal("process", refine.RecipeKind);
|
||||||
|
Assert.False(unknown);
|
||||||
|
Assert.Null(missing);
|
||||||
Assert.Equal(8, list.Count);
|
Assert.Equal(8, list.Count);
|
||||||
Assert.Contains(list, r => r.Id == "make_field_stim_mk0" && r.RecipeKind == "make");
|
Assert.Contains(list, r => r.Id == "make_field_stim_mk0" && r.RecipeKind == "make");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ namespace NeonSprawl.Server.Game.Crafting;
|
||||||
/// <summary>Adapter over <see cref="RecipeDefinitionCatalog"/> (NEO-67).</summary>
|
/// <summary>Adapter over <see cref="RecipeDefinitionCatalog"/> (NEO-67).</summary>
|
||||||
public sealed class RecipeDefinitionRegistry(RecipeDefinitionCatalog catalog) : IRecipeDefinitionRegistry
|
public sealed class RecipeDefinitionRegistry(RecipeDefinitionCatalog catalog) : IRecipeDefinitionRegistry
|
||||||
{
|
{
|
||||||
|
private readonly IReadOnlyList<RecipeDefRow> _definitionsInIdOrder = BuildDefinitionsInIdOrder(catalog);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool TryGetDefinition(string? recipeId, [NotNullWhen(true)] out RecipeDefRow? definition)
|
public bool TryGetDefinition(string? recipeId, [NotNullWhen(true)] out RecipeDefRow? definition)
|
||||||
{
|
{
|
||||||
|
|
@ -14,18 +16,13 @@ public sealed class RecipeDefinitionRegistry(RecipeDefinitionCatalog catalog) :
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (catalog.ById.TryGetValue(recipeId, out var row))
|
return catalog.TryGetRecipe(recipeId, out definition);
|
||||||
{
|
|
||||||
definition = row;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
definition = null;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IReadOnlyList<RecipeDefRow> GetDefinitionsInIdOrder()
|
public IReadOnlyList<RecipeDefRow> GetDefinitionsInIdOrder() => _definitionsInIdOrder;
|
||||||
|
|
||||||
|
private static IReadOnlyList<RecipeDefRow> BuildDefinitionsInIdOrder(RecipeDefinitionCatalog catalog)
|
||||||
{
|
{
|
||||||
var ids = catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal).ToArray();
|
var ids = catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal).ToArray();
|
||||||
var list = new List<RecipeDefRow>(ids.Length);
|
var list = new List<RecipeDefRow>(ids.Length);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue