using NeonSprawl.Server.Game.Factions; using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; public sealed class InMemoryReputationDeltaStoreTests { private const string PlayerId = "dev-local-1"; private const string GridFactionId = "prototype_faction_grid_operators"; private static readonly DateTimeOffset RecordedAt = new(2026, 6, 15, 12, 0, 0, TimeSpan.Zero); [Fact] public void TryAppend_ShouldReturnTrueAndQueryRow_WhenFirstAppend() { // Arrange var store = CreateStore(); var row = CreateRow("delta-001", 15, 15); // Act var appended = store.TryAppend(row); var rows = store.GetDeltasForPlayer(PlayerId); // Assert Assert.True(appended); var read = Assert.Single(rows); Assert.Equal(row.Id, read.Id); Assert.Equal(15, read.DeltaAmount); Assert.Equal(15, read.ResultingStanding); } [Fact] public void TryAppend_ShouldReturnFalse_WhenDuplicateId() { // Arrange var store = CreateStore(); var row = CreateRow("delta-dup", 10, 10); Assert.True(store.TryAppend(row)); // Act var duplicate = store.TryAppend(row with { DeltaAmount = 99, ResultingStanding = 99 }); // Assert Assert.False(duplicate); var read = Assert.Single(store.GetDeltasForPlayer(PlayerId)); Assert.Equal(10, read.DeltaAmount); } [Fact] public void TryAppend_ShouldReturnTrueTwice_WhenDistinctIds() { // Arrange var store = CreateStore(); // Act var first = store.TryAppend(CreateRow("delta-a", 15, 15)); var second = store.TryAppend(CreateRow("delta-b", 10, 25)); // Assert Assert.True(first); Assert.True(second); Assert.Equal(2, store.GetDeltasForPlayer(PlayerId).Count); } [Fact] public void TryAppend_ShouldReturnFalse_WhenRowInvalid() { // Arrange var store = CreateStore(); var emptyId = CreateRow("", 5, 5); var emptyPlayer = CreateRow("delta-x", 5, 5) with { PlayerId = " " }; var emptyFaction = CreateRow("delta-y", 5, 5) with { FactionId = "" }; // Act var noId = store.TryAppend(emptyId); var noPlayer = store.TryAppend(emptyPlayer); var noFaction = store.TryAppend(emptyFaction); // Assert Assert.False(noId); Assert.False(noPlayer); Assert.False(noFaction); Assert.Empty(store.GetDeltasForPlayer(PlayerId)); } [Fact] public void GetDeltasForPlayer_ShouldOrderByRecordedAtThenId() { // Arrange var store = CreateStore(); Assert.True(store.TryAppend(CreateRow("delta-z", 1, 1) with { RecordedAt = RecordedAt.AddMinutes(2) })); Assert.True(store.TryAppend(CreateRow("delta-a", 2, 3) with { RecordedAt = RecordedAt })); Assert.True(store.TryAppend(CreateRow("delta-m", 3, 6) with { RecordedAt = RecordedAt })); // Act var rows = store.GetDeltasForPlayer(PlayerId); // Assert Assert.Equal(["delta-a", "delta-m", "delta-z"], rows.Select(static r => r.Id).ToArray()); } [Fact] public void GetDeltasForPlayer_ShouldRespectLimit_WhenProvided() { // Arrange var store = CreateStore(); Assert.True(store.TryAppend(CreateRow("delta-1", 1, 1))); Assert.True(store.TryAppend(CreateRow("delta-2", 1, 2))); // Act var rows = store.GetDeltasForPlayer(PlayerId, limit: 1); // Assert Assert.Single(rows); Assert.Equal("delta-1", rows[0].Id); } private static InMemoryReputationDeltaStore CreateStore() => new(); private static ReputationDeltaRow CreateRow(string id, int delta, int resulting) => new( id, PlayerId, GridFactionId, delta, resulting, ReputationDeltaSourceKinds.QuestCompletion, "prototype_quest_operator_chain", RecordedAt); }