Implement phase 6 critical effect normalization
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
using RolemasterDb.App.Data;
|
||||
using RolemasterDb.App.Domain;
|
||||
using RolemasterDb.App.Features;
|
||||
using RolemasterDb.ImportTool.Parsing;
|
||||
|
||||
namespace RolemasterDb.ImportTool.Tests;
|
||||
@@ -303,7 +305,112 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Loader_upgrades_existing_sqlite_and_persists_branch_rows()
|
||||
public async Task Slash_base_affixes_are_normalized_into_effects()
|
||||
{
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "slash", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var result = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "51-55", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "D", StringComparison.Ordinal));
|
||||
|
||||
Assert.Equal("+5H – π – 3∫ – (-15)", result.RawAffixText);
|
||||
Assert.Collection(
|
||||
result.Effects,
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.DirectHits, effect.EffectCode);
|
||||
Assert.Equal(5, effect.ValueInteger);
|
||||
},
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.MustParryRounds, effect.EffectCode);
|
||||
Assert.Equal(1, effect.DurationRounds);
|
||||
},
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.BleedPerRound, effect.EffectCode);
|
||||
Assert.Equal(3, effect.PerRound);
|
||||
},
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.FoePenalty, effect.EffectCode);
|
||||
Assert.Equal(-15, effect.Modifier);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Slash_branch_affixes_are_normalized_into_effects()
|
||||
{
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "slash", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var result = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "36-45", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "B", StringComparison.Ordinal));
|
||||
|
||||
var withGreaves = result.Branches.Single(item => string.Equals(item.ConditionKey, "with_leg_greaves", StringComparison.Ordinal));
|
||||
var withoutGreaves = result.Branches.Single(item => string.Equals(item.ConditionKey, "without_leg_greaves", StringComparison.Ordinal));
|
||||
|
||||
Assert.Collection(
|
||||
withGreaves.Effects,
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.DirectHits, effect.EffectCode);
|
||||
Assert.Equal(2, effect.ValueInteger);
|
||||
},
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.MustParryRounds, effect.EffectCode);
|
||||
Assert.Equal(1, effect.DurationRounds);
|
||||
});
|
||||
|
||||
Assert.Collection(
|
||||
withoutGreaves.Effects,
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.DirectHits, effect.EffectCode);
|
||||
Assert.Equal(2, effect.ValueInteger);
|
||||
},
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.BleedPerRound, effect.EffectCode);
|
||||
Assert.Equal(1, effect.PerRound);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Mana_affixes_use_footer_legend_for_stun_and_powerpoint_modification()
|
||||
{
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "mana", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var result = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "21-35", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "C", StringComparison.Ordinal));
|
||||
|
||||
Assert.Equal("+8H - - +(2d10-18)P", result.RawAffixText);
|
||||
Assert.Collection(
|
||||
result.Effects,
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.DirectHits, effect.EffectCode);
|
||||
Assert.Equal(8, effect.ValueInteger);
|
||||
},
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.StunnedRounds, effect.EffectCode);
|
||||
Assert.Equal(1, effect.DurationRounds);
|
||||
},
|
||||
effect =>
|
||||
{
|
||||
Assert.Equal(CriticalEffectCodes.PowerPointModifier, effect.EffectCode);
|
||||
Assert.Equal("2d10-18", effect.ValueExpression);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Loader_upgrades_existing_sqlite_and_persists_branch_rows_and_effects()
|
||||
{
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "slash", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
@@ -318,6 +425,7 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
.Include(item => item.CriticalColumn)
|
||||
.Include(item => item.CriticalRollBand)
|
||||
.Include(item => item.Branches)
|
||||
.ThenInclude(item => item.Effects)
|
||||
.SingleAsync(item =>
|
||||
item.CriticalTable.Slug == "slash" &&
|
||||
item.CriticalColumn.ColumnKey == "B" &&
|
||||
@@ -327,6 +435,34 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
Assert.Equal(2, result.Branches.Count);
|
||||
Assert.Contains(result.Branches, item => item.ConditionKey == "with_leg_greaves" && item.RawAffixText == "+2H – π");
|
||||
Assert.Contains(result.Branches, item => item.ConditionKey == "without_leg_greaves" && item.RawAffixText == "+2H – ∫");
|
||||
Assert.Contains(result.Branches.SelectMany(item => item.Effects), item => item.EffectCode == CriticalEffectCodes.MustParryRounds);
|
||||
Assert.Contains(result.Branches.SelectMany(item => item.Effects), item => item.EffectCode == CriticalEffectCodes.BleedPerRound);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Lookup_service_returns_effects_for_results_and_branches()
|
||||
{
|
||||
var slashEntry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "slash", StringComparison.Ordinal));
|
||||
var manaEntry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "mana", StringComparison.Ordinal));
|
||||
var slashParseResult = await LoadParseResultAsync(slashEntry);
|
||||
var manaParseResult = await LoadParseResultAsync(manaEntry);
|
||||
var databasePath = CreateTemporaryDatabaseCopy();
|
||||
var loader = new CriticalImportLoader(databasePath);
|
||||
|
||||
await loader.LoadAsync(slashParseResult.Table);
|
||||
await loader.LoadAsync(manaParseResult.Table);
|
||||
|
||||
var factory = CreateDbContextFactory(databasePath);
|
||||
var lookupService = new LookupService(factory);
|
||||
|
||||
var slashResponse = await lookupService.LookupCriticalAsync(new CriticalLookupRequest("slash", "B", 40, null));
|
||||
var manaResponse = await lookupService.LookupCriticalAsync(new CriticalLookupRequest("mana", "C", 30, null));
|
||||
|
||||
Assert.NotNull(slashResponse);
|
||||
Assert.NotNull(manaResponse);
|
||||
Assert.Contains(slashResponse!.Branches, branch => branch.ConditionKey == "with_leg_greaves" && branch.Effects.Any(effect => effect.EffectCode == CriticalEffectCodes.MustParryRounds));
|
||||
Assert.Contains(slashResponse.Branches, branch => branch.ConditionKey == "without_leg_greaves" && branch.Effects.Any(effect => effect.EffectCode == CriticalEffectCodes.BleedPerRound));
|
||||
Assert.Contains(manaResponse!.Effects, effect => effect.EffectCode == CriticalEffectCodes.PowerPointModifier && effect.ValueExpression == "2d10-18");
|
||||
}
|
||||
|
||||
private static async Task<CriticalTableParseResult> LoadParseResultAsync(CriticalImportManifestEntry entry)
|
||||
@@ -367,6 +503,15 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
return new RolemasterDbContext(options);
|
||||
}
|
||||
|
||||
private static IDbContextFactory<RolemasterDbContext> CreateDbContextFactory(string databasePath)
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<RolemasterDbContext>()
|
||||
.UseSqlite($"Data Source={databasePath}")
|
||||
.Options;
|
||||
|
||||
return new TestRolemasterDbContextFactory(options);
|
||||
}
|
||||
|
||||
private static string CreateTemporaryDatabaseCopy()
|
||||
{
|
||||
var databasePath = Path.Combine(GetArtifactCacheRoot(), $"rolemaster-{Guid.NewGuid():N}.db");
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
using RolemasterDb.App.Data;
|
||||
|
||||
namespace RolemasterDb.ImportTool.Tests;
|
||||
|
||||
internal sealed class TestRolemasterDbContextFactory(DbContextOptions<RolemasterDbContext> options) : IDbContextFactory<RolemasterDbContext>
|
||||
{
|
||||
public RolemasterDbContext CreateDbContext() => new(options);
|
||||
|
||||
public Task<RolemasterDbContext> CreateDbContextAsync(CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(CreateDbContext());
|
||||
}
|
||||
Reference in New Issue
Block a user