Files

106 lines
4.5 KiB
C#
Raw Permalink Normal View History

using Theriapolis.Core;
using Theriapolis.Core.Data;
using Theriapolis.Core.Persistence;
using Theriapolis.Core.Rules.Reputation;
using Xunit;
namespace Theriapolis.Tests.Reputation;
/// <summary>
/// Phase 6 M2 — round-trip <see cref="PlayerReputation"/> through the
/// codec. Every field must survive Capture → Restore identically. Plus
/// the SaveCodec serialization path itself: write a SaveBody with rep
/// data, parse it back, compare.
/// </summary>
public sealed class ReputationRoundTripTests
{
[Fact]
public void CaptureRestore_FactionStandings_RoundTrips()
{
var factions = new ContentResolver(new ContentLoader(TestHelpers.DataDirectory)).Factions;
var rep = new PlayerReputation();
rep.Factions.Apply("inheritors", 30, factions);
rep.Factions.Apply("merchant_guilds", 50, factions);
var snap = ReputationCodec.Capture(rep);
var restored = ReputationCodec.Restore(snap);
Assert.Equal(rep.Factions.Get("inheritors"), restored.Factions.Get("inheritors"));
Assert.Equal(rep.Factions.Get("covenant_enforcers"), restored.Factions.Get("covenant_enforcers"));
Assert.Equal(rep.Factions.Get("merchant_guilds"), restored.Factions.Get("merchant_guilds"));
}
[Fact]
public void CaptureRestore_PersonalDispositions_RoundTrip()
{
var rep = new PlayerReputation();
var pd = rep.PersonalFor("millhaven.innkeeper");
pd.Score = 25;
pd.Trust = TrustLevel.Familiar;
pd.Betrayed = false;
pd.Memory.Add("saved-her-kit");
pd.Memory.Add("paid-for-the-window");
pd.Log.Add(new RepEvent { Kind = RepEventKind.Aid, RoleTag = "millhaven.innkeeper",
Magnitude = 10, Note = "first" });
var snap = ReputationCodec.Capture(rep);
var restored = ReputationCodec.Restore(snap);
Assert.True(restored.Personal.ContainsKey("millhaven.innkeeper"));
var rPd = restored.Personal["millhaven.innkeeper"];
Assert.Equal(25, rPd.Score);
Assert.Equal(TrustLevel.Familiar, rPd.Trust);
Assert.Contains("saved-her-kit", rPd.Memory);
Assert.Contains("paid-for-the-window", rPd.Memory);
Assert.Single(rPd.Log);
Assert.Equal("first", rPd.Log[0].Note);
}
[Fact]
public void CaptureRestore_Ledger_RoundTrips()
{
var factions = new ContentResolver(new ContentLoader(TestHelpers.DataDirectory)).Factions;
var rep = new PlayerReputation();
rep.Submit(new RepEvent { Kind = RepEventKind.Quest, FactionId = "inheritors", Magnitude = 10, Note = "a" }, factions);
rep.Submit(new RepEvent { Kind = RepEventKind.Betrayal, FactionId = "thorn_council", Magnitude = -25, Note = "b" }, factions);
var snap = ReputationCodec.Capture(rep);
var restored = ReputationCodec.Restore(snap);
Assert.Equal(rep.Ledger.Count, restored.Ledger.Count);
Assert.Equal(rep.Ledger.Entries[0].Note, restored.Ledger.Entries[0].Note);
Assert.Equal(rep.Ledger.Entries[1].Kind, restored.Ledger.Entries[1].Kind);
}
[Fact]
public void SaveCodec_RoundTripsReputationState()
{
var factions = new ContentResolver(new ContentLoader(TestHelpers.DataDirectory)).Factions;
var body = new SaveBody();
body.Player.Name = "Tester";
body.Player.PositionX = 100;
body.Player.PositionY = 200;
// Populate reputation state.
var rep = new PlayerReputation();
rep.Submit(new RepEvent { Kind = RepEventKind.Quest, FactionId = "inheritors", Magnitude = 10 }, factions);
var pd = rep.PersonalFor("millhaven.constable_fenn");
pd.Score = 7;
pd.Memory.Add("met-at-the-magistrate");
body.ReputationState = ReputationCodec.Capture(rep);
var header = new SaveHeader { Version = C.SAVE_SCHEMA_VERSION, WorldSeedHex = "0xCAFE" };
var bytes = SaveCodec.Serialize(header, body);
var (h2, b2) = SaveCodec.Deserialize(bytes);
Assert.Equal(C.SAVE_SCHEMA_VERSION, h2.Version);
Assert.Equal( 10, b2.ReputationState.FactionStandings["inheritors"]);
Assert.Equal( -5, b2.ReputationState.FactionStandings["covenant_enforcers"]);
Assert.Single(b2.ReputationState.Personal);
Assert.Equal("millhaven.constable_fenn", b2.ReputationState.Personal[0].RoleTag);
Assert.Contains("met-at-the-magistrate", b2.ReputationState.Personal[0].MemoryTags);
Assert.Single(b2.ReputationState.Ledger);
}
}