Files
Christopher Wiebe b451f83174 Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback
anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md).
All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:40:51 -07:00

83 lines
2.8 KiB
C#

using Theriapolis.Core;
using Theriapolis.Core.Persistence;
using Theriapolis.Core.Rules.Quests;
using Xunit;
namespace Theriapolis.Tests.Quests;
/// <summary>
/// Phase 6 M4 — capture/restore round-trip for quest engine state.
/// </summary>
public sealed class QuestSnapshotTests
{
[Fact]
public void CaptureAndRestore_RoundTripActiveAndCompleted()
{
var engine = new QuestEngine();
engine.AdoptActive(new QuestState
{
QuestId = "q1", CurrentStep = "step_a", Status = QuestStatus.Active,
StartedAt = 100, StepStartedAt = 150,
});
engine.Get("q1")!.Journal.Add("started q1");
engine.AdoptCompleted(new QuestState
{
QuestId = "q2", CurrentStep = "<end>", Status = QuestStatus.Completed,
StartedAt = 0, StepStartedAt = 200,
});
engine.Journal.Add("global event 1");
var snap = QuestCodec.Capture(engine);
Assert.Single(snap.Active);
Assert.Single(snap.Completed);
Assert.Single(snap.Journal);
var rebuilt = new QuestEngine();
QuestCodec.Restore(rebuilt, snap);
Assert.True(rebuilt.IsActive("q1"));
Assert.True(rebuilt.IsCompleted("q2"));
Assert.Single(rebuilt.Journal);
Assert.Equal("step_a", rebuilt.Get("q1")!.CurrentStep);
Assert.Contains("started q1", rebuilt.Get("q1")!.Journal);
}
[Fact]
public void SaveCodec_RoundTripsQuestEngineState()
{
var engine = new QuestEngine();
engine.AdoptActive(new QuestState
{
QuestId = "main_act_i_001_arrival",
CurrentStep = "find_magistrate",
Status = QuestStatus.Active,
StartedAt = 500, StepStartedAt = 700,
});
engine.Journal.Add("Arrived in Millhaven");
var body = new SaveBody();
body.Player.Name = "Tester";
body.QuestEngineState = QuestCodec.Capture(engine);
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.Single(b2.QuestEngineState.Active);
Assert.Equal("find_magistrate", b2.QuestEngineState.Active[0].CurrentStep);
Assert.Single(b2.QuestEngineState.Journal);
}
[Fact]
public void EmptyEngineState_OmitsTagFromSave()
{
// No active/completed/journal → no TAG_QUESTS section written.
var body = new SaveBody { Player = { Name = "Empty" } };
var bytes = SaveCodec.Serialize(new SaveHeader(), body);
var (_, b2) = SaveCodec.Deserialize(bytes);
Assert.Empty(b2.QuestEngineState.Active);
Assert.Empty(b2.QuestEngineState.Completed);
Assert.Empty(b2.QuestEngineState.Journal);
}
}