using Chessistics.Engine.Commands; using Chessistics.Engine.Events; using Chessistics.Engine.Model; using Chessistics.Tests.Helpers; using Xunit; namespace Chessistics.Tests.Simulation; public class QuickSaveTests { private SimHelper CreateSim() { var level = new BoardBuilder(4, 4) .WithProduction(0, 0, "Scierie", CargoType.Wood, amount: 1) .WithDemand(3, 0, "Depot", CargoType.Wood, 3, 30) .WithStock(PieceKind.Rook, 3) .Build(); return SimHelper.FromLevel(level); } [Fact] public void QuickSave_ReturnsSavedEvent() { var sim = CreateSim(); var events = sim.Sim.QuickSave(); Assert.Single(events); Assert.IsType(events[0]); } [Fact] public void QuickLoad_WithoutSave_ReturnsEmpty() { var sim = CreateSim(); var events = sim.Sim.QuickLoad(); Assert.Empty(events); } [Fact] public void QuickLoad_AfterSave_EmitsRestoredEvent() { var sim = CreateSim(); sim.Sim.QuickSave(); var events = sim.Sim.QuickLoad(); Assert.Single(events); var restored = Assert.IsType(events[0]); Assert.NotNull(restored.Snapshot); } [Fact] public void Save_MutateState_Load_RestoresPreviousState() { var sim = CreateSim(); // Place a piece, then save sim.Place(PieceKind.Rook, (0, 0), (1, 0)); sim.Sim.QuickSave(); var beforeSnap = sim.Snapshot; Assert.Single(beforeSnap.Pieces); Assert.Equal(3 - 1, beforeSnap.RemainingStock[PieceKind.Rook]); // Mutate: place another piece, step simulation sim.Place(PieceKind.Rook, (0, 1), (1, 1)); sim.Step(); sim.Step(); var dirtySnap = sim.Snapshot; Assert.Equal(2, dirtySnap.Pieces.Count); Assert.Equal(2, dirtySnap.TurnNumber); // Load: should match beforeSnap sim.Sim.QuickLoad(); var afterSnap = sim.Snapshot; Assert.Single(afterSnap.Pieces); Assert.Equal(0, afterSnap.TurnNumber); Assert.Equal(3 - 1, afterSnap.RemainingStock[PieceKind.Rook]); Assert.Equal(beforeSnap.Pieces[0].Id, afterSnap.Pieces[0].Id); Assert.Equal(beforeSnap.Pieces[0].StartCell, afterSnap.Pieces[0].StartCell); } [Fact] public void Load_IsIndependent_FromFurtherChanges() { // Saving should not alias; mutating state after save must not affect the save. var sim = CreateSim(); sim.Place(PieceKind.Rook, (0, 0), (1, 0)); sim.Sim.QuickSave(); // Mutate after save sim.Place(PieceKind.Rook, (0, 1), (1, 1)); sim.Step(); // Load should restore to 1 piece, turn 0 sim.Sim.QuickLoad(); var snap = sim.Snapshot; Assert.Single(snap.Pieces); Assert.Equal(0, snap.TurnNumber); // Mutate again, load again — save still usable sim.Place(PieceKind.Rook, (0, 2), (1, 2)); sim.Sim.QuickLoad(); snap = sim.Snapshot; Assert.Single(snap.Pieces); } [Fact] public void QuickSave_PreservesCampaignProgression() { var campaign = CampaignBuilder(); var sim = SimHelper.FromCampaign(campaign); sim.Sim.ProcessCommand(new LoadCampaignCommand()); sim.Place(PieceKind.Pawn, (0, 0), (1, 0)); sim.Sim.QuickSave(); var before = sim.Snapshot; Assert.Equal(0, before.Campaign!.CurrentMissionIndex); // Mutate sim.Step(); sim.Step(); sim.Sim.QuickLoad(); var after = sim.Snapshot; Assert.Equal(before.Campaign!.CurrentMissionIndex, after.Campaign!.CurrentMissionIndex); Assert.Equal(before.Pieces.Count, after.Pieces.Count); Assert.Equal(0, after.TurnNumber); } [Fact] public void MultipleSlots_AreIndependent() { var sim = CreateSim(); sim.Place(PieceKind.Rook, (0, 0), (1, 0)); sim.Sim.QuickSave(slot: 1); sim.Place(PieceKind.Rook, (0, 1), (1, 1)); sim.Sim.QuickSave(slot: 2); // Slot 1 should have 1 piece; slot 2 should have 2 sim.Sim.QuickLoad(slot: 1); Assert.Single(sim.Snapshot.Pieces); sim.Sim.QuickLoad(slot: 2); Assert.Equal(2, sim.Snapshot.Pieces.Count); } private static CampaignDef CampaignBuilder() { return new CampaignDef { Name = "TestCampaign", InitialWidth = 4, InitialHeight = 4, Missions = new List { new() { Id = 1, Name = "M1", TerrainPatch = new TerrainPatch { NewWidth = 4, NewHeight = 4, Cells = new List { new() { Col = 0, Row = 0, Type = CellType.Production, Production = new ProductionDef(new Coords(0, 0), "S", CargoType.Wood, 1) }, new() { Col = 3, Row = 0, Type = CellType.Demand, Demand = new DemandDef(new Coords(3, 0), "D", CargoType.Wood, 3) } } }, UnlockedPieces = new List { PieceKind.Pawn }, UnlockedLevels = new List { new(PieceKind.Pawn, 1) }, Stock = new List { new(PieceKind.Pawn, 4) } } } }; } }