using NUnit.Framework; using ProjectM.Simulation; using Unity.Collections; using Unity.Entities; namespace ProjectM.Tests { /// /// Pins the room-scoped teardown contract (): destroying room i kills ONLY /// room-i entities — the other room survives (the DR-031/DR-040 cross-room-wipe regression, load-bearing for the /// ping-pong sub-slot handoff where two rooms transiently coexist), untagged entities are untouched, and each /// entity is destroyed at most once (single-visit ⇒ no double-destroy Playback throw). /// public class RoomTeardownTests { static Entity MakeRoomEntity(EntityManager em, byte room, bool asNode) { // Mimic real room content: some entities look like resource nodes, some like zone enemies — the // teardown must be type-agnostic (RoomTag is the only contract). var e = asNode ? em.CreateEntity(typeof(RoomTag), typeof(ResourceNode)) : em.CreateEntity(typeof(RoomTag), typeof(ZoneEnemyTag)); em.SetComponentData(e, new RoomTag { Room = room }); return e; } [Test] public void DestroyRoom_KillsOnlyThatRoom_SparesOtherRoomAndUntagged() { using var world = new World("RoomTeardownTest"); var em = world.EntityManager; for (int i = 0; i < 3; i++) MakeRoomEntity(em, 0, asNode: i % 2 == 0); // room 0: 3 entities for (int i = 0; i < 2; i++) MakeRoomEntity(em, 1, asNode: i % 2 == 0); // room 1: 2 entities var untagged = em.CreateEntity(typeof(ResourceNode)); // e.g. a base-field node using var roomQuery = em.CreateEntityQuery(typeof(RoomTag)); var ecb = new EntityCommandBuffer(Allocator.Temp); int destroyed = RoomTeardown.DestroyRoom(roomQuery, ecb, 0); ecb.Playback(em); ecb.Dispose(); Assert.AreEqual(3, destroyed, "exactly room-0's entities were queued"); using var remaining = em.CreateEntityQuery(typeof(RoomTag)); var tags = remaining.ToComponentDataArray(Allocator.Temp); Assert.AreEqual(2, tags.Length, "room 1 survives intact"); for (int i = 0; i < tags.Length; i++) Assert.AreEqual(1, tags[i].Room, "every survivor belongs to room 1"); tags.Dispose(); Assert.IsTrue(em.Exists(untagged), "untagged (non-room) entities are never touched"); } [Test] public void DestroyRoom_EmptyRoom_IsANoOp() { using var world = new World("RoomTeardownTest2"); var em = world.EntityManager; MakeRoomEntity(em, 1, asNode: true); using var roomQuery = em.CreateEntityQuery(typeof(RoomTag)); var ecb = new EntityCommandBuffer(Allocator.Temp); int destroyed = RoomTeardown.DestroyRoom(roomQuery, ecb, 0); // room 0 has nothing ecb.Playback(em); ecb.Dispose(); Assert.AreEqual(0, destroyed); using var remaining = em.CreateEntityQuery(typeof(RoomTag)); Assert.AreEqual(1, remaining.CalculateEntityCount(), "room 1 untouched"); } } }