using System.Text; using System.Xml; using Ludarium.Application; using Ludarium.Domain; namespace Ludarium.UnitTests; public sealed class CatalogImportTests { [Fact] public async Task LogiqxImportIsVersionedStreamingAndDeterministic() { const string xml = """
Synthetic
"""; var store = new CapturingCatalogStore(); var importer = new LogiqxCatalogImporter(store); await using var input = new MemoryStream(Encoding.UTF8.GetBytes(xml)); var source = await importer.ImportLogiqxAsync("Synthetic DAT", "2026.07", input, CancellationToken.None); Assert.Equal("Ready", source.State); Assert.Equal(1, source.EntryCount); Assert.Equal(64, source.Sha256?.Length); var entry = Assert.Single(store.Entries); Assert.Equal("Example Game", entry.GameName); Assert.Equal("cbf43926", entry.Crc32); Assert.Equal(1, store.MatchCalls); } [Fact] public async Task LogiqxImportRejectsDocumentTypes() { const string xml = "]>"; var importer = new LogiqxCatalogImporter(new CapturingCatalogStore()); await using var input = new MemoryStream(Encoding.UTF8.GetBytes(xml)); await Assert.ThrowsAsync(() => importer.ImportLogiqxAsync("Hostile", "1", input, CancellationToken.None)); } private sealed class CapturingCatalogStore : ICatalogStore { public List Entries { get; } = []; public int MatchCalls { get; private set; } public Task UpsertCatalogSourceAsync(CatalogSource source, CancellationToken cancellationToken) => Task.CompletedTask; public Task UpsertCatalogEntriesAsync(IReadOnlyList entries, CancellationToken cancellationToken) { Entries.AddRange(entries); return Task.CompletedTask; } public Task> ListCatalogSourcesAsync(CancellationToken cancellationToken) => Task.FromResult>([]); public Task MatchCatalogAsync(Guid sourceId, CancellationToken cancellationToken) { MatchCalls++; return Task.FromResult(Entries.Count); } public Task> ListMatchCandidatesAsync(CancellationToken cancellationToken) => Task.FromResult>([]); } }