CultLib/tests/GameCult.Networking.Tests/CultNetDocumentRegistryVariantTests.cs
Meta Vens fc78b9ad2b Test the C# variant path and add the C#-written variant store as a shared vector
VariantTests drive the cache batch API and the real single-file store. The C1
vector was written by the code under test through that path; C# reads it and
rewrites it byte for byte, and the other runtimes' tests read the same bytes next.
The C0 tests that expected C# to refuse a v2 store now expect what C1 does with
it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 03:52:35 +02:00

78 lines
3.4 KiB
C#

#nullable enable
using System;
using System.Threading.Tasks;
using GameCult.Caching;
using GameCult.Caching.MessagePack;
using MessagePack;
using NUnit.Framework;
namespace GameCult.Networking.Tests
{
// Q6 (docs/document-variants-cut.md C1): CultNet carries no variant deltas yet, so building a row for one is refused
// loudly, on the v1 selection path and on the v0 snapshot path alike.
public sealed class CultNetDocumentRegistryVariantTests
{
private static readonly CultRecordKey BaseKey = new("variant-fixture-base");
private static readonly CultRecordKey VariantKey = new("variant-fixture-big");
private static async Task<(CultCache Cache, CultNetDocumentRegistry Documents)> BuildFixtureAsync(bool withVariant)
{
var registry = CultDocumentRegistry.Shared;
var cache = new CultCache(registry, CultCacheMessagePack.CreateCodec(registry));
var documents = new CultNetDocumentRegistry(registry)
.Register(CultNetDocumentBinding.ForDocument<VariantWireFixture>(registry));
await cache.UpsertAsync(new VariantWireFixture { Name = "base", Power = 1 }, new CultRecordHandle<VariantWireFixture>(BaseKey));
if (withVariant)
await cache.UpsertVariantAsync(VariantKey, BaseKey, new[]
{
cache.Override<VariantWireFixture>(nameof(VariantWireFixture.Name), "big"),
cache.Override<VariantWireFixture>(nameof(VariantWireFixture.Power), 9)
});
return (cache, documents);
}
[Test]
public async Task SelectionResponseRefusesAVariantRowNamingIt()
{
var (cache, documents) = await BuildFixtureAsync(withVariant: true);
var selection = new CultNetSelection { Projection = CultNetSelectionProjections.Document };
var error = Assert.Throws<NotSupportedException>(() =>
documents.CreateSelectionResponse(cache, "m1", selection, ordinalOf: (_, _) => 1, asOf: 1))!;
Assert.That(error.Message, Does.Contain(VariantKey.Value).And.Contain(BaseKey.Value));
}
[Test]
public async Task RawSnapshotResponseRefusesAVariantRowNamingIt()
{
var (cache, documents) = await BuildFixtureAsync(withVariant: true);
var error = Assert.Throws<NotSupportedException>(() => documents.CreateRawSnapshotResponse(cache, "m1"))!;
Assert.That(error.Message, Does.Contain(VariantKey.Value));
}
[Test]
public async Task ACacheWithoutVariantsStillAnswersBothPaths()
{
var (cache, documents) = await BuildFixtureAsync(withVariant: false);
var selection = new CultNetSelection { Projection = CultNetSelectionProjections.Document };
Assert.That(documents.CreateSelectionResponse(cache, "m1", selection, ordinalOf: (_, _) => 1, asOf: 1).Documents, Has.Length.EqualTo(1));
Assert.That(documents.CreateRawSnapshotResponse(cache, "m2").Documents, Has.Length.EqualTo(1));
}
[CultDocument("variants.wire-fixture", "variants.wire-fixture.v1")]
[MessagePackObject(AllowPrivate = true)]
public sealed class VariantWireFixture
{
[Key(0)]
[CultName]
public string Name = string.Empty;
[Key(1)]
public int Power;
}
}
}