Implement phase 3 standard critical imports
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RolemasterDb.ImportTool\RolemasterDb.ImportTool.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="UnitTest1.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,146 @@
|
||||
using RolemasterDb.ImportTool.Parsing;
|
||||
|
||||
namespace RolemasterDb.ImportTool.Tests;
|
||||
|
||||
public sealed class StandardCriticalTableParserIntegrationTests
|
||||
{
|
||||
private static readonly string[] ExpectedPhase3Slugs =
|
||||
[
|
||||
"arcane-aether",
|
||||
"arcane-nether",
|
||||
"ballistic-shrapnel",
|
||||
"brawling",
|
||||
"cold",
|
||||
"electricity",
|
||||
"grapple",
|
||||
"heat",
|
||||
"impact",
|
||||
"krush",
|
||||
"ma-strikes",
|
||||
"ma-sweeps",
|
||||
"puncture",
|
||||
"slash",
|
||||
"subdual",
|
||||
"tiny",
|
||||
"unbalance"
|
||||
];
|
||||
|
||||
private static readonly PdfXmlExtractor Extractor = new();
|
||||
private static readonly StandardCriticalTableParser Parser = new();
|
||||
|
||||
public static IEnumerable<object[]> EnabledStandardTables() =>
|
||||
LoadManifest().Tables
|
||||
.Where(item => item.Enabled)
|
||||
.OrderBy(item => item.Slug, StringComparer.Ordinal)
|
||||
.Select(item => new object[] { item });
|
||||
|
||||
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 ["tiny", "100", "E", "Vein and artery severed"];
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Manifest_enables_the_phase_3_standard_table_set()
|
||||
{
|
||||
var manifest = LoadManifest();
|
||||
var enabledTables = manifest.Tables
|
||||
.Where(item => item.Enabled)
|
||||
.OrderBy(item => item.Slug, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
Assert.Equal(ExpectedPhase3Slugs, 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}'.");
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EnabledStandardTables))]
|
||||
public async Task Enabled_standard_tables_extract_and_parse_successfully(CriticalImportManifestEntry entry)
|
||||
{
|
||||
var parseResult = await LoadParseResultAsync(entry);
|
||||
|
||||
Assert.True(parseResult.ValidationReport.IsValid, string.Join(Environment.NewLine, parseResult.ValidationReport.Errors));
|
||||
Assert.Equal(5, parseResult.Table.Columns.Count);
|
||||
Assert.NotEmpty(parseResult.Table.RollBands);
|
||||
Assert.Equal(parseResult.ValidationReport.RowCount * 5, parseResult.ValidationReport.CellCount);
|
||||
Assert.Equal(parseResult.ValidationReport.CellCount, parseResult.Table.Results.Count);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RepresentativeCells))]
|
||||
public async Task Representative_cells_keep_expected_descriptions(
|
||||
string slug,
|
||||
string rollBandLabel,
|
||||
string columnKey,
|
||||
string expectedSnippet)
|
||||
{
|
||||
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.RollBandLabel, rollBandLabel, StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, columnKey, StringComparison.Ordinal));
|
||||
|
||||
Assert.Contains(expectedSnippet, result.DescriptionText, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Slash_boundary_repair_keeps_56_60_a_prose_first()
|
||||
{
|
||||
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 =>
|
||||
string.Equals(item.RollBandLabel, "56-60", StringComparison.Ordinal) &&
|
||||
string.Equals(item.ColumnKey, "A", StringComparison.Ordinal));
|
||||
|
||||
Assert.StartsWith("You recover from your initial swing", result.RawCellText, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static async Task<StandardCriticalTableParseResult> LoadParseResultAsync(CriticalImportManifestEntry entry)
|
||||
{
|
||||
var xmlPath = Path.Combine(GetArtifactCacheRoot(), $"{entry.Slug}.xml");
|
||||
|
||||
if (!File.Exists(xmlPath))
|
||||
{
|
||||
await Extractor.ExtractAsync(Path.Combine(GetRepositoryRoot(), entry.PdfPath), xmlPath);
|
||||
}
|
||||
|
||||
var xmlContent = await File.ReadAllTextAsync(xmlPath);
|
||||
return Parser.Parse(entry, xmlContent);
|
||||
}
|
||||
|
||||
private static CriticalImportManifest LoadManifest() =>
|
||||
new CriticalImportManifestLoader().Load(Path.Combine(GetRepositoryRoot(), "sources", "critical-import-manifest.json"));
|
||||
|
||||
private static string GetArtifactCacheRoot()
|
||||
{
|
||||
var cacheRoot = Path.Combine(Path.GetTempPath(), "RolemasterDb.ImportTool.Tests");
|
||||
Directory.CreateDirectory(cacheRoot);
|
||||
return cacheRoot;
|
||||
}
|
||||
|
||||
private static string GetRepositoryRoot()
|
||||
{
|
||||
var probe = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
|
||||
while (probe is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(probe.FullName, "RolemasterDB.slnx")))
|
||||
{
|
||||
return probe.FullName;
|
||||
}
|
||||
|
||||
probe = probe.Parent;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Could not find the repository root for integration tests.");
|
||||
}
|
||||
}
|
||||
3
src/RolemasterDb.ImportTool.Tests/TestAssembly.cs
Normal file
3
src/RolemasterDb.ImportTool.Tests/TestAssembly.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
using Xunit;
|
||||
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
||||
Reference in New Issue
Block a user