Expose critical curation and source image APIs
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
using RolemasterDb.App.Data;
|
||||
using RolemasterDb.App.Domain;
|
||||
using RolemasterDb.App.Features;
|
||||
|
||||
namespace RolemasterDb.ImportTool.Tests;
|
||||
|
||||
public sealed class LookupServiceCurationIntegrationTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Lookup_service_surfaces_and_persists_curated_state_and_source_image_metadata()
|
||||
{
|
||||
var databasePath = CreateEmptyDatabasePath();
|
||||
var repositoryRoot = CreateTemporaryRepositoryRoot();
|
||||
var locator = new CriticalImportArtifactLocator(new TestHostEnvironment(Path.Combine(repositoryRoot, "src", "RolemasterDb.App")));
|
||||
|
||||
await SeedCriticalResultAsync(databasePath, "slash/cells/source-cell.png", 2);
|
||||
WriteSourceImage(repositoryRoot, "slash/cells/source-cell.png");
|
||||
|
||||
var lookupService = new LookupService(CreateDbContextFactory(databasePath), locator);
|
||||
var resultId = await GetResultIdAsync(databasePath);
|
||||
|
||||
var initialResponse = await lookupService.GetCriticalCellEditorAsync("slash", resultId);
|
||||
Assert.NotNull(initialResponse);
|
||||
Assert.False(initialResponse!.IsCurated);
|
||||
Assert.Equal(2, initialResponse.SourcePageNumber);
|
||||
Assert.Equal($"/api/tables/critical/slash/cells/{resultId}/source-image", initialResponse.SourceImageUrl);
|
||||
|
||||
var updateRequest = new CriticalCellUpdateRequest(
|
||||
initialResponse.RawCellText,
|
||||
initialResponse.QuickParseInput,
|
||||
initialResponse.DescriptionText,
|
||||
initialResponse.RawAffixText,
|
||||
initialResponse.ParseStatus,
|
||||
initialResponse.ParsedJson,
|
||||
true,
|
||||
initialResponse.IsDescriptionOverridden,
|
||||
initialResponse.IsRawAffixTextOverridden,
|
||||
initialResponse.AreEffectsOverridden,
|
||||
initialResponse.AreBranchesOverridden,
|
||||
initialResponse.Effects,
|
||||
initialResponse.Branches);
|
||||
|
||||
var updatedResponse = await lookupService.UpdateCriticalCellAsync("slash", resultId, updateRequest);
|
||||
Assert.NotNull(updatedResponse);
|
||||
Assert.True(updatedResponse!.IsCurated);
|
||||
|
||||
var tableDetail = await lookupService.GetCriticalTableAsync("slash");
|
||||
Assert.NotNull(tableDetail);
|
||||
Assert.Contains(tableDetail!.Cells, item => item.ResultId == resultId && item.IsCurated);
|
||||
|
||||
var reopenedResponse = await lookupService.GetCriticalCellEditorAsync("slash", resultId);
|
||||
Assert.NotNull(reopenedResponse);
|
||||
Assert.True(reopenedResponse!.IsCurated);
|
||||
Assert.Equal(initialResponse.SourceImageUrl, reopenedResponse.SourceImageUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Lookup_service_resolves_source_image_paths_only_when_artifacts_exist()
|
||||
{
|
||||
var databasePath = CreateEmptyDatabasePath();
|
||||
var repositoryRoot = CreateTemporaryRepositoryRoot();
|
||||
var locator = new CriticalImportArtifactLocator(new TestHostEnvironment(Path.Combine(repositoryRoot, "src", "RolemasterDb.App")));
|
||||
|
||||
await SeedCriticalResultAsync(databasePath, "slash/cells/missing.png", 1);
|
||||
|
||||
var lookupService = new LookupService(CreateDbContextFactory(databasePath), locator);
|
||||
var resultId = await GetResultIdAsync(databasePath);
|
||||
|
||||
var missingPath = await lookupService.GetCriticalSourceImagePathAsync("slash", resultId);
|
||||
Assert.Null(missingPath);
|
||||
|
||||
WriteSourceImage(repositoryRoot, "slash/cells/missing.png");
|
||||
|
||||
var resolvedPath = await lookupService.GetCriticalSourceImagePathAsync("slash", resultId);
|
||||
Assert.NotNull(resolvedPath);
|
||||
Assert.True(File.Exists(resolvedPath));
|
||||
}
|
||||
|
||||
private static async Task SeedCriticalResultAsync(string databasePath, string sourceImagePath, int sourcePageNumber)
|
||||
{
|
||||
await using var dbContext = CreateDbContext(databasePath);
|
||||
await dbContext.Database.EnsureCreatedAsync();
|
||||
await RolemasterDbSchemaUpgrader.EnsureLatestAsync(dbContext);
|
||||
|
||||
var table = new CriticalTable
|
||||
{
|
||||
Slug = "slash",
|
||||
DisplayName = "Slash Critical Strike Table",
|
||||
Family = "standard",
|
||||
SourceDocument = "Slash.pdf"
|
||||
};
|
||||
var column = new CriticalColumn
|
||||
{
|
||||
CriticalTable = table,
|
||||
ColumnKey = "B",
|
||||
Label = "B",
|
||||
Role = "severity",
|
||||
SortOrder = 2
|
||||
};
|
||||
var rollBand = new CriticalRollBand
|
||||
{
|
||||
CriticalTable = table,
|
||||
Label = "36-40",
|
||||
MinRoll = 36,
|
||||
MaxRoll = 40,
|
||||
SortOrder = 8
|
||||
};
|
||||
|
||||
var result = new CriticalResult
|
||||
{
|
||||
CriticalTable = table,
|
||||
CriticalColumn = column,
|
||||
CriticalRollBand = rollBand,
|
||||
IsCurated = false,
|
||||
RawCellText = "Imported raw cell text",
|
||||
DescriptionText = "Imported description",
|
||||
ParseStatus = "partial",
|
||||
ParsedJson = "{}",
|
||||
SourcePageNumber = sourcePageNumber,
|
||||
SourceImagePath = sourceImagePath,
|
||||
SourceImageCropJson = "{\"pageNumber\":1}"
|
||||
};
|
||||
|
||||
result.Effects.Add(new CriticalEffect
|
||||
{
|
||||
EffectCode = CriticalEffectCodes.DirectHits,
|
||||
ValueInteger = 5,
|
||||
IsPermanent = false,
|
||||
SourceType = "symbol",
|
||||
SourceText = "+5H"
|
||||
});
|
||||
|
||||
dbContext.CriticalTables.Add(table);
|
||||
dbContext.CriticalResults.Add(result);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private static void WriteSourceImage(string repositoryRoot, string relativePath)
|
||||
{
|
||||
var fullPath = Path.Combine(repositoryRoot, "artifacts", "import", "critical", relativePath.Replace('/', Path.DirectorySeparatorChar));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);
|
||||
File.WriteAllBytes(fullPath, [137, 80, 78, 71]);
|
||||
}
|
||||
|
||||
private static async Task<int> GetResultIdAsync(string databasePath)
|
||||
{
|
||||
await using var dbContext = CreateDbContext(databasePath);
|
||||
return await dbContext.CriticalResults
|
||||
.Where(item => item.CriticalTable.Slug == "slash")
|
||||
.Select(item => item.Id)
|
||||
.SingleAsync();
|
||||
}
|
||||
|
||||
private static RolemasterDbContext CreateDbContext(string databasePath)
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<RolemasterDbContext>()
|
||||
.UseSqlite($"Data Source={databasePath}")
|
||||
.Options;
|
||||
|
||||
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 CreateEmptyDatabasePath() =>
|
||||
Path.Combine(Path.GetTempPath(), $"lookup-service-curation-{Guid.NewGuid():N}.db");
|
||||
|
||||
private static string CreateTemporaryRepositoryRoot()
|
||||
{
|
||||
var repositoryRoot = Path.Combine(Path.GetTempPath(), $"rolemaster-repo-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(Path.Combine(repositoryRoot, "src", "RolemasterDb.App"));
|
||||
File.WriteAllText(Path.Combine(repositoryRoot, "RolemasterDB.slnx"), string.Empty);
|
||||
return repositoryRoot;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user