diff --git a/OECS.Tests/ReactivityTests.cs b/OECS.Tests/ReactivityTests.cs index c6dd7c3..9c2c926 100644 --- a/OECS.Tests/ReactivityTests.cs +++ b/OECS.Tests/ReactivityTests.cs @@ -9,6 +9,8 @@ public class ReactivityTests private struct Position { public float X; public float Y; } private struct Health { public int Value; } private struct Frozen { } + private struct ChildOf { } + private struct ParentOf { } /// /// Helper that collects changes into a list and exposes an R3 Observer. @@ -264,6 +266,31 @@ public class ReactivityTests collector.Changes.Should().Contain(c => c.Kind == ChangeKind.EntityAdded); } + [Fact] + public void ReorderSources_PostsRelationshipReordered() + { + var world = new World(); + var parent = world.CreateEntity(); + var a = world.CreateEntity(); + var b = world.CreateEntity(); + + world.AddComponent(a, new Relationship { Target = parent }); + world.AddComponent(b, new Relationship { Target = parent }); + world.PostChanges(); // Clear pending + + var collector = new ChangeCollector(); + using var sub = world.ObserveEntityChanges().Subscribe(collector.ToObserver()); + + world.ReorderSources>(parent, [b, a]); + world.PostChanges(); + + collector.Changes.Should().ContainSingle() + .Which.Should().Match(c => + c.Entity == parent && + c.Kind == ChangeKind.RelationshipReordered && + c.ComponentType == typeof(Relationship)); + } + private class EntityCreatorSystem : ISystem { private readonly World _world; diff --git a/OECS.Tests/RelationshipTests.cs b/OECS.Tests/RelationshipTests.cs index 70f1669..037b8c0 100644 --- a/OECS.Tests/RelationshipTests.cs +++ b/OECS.Tests/RelationshipTests.cs @@ -197,6 +197,80 @@ public class RelationshipTests results.Should().BeEquivalentTo([child]); } + [Fact] + public void GetSources_PreservesInsertionOrder() + { + var world = new World(); + var parent = world.CreateEntity(); + + // Add sources in a specific order. + var sources = new Entity[5]; + for (int i = 0; i < 5; i++) + { + sources[i] = world.CreateEntity(); + world.AddComponent(sources[i], new Relationship + { + Target = parent + }); + } + + var result = world.GetSources>(parent); + result.Should().Equal(sources); + } + + [Fact] + public void GetSources_OrderIsStableAfterMiddleRemove() + { + var world = new World(); + var parent = world.CreateEntity(); + + var a = world.CreateEntity(); + var b = world.CreateEntity(); + var c = world.CreateEntity(); + + world.AddComponent(a, new Relationship { Target = parent }); + world.AddComponent(b, new Relationship { Target = parent }); + world.AddComponent(c, new Relationship { Target = parent }); + + // Remove the middle source. + world.RemoveComponent>(b); + + // Remaining sources should preserve insertion order. + var result = world.GetSources>(parent); + result.Should().Equal([a, c]); + } + + [Fact] + public void ReorderSources_ChangesIterationOrder() + { + var world = new World(); + var parent = world.CreateEntity(); + + var a = world.CreateEntity(); + var b = world.CreateEntity(); + var c = world.CreateEntity(); + + world.AddComponent(a, new Relationship { Target = parent }); + world.AddComponent(b, new Relationship { Target = parent }); + world.AddComponent(c, new Relationship { Target = parent }); + + // Reverse the order. + world.ReorderSources>(parent, [c, b, a]); + + var result = world.GetSources>(parent); + result.Should().Equal([c, b, a]); + } + + [Fact] + public void ReorderSources_NoopsWhenTargetHasNoRelationships() + { + var world = new World(); + var entity = world.CreateEntity(); + + // Should not throw. + world.ReorderSources>(entity, []); + } + [Fact] public void DestroyEntity_WithBothIncomingAndOutgoingRelationships() {