Implement phase 4 critical table imports
This commit is contained in:
@@ -4,7 +4,7 @@ namespace RolemasterDb.ImportTool.Tests;
|
||||
|
||||
public sealed class StandardCriticalTableParserIntegrationTests
|
||||
{
|
||||
private static readonly string[] ExpectedPhase3Slugs =
|
||||
private static readonly string[] ExpectedEnabledSlugs =
|
||||
[
|
||||
"arcane-aether",
|
||||
"arcane-nether",
|
||||
@@ -16,20 +16,25 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
"heat",
|
||||
"impact",
|
||||
"krush",
|
||||
"large_creature_magic",
|
||||
"large_creature_weapon",
|
||||
"ma-strikes",
|
||||
"ma-sweeps",
|
||||
"mana",
|
||||
"puncture",
|
||||
"slash",
|
||||
"subdual",
|
||||
"super_large_creature_weapon",
|
||||
"tiny",
|
||||
"unbalance"
|
||||
];
|
||||
|
||||
private static readonly PdfXmlExtractor Extractor = new();
|
||||
private static readonly StandardCriticalTableParser Parser = new();
|
||||
private static readonly StandardCriticalTableParser StandardParser = new();
|
||||
private static readonly VariantColumnCriticalTableParser VariantColumnParser = new();
|
||||
private static readonly GroupedVariantCriticalTableParser GroupedVariantParser = new();
|
||||
|
||||
public static IEnumerable<object[]> EnabledStandardTables() =>
|
||||
public static IEnumerable<object[]> EnabledTables() =>
|
||||
LoadManifest().Tables
|
||||
.Where(item => item.Enabled)
|
||||
.OrderBy(item => item.Slug, StringComparer.Ordinal)
|
||||
@@ -37,18 +42,22 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
|
||||
public static IEnumerable<object[]> RepresentativeCells()
|
||||
{
|
||||
yield return ["slash", "71-75", "A", "Blow falls on lower leg"];
|
||||
yield return ["puncture", "66", "C", "Strike shatters foe's knee"];
|
||||
yield return ["ballistic-shrapnel", "86-90", "E", "destroy his heart"];
|
||||
yield return ["arcane-aether", "96-99", "E", "smoking pulp"];
|
||||
yield return ["ma-strikes", "96-99", "E", "drives bone into brain"];
|
||||
yield return ["mana", "96-99", "E", "momentarily transformed"];
|
||||
yield return ["mana", "100", "E", "Mana consumes everything"];
|
||||
yield return ["tiny", "100", "E", "Vein and artery severed"];
|
||||
yield return new object[] { "slash", null!, "71-75", "A", "Blow falls on lower leg" };
|
||||
yield return new object[] { "puncture", null!, "66", "C", "Strike shatters foe's knee" };
|
||||
yield return new object[] { "ballistic-shrapnel", null!, "86-90", "E", "destroy his heart" };
|
||||
yield return new object[] { "arcane-aether", null!, "96-99", "E", "smoking pulp" };
|
||||
yield return new object[] { "ma-strikes", null!, "96-99", "E", "drives bone into brain" };
|
||||
yield return new object[] { "mana", null!, "96-99", "E", "momentarily transformed" };
|
||||
yield return new object[] { "mana", null!, "100", "E", "Mana consumes everything" };
|
||||
yield return new object[] { "tiny", null!, "100", "E", "Vein and artery severed" };
|
||||
yield return new object[] { "large_creature_weapon", null!, "01-05", "NORMAL", "Weapon shatters" };
|
||||
yield return new object[] { "super_large_creature_weapon", null!, "31-40", "SLAYING", "Boom! Solid without question" };
|
||||
yield return new object[] { "large_creature_magic", "large", "251+", "NORMAL", "Foe lowers his eyes within your reach" };
|
||||
yield return new object[] { "large_creature_magic", "super_large", "251+", "SLAYING", "Blast goes in through foe's eye" };
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Manifest_enables_the_phase_3_standard_table_set()
|
||||
public void Manifest_enables_the_phase_4_table_set()
|
||||
{
|
||||
var manifest = LoadManifest();
|
||||
var enabledTables = manifest.Tables
|
||||
@@ -56,25 +65,29 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
.OrderBy(item => item.Slug, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
Assert.Equal(ExpectedPhase3Slugs, enabledTables.Select(item => item.Slug));
|
||||
Assert.Equal(ExpectedEnabledSlugs, enabledTables.Select(item => item.Slug));
|
||||
Assert.All(enabledTables, entry =>
|
||||
{
|
||||
Assert.Equal("standard", entry.Family);
|
||||
Assert.Equal("xml", entry.ExtractionMethod);
|
||||
Assert.True(File.Exists(Path.Combine(GetRepositoryRoot(), entry.PdfPath)), $"Missing source PDF for '{entry.Slug}'.");
|
||||
});
|
||||
|
||||
Assert.Equal("variant_column", enabledTables.Single(item => item.Slug == "large_creature_weapon").Family);
|
||||
Assert.Equal("variant_column", enabledTables.Single(item => item.Slug == "super_large_creature_weapon").Family);
|
||||
Assert.Equal("grouped_variant", enabledTables.Single(item => item.Slug == "large_creature_magic").Family);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EnabledStandardTables))]
|
||||
public async Task Enabled_standard_tables_extract_and_parse_successfully(CriticalImportManifestEntry entry)
|
||||
[MemberData(nameof(EnabledTables))]
|
||||
public async Task Enabled_tables_extract_and_parse_successfully(CriticalImportManifestEntry entry)
|
||||
{
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var expectedGroupCount = Math.Max(parseResult.Table.Groups.Count, 1);
|
||||
|
||||
Assert.True(parseResult.ValidationReport.IsValid, string.Join(Environment.NewLine, parseResult.ValidationReport.Errors));
|
||||
Assert.Equal(5, parseResult.Table.Columns.Count);
|
||||
Assert.NotEmpty(parseResult.Table.Columns);
|
||||
Assert.NotEmpty(parseResult.Table.RollBands);
|
||||
Assert.Equal(parseResult.ValidationReport.RowCount * 5, parseResult.ValidationReport.CellCount);
|
||||
Assert.Equal(parseResult.ValidationReport.RowCount * parseResult.Table.Columns.Count * expectedGroupCount, parseResult.ValidationReport.CellCount);
|
||||
Assert.Equal(parseResult.ValidationReport.CellCount, parseResult.Table.Results.Count);
|
||||
}
|
||||
|
||||
@@ -82,6 +95,7 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
[MemberData(nameof(RepresentativeCells))]
|
||||
public async Task Representative_cells_keep_expected_descriptions(
|
||||
string slug,
|
||||
string? groupKey,
|
||||
string rollBandLabel,
|
||||
string columnKey,
|
||||
string expectedSnippet)
|
||||
@@ -89,6 +103,7 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, slug, StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var result = parseResult.Table.Results.Single(item =>
|
||||
string.Equals(item.GroupKey, groupKey, StringComparison.Ordinal) &&
|
||||
string.Equals(item.RollBandLabel, rollBandLabel, StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, columnKey, StringComparison.Ordinal));
|
||||
|
||||
@@ -101,6 +116,7 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
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, "56-60", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "A", StringComparison.Ordinal));
|
||||
|
||||
@@ -113,9 +129,11 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "mana", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var row96E = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "96-99", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "E", StringComparison.Ordinal));
|
||||
var row100E = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "100", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "E", StringComparison.Ordinal));
|
||||
|
||||
@@ -130,6 +148,7 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "mana", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var row100C = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "100", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "C", StringComparison.Ordinal));
|
||||
|
||||
@@ -143,9 +162,11 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "mana", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var row71A = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "71-75", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "A", StringComparison.Ordinal));
|
||||
var row71B = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "71-75", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "B", StringComparison.Ordinal));
|
||||
|
||||
@@ -159,9 +180,11 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "mana", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var row71D = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "71-75", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "D", StringComparison.Ordinal));
|
||||
var row71E = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "71-75", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "E", StringComparison.Ordinal));
|
||||
|
||||
@@ -175,9 +198,11 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "mana", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var row91B = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "91-95", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "B", StringComparison.Ordinal));
|
||||
var row91C = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "91-95", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "C", StringComparison.Ordinal));
|
||||
|
||||
@@ -191,9 +216,11 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "mana", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
var row86B = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "86-90", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "B", StringComparison.Ordinal));
|
||||
var row86C = parseResult.Table.Results.Single(item =>
|
||||
item.GroupKey is null &&
|
||||
string.Equals(item.RollBandLabel, "86-90", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "C", StringComparison.Ordinal));
|
||||
|
||||
@@ -201,7 +228,28 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
Assert.Contains("+16H - 8", row86C.RawAffixText, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static async Task<StandardCriticalTableParseResult> LoadParseResultAsync(CriticalImportManifestEntry entry)
|
||||
[Fact]
|
||||
public async Task Grouped_magic_table_keeps_large_and_super_large_groups_distinct()
|
||||
{
|
||||
var entry = LoadManifest().Tables.Single(item => string.Equals(item.Slug, "large_creature_magic", StringComparison.Ordinal));
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
|
||||
Assert.Equal(["large", "super_large"], parseResult.Table.Groups.Select(item => item.GroupKey));
|
||||
|
||||
var largeNormal = parseResult.Table.Results.Single(item =>
|
||||
string.Equals(item.GroupKey, "large", StringComparison.Ordinal) &&
|
||||
string.Equals(item.RollBandLabel, "251+", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "NORMAL", StringComparison.Ordinal));
|
||||
var superSlaying = parseResult.Table.Results.Single(item =>
|
||||
string.Equals(item.GroupKey, "super_large", StringComparison.Ordinal) &&
|
||||
string.Equals(item.RollBandLabel, "251+", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "SLAYING", StringComparison.Ordinal));
|
||||
|
||||
Assert.DoesNotContain("Blast goes in through foe's eye", largeNormal.DescriptionText, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("Blast goes in through foe's eye", superSlaying.DescriptionText, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static async Task<CriticalTableParseResult> LoadParseResultAsync(CriticalImportManifestEntry entry)
|
||||
{
|
||||
var xmlPath = Path.Combine(GetArtifactCacheRoot(), $"{entry.Slug}.xml");
|
||||
|
||||
@@ -211,7 +259,13 @@ public sealed class StandardCriticalTableParserIntegrationTests
|
||||
}
|
||||
|
||||
var xmlContent = await File.ReadAllTextAsync(xmlPath);
|
||||
return Parser.Parse(entry, xmlContent);
|
||||
return entry.Family switch
|
||||
{
|
||||
"standard" => StandardParser.Parse(entry, xmlContent),
|
||||
"variant_column" => VariantColumnParser.Parse(entry, xmlContent),
|
||||
"grouped_variant" => GroupedVariantParser.Parse(entry, xmlContent),
|
||||
_ => throw new InvalidOperationException($"Unsupported manifest family '{entry.Family}'.")
|
||||
};
|
||||
}
|
||||
|
||||
private static CriticalImportManifest LoadManifest() =>
|
||||
|
||||
Reference in New Issue
Block a user