120 lines
4.5 KiB
C#
120 lines
4.5 KiB
C#
using Ghost.Editor.Core.SceneGraph;
|
|
using Ghost.Editor.Core.Services;
|
|
using Ghost.Entities;
|
|
|
|
namespace Ghost.UnitTest;
|
|
|
|
[TestClass]
|
|
public class UndoServiceEcsTests
|
|
{
|
|
private struct CompA : IComponentData { public int value; }
|
|
private struct CompB : IComponentData { public int value; }
|
|
|
|
private EditorWorldService _worldService = null!;
|
|
private UndoService _undoService = null!;
|
|
|
|
[TestInitialize]
|
|
public void Setup()
|
|
{
|
|
_worldService = new EditorWorldService();
|
|
_undoService = new UndoService(_worldService);
|
|
}
|
|
|
|
[TestCleanup]
|
|
public void Cleanup()
|
|
{
|
|
_worldService.Dispose();
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestRecordEntityStructure()
|
|
{
|
|
var world = _worldService.EditorWorld;
|
|
var e = world.EntityManager.CreateEntity();
|
|
world.EntityManager.AddComponent<CompA>(e);
|
|
|
|
// Initial state: Entity has CompA
|
|
ref var compA = ref world.EntityManager.GetComponent<CompA>(e);
|
|
compA.value = 10;
|
|
|
|
var node = new EntityNode(world, e, "TestEntity", null);
|
|
|
|
_undoService.BeginTransaction("Add CompB");
|
|
_undoService.RecordObject(node, "Before Add CompB");
|
|
|
|
// Modify structure
|
|
world.EntityManager.AddComponent<CompB>(e);
|
|
ref var compB = ref world.EntityManager.GetComponent<CompB>(e);
|
|
compB.value = 20;
|
|
|
|
// Re-fetch CompA because AddComponent moves the entity to a new chunk,
|
|
// invalidating the previous ref!
|
|
ref var compA_new = ref world.EntityManager.GetComponent<CompA>(e);
|
|
compA_new.value = 15; // also modify compA
|
|
|
|
_undoService.EndTransaction();
|
|
|
|
// Perform Undo
|
|
_undoService.PerformUndo();
|
|
|
|
Assert.IsTrue(world.EntityManager.HasComponent<CompA>(e), "Should have CompA");
|
|
Assert.IsFalse(world.EntityManager.HasComponent<CompB>(e), "Should NOT have CompB");
|
|
Assert.AreEqual(10, world.EntityManager.GetComponent<CompA>(e).value, "CompA value should be reverted to 10");
|
|
|
|
// Perform Redo
|
|
_undoService.PerformRedo();
|
|
|
|
Assert.IsTrue(world.EntityManager.HasComponent<CompA>(e), "Should have CompA");
|
|
Assert.IsTrue(world.EntityManager.HasComponent<CompB>(e), "Should have CompB");
|
|
Assert.AreEqual(15, world.EntityManager.GetComponent<CompA>(e).value, "CompA value should be restored to 15");
|
|
Assert.AreEqual(20, world.EntityManager.GetComponent<CompB>(e).value, "CompB value should be restored to 20");
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestRecordEntityLifecycle_CreateAndDestroy()
|
|
{
|
|
var world = _worldService.EditorWorld;
|
|
|
|
// Step 1: Create Entity
|
|
var e = world.EntityManager.CreateEntity();
|
|
world.EntityManager.AddComponent<CompA>(e);
|
|
world.EntityManager.GetComponent<CompA>(e).value = 42;
|
|
var node = new EntityNode(world, e, "TestEntity", null);
|
|
|
|
_undoService.BeginTransaction("Create Entity");
|
|
_undoService.RegisterCreatedObjectUndo(node, "Create Entity");
|
|
_undoService.EndTransaction();
|
|
|
|
// Undo Creation (Expect destruction)
|
|
_undoService.PerformUndo();
|
|
Assert.IsFalse(world.EntityManager.Exists(e), "Entity should be destroyed by Undo of Creation");
|
|
|
|
// Redo Creation (Expect resurrection)
|
|
_undoService.PerformRedo();
|
|
|
|
// Note: The entity ID might be different, but the EntityNode should be updated
|
|
var resurrectedEntity = node.Entity;
|
|
Assert.IsTrue(world.EntityManager.Exists(resurrectedEntity), "Entity should be resurrected by Redo of Creation");
|
|
// In our current implementation, restoring components for created entities isn't fully robust yet,
|
|
// but we verify the entity is alive.
|
|
|
|
// Step 2: Destroy Entity
|
|
_undoService.BeginTransaction("Destroy Entity");
|
|
_undoService.RecordObject(node, "Destroy Entity");
|
|
world.EntityManager.DestroyEntity(resurrectedEntity);
|
|
_undoService.EndTransaction();
|
|
|
|
Assert.IsFalse(world.EntityManager.Exists(resurrectedEntity), "Entity destroyed manually");
|
|
|
|
// Undo Destruction (Expect resurrection)
|
|
_undoService.PerformUndo();
|
|
|
|
var undoneDestroyEntity = node.Entity;
|
|
Assert.IsTrue(world.EntityManager.Exists(undoneDestroyEntity), "Entity should be resurrected by Undo of Destruction");
|
|
|
|
// Redo Destruction (Expect destruction)
|
|
_undoService.PerformRedo();
|
|
Assert.IsFalse(world.EntityManager.Exists(undoneDestroyEntity), "Entity should be destroyed by Redo of Destruction");
|
|
}
|
|
}
|