CultLib/tests/GameCult.Caching.Tests/CultCacheClockTests.cs
Meta Vens b4edbb1eeb Union golden: the store's clock is an internal seam, the writer pins it, the gate test runs under any switch
CultCache mints storedAt from an internal Clock (default the wall clock); the vector writer pins it, so
union-surface.cc is regenerated in process and byte-compared on every run. The gate test sets the switch
itself and writes only a probe, so it neither skips nor touches a committed vector.

This commit does not pass: union-surface.cc still holds the old wall-clock stored-at; the next commit
regenerates it. Builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:58:54 +02:00

69 lines
2.6 KiB
C#

#nullable enable
using System;
using System.Globalization;
using System.IO;
using GameCult.Caching;
using GameCult.Caching.MessagePack;
using NUnit.Framework;
namespace GameCult.Caching.Tests
{
// The clock behind every storedAt: the wall clock by default, and a pinned one when a golden store has to reproduce.
public class CultCacheClockTests
{
private static readonly CultDocumentRegistry Registry = CultDocumentRegistry.ForTypes(new[] { typeof(UnionParityVectorTests.UnionSurface) });
private static readonly CultRecordKey Key = new("surface");
private string _directory = string.Empty;
[SetUp]
public void CreateDirectory()
{
_directory = Path.Combine(Path.GetTempPath(), $"cultlib-clock-{Guid.NewGuid():N}");
Directory.CreateDirectory(_directory);
}
[TearDown]
public void DeleteDirectory()
{
if (Directory.Exists(_directory)) Directory.Delete(_directory, recursive: true);
}
private CultCache Open() => CultCacheMessagePack.Create(Path.Combine(_directory, "clock.cc"), new CultCacheOpenOptions { Registry = Registry });
private static string Upsert(CultCache cache)
{
cache.UpsertAsync(typeof(UnionParityVectorTests.UnionSurface), new UnionParityVectorTests.UnionSurface(), Key).GetAwaiter().GetResult();
return cache.GetStored(Key)!.StoredAt;
}
[Test]
public void ADefaultCacheStampsTheWallClock()
{
using var cache = Open();
var before = DateTimeOffset.UtcNow;
var stamp = DateTimeOffset.Parse(Upsert(cache), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
var after = DateTimeOffset.UtcNow;
Assert.That(stamp, Is.InRange(before, after));
}
[Test]
public void APinnedClockIsTheStoredAt()
{
var pinned = new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);
using var cache = Open();
cache.Clock = () => pinned;
Assert.That(Upsert(cache), Is.EqualTo("2026-01-01T00:00:00.0000000+00:00"));
}
[Test]
public void APinnedClockStillIncreasesStoredAtPerKey()
{
var pinned = new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);
using var cache = Open();
cache.Clock = () => pinned;
Upsert(cache);
Assert.That(Upsert(cache), Is.EqualTo("2026-01-01T00:00:00.0000001+00:00"), "the same instant again is one tick later");
}
}
}