Files
Ludarium-Public/tests/Ludarium.UnitTests/CatalogImportTests.cs
T
Ludarium release export df869819ce
Public source validation / source (push) Successful in 2m16s
Publish Ludarium source
2026-09-03 02:08:58 +02:00

50 lines
2.7 KiB
C#

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 = """
<?xml version="1.0"?>
<datafile><header><name>Synthetic</name></header><game name="Example Game">
<rom name="example.nes" size="16" crc="CBF43926" sha1="a9993e364706816aba3e25717850c26c9cd0d89d" sha256="ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" />
<rom name="ignored.bin" size="4" />
</game></datafile>
""";
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 = "<!DOCTYPE datafile [<!ENTITY x SYSTEM 'file:///etc/passwd'>]><datafile><game name='x'><rom name='x' crc='00000000'/></game></datafile>";
var importer = new LogiqxCatalogImporter(new CapturingCatalogStore());
await using var input = new MemoryStream(Encoding.UTF8.GetBytes(xml));
await Assert.ThrowsAsync<XmlException>(() => importer.ImportLogiqxAsync("Hostile", "1", input, CancellationToken.None));
}
private sealed class CapturingCatalogStore : ICatalogStore
{
public List<CatalogEntry> Entries { get; } = [];
public int MatchCalls { get; private set; }
public Task UpsertCatalogSourceAsync(CatalogSource source, CancellationToken cancellationToken) => Task.CompletedTask;
public Task UpsertCatalogEntriesAsync(IReadOnlyList<CatalogEntry> entries, CancellationToken cancellationToken) { Entries.AddRange(entries); return Task.CompletedTask; }
public Task<IReadOnlyList<CatalogSource>> ListCatalogSourcesAsync(CancellationToken cancellationToken) => Task.FromResult<IReadOnlyList<CatalogSource>>([]);
public Task<int> MatchCatalogAsync(Guid sourceId, CancellationToken cancellationToken) { MatchCalls++; return Task.FromResult(Entries.Count); }
public Task<IReadOnlyList<MatchCandidate>> ListMatchCandidatesAsync(CancellationToken cancellationToken) => Task.FromResult<IReadOnlyList<MatchCandidate>>([]);
}
}