using NUnit.Framework; using FluentAssertions; using Encompass; using System; using System.Linq; using System.Collections.Generic; namespace Tests { public class EngineTest { static List> resultComponents; static MockComponent resultComponent; static List resultMessages; public class ReadComponentsTestEngine : Engine { public override void Update(float dt) { resultComponents = this.ReadComponents().ToList(); } } public class ReadComponentTestEngine : Engine { public override void Update(float dt) { resultComponent = this.ReadComponent().Value; } } [Test] public void ReadComponents() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; mockComponent.myInt = 0; mockComponent.myString = "hello"; MockComponent mockComponentB; mockComponentB.myInt = 1; mockComponentB.myString = "howdy"; var componentAID = entity.AddComponent(mockComponent); var componentBID = entity.AddComponent(mockComponentB); var world = worldBuilder.Build(); world.Update(0.01f); var resultComponentValues = resultComponents.Select((kv) => kv.Value); resultComponentValues.Should().Contain(mockComponent); resultComponentValues.Should().Contain(mockComponentB); } [Test] public void ReadComponent() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; mockComponent.myInt = 0; mockComponent.myString = "hello"; entity.AddComponent(mockComponent); var world = worldBuilder.Build(); world.Update(0.01f); Assert.AreEqual(mockComponent, resultComponent); } [Test] public void ReadComponentWhenMultipleComponents() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; mockComponent.myInt = 0; mockComponent.myString = "hello"; MockComponent mockComponentB; mockComponentB.myInt = 1; mockComponentB.myString = "howdy"; entity.AddComponent(mockComponent); entity.AddComponent(mockComponentB); var world = worldBuilder.Build(); Assert.Throws(() => world.Update(0.01f)); } [Mutates(typeof(MockComponent))] public class UpdateComponentTestEngine : Engine { public override void Update(float dt) { (var componentID, var component) = this.ReadComponent(); component.myInt = 420; component.myString = "blaze it"; this.UpdateComponent(componentID, component); resultComponent = this.ReadComponent().Value; } } [Test] public void UpdateComponent() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; mockComponent.myInt = 0; mockComponent.myString = "hello"; entity.AddComponent(mockComponent); var world = worldBuilder.Build(); world.Update(0.01f); Assert.AreEqual(420, resultComponent.myInt); Assert.AreEqual("blaze it", resultComponent.myString); } public class UndeclaredUpdateComponentTestEngine : Engine { public override void Update(float dt) { (var componentID, var component) = this.ReadComponent(); component.myInt = 420; component.myString = "blaze it"; this.UpdateComponent(componentID, component); component = this.ReadComponent().Value; } } [Test] public void UpdateUndeclaredComponent() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; mockComponent.myInt = 0; mockComponent.myString = "hello"; entity.AddComponent(mockComponent); var world = worldBuilder.Build(); var ex = Assert.Throws(() => world.Update(0.01f)); Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to mutate undeclared Component MockComponent")); } struct MockMessage : IMessage { public string myString; } [Emits(typeof(MockMessage))] public class MessageEmitEngine : Engine { public override void Update(float dt) { MockMessage message; message.myString = "howdy"; this.EmitMessage(message); } } [Reads(typeof(MockMessage))] public class MessageReadEngine : Engine { public override void Update(float dt) { resultMessages = this.ReadMessages().ToList(); } } [Test] public void EmitAndReadMessage() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); worldBuilder.AddEngine(); var world = worldBuilder.Build(); world.Update(0.01f); Assert.AreEqual(resultMessages.First().myString, "howdy"); } public class UndeclaredMessageEmitEngine : Engine { public override void Update(float dt) { MockMessage message; message.myString = "howdy"; this.EmitMessage(message); } } static IEnumerable emptyReadMessagesResult; [Reads(typeof(MockMessage))] class ReadMessagesWhenNoneExistEngine : Engine { public override void Update(float dt) { emptyReadMessagesResult = ReadMessages(); } } [Test] public void ReadMessagesWhenNoneHaveBeenEmitted() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); var world = worldBuilder.Build(); world.Update(0.01f); emptyReadMessagesResult.Should().BeEmpty(); } [Test] public void EmitUndeclaredMessage() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); var world = worldBuilder.Build(); var ex = Assert.Throws(() => world.Update(0.01f)); Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredMessageEmitEngine tried to emit undeclared Message MockMessage")); } static bool someTest; [Emits(typeof(MockMessage))] class EmitMockMessageEngine : Engine { public override void Update(float dt) { MockMessage message; message.myString = "howdy"; this.EmitMessage(message); } } [Reads(typeof(MockMessage))] class SomeTestEngine : Engine { public override void Update(float dt) { someTest = this.Some(); } } [Test] public void Some() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); worldBuilder.AddEngine(); var world = worldBuilder.Build(); world.Update(0.01f); Assert.That(someTest, Is.True); } class UndeclaredSomeEngine : Engine { public override void Update(float dt) { someTest = this.Some(); } } [Test] public void IllegalSome() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); worldBuilder.AddEngine(); var world = worldBuilder.Build(); Assert.Throws(() => world.Update(0.01f)); } static KeyValuePair pairA; static KeyValuePair pairB; class SameValueComponentReadEngine : Engine { public override void Update(float dt) { var components = this.ReadComponents(); pairA = components.First(); pairB = components.Last(); } } // Tests that components with identical values should be distinguishable by ID [Test] public void SameValueComponents() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); MockComponent componentA; componentA.myInt = 20; componentA.myString = "hello"; MockComponent componentB; componentB.myInt = 20; componentB.myString = "hello"; var entity = worldBuilder.CreateEntity(); entity.AddComponent(componentA); entity.AddComponent(componentB); var world = worldBuilder.Build(); world.Update(0.01f); Assert.That(pairA, Is.Not.EqualTo(pairB)); Assert.That(pairA.Value, Is.EqualTo(pairB.Value)); } static IEnumerable> emptyComponentReadResult; class ReadEmptyMockComponentsEngine : Engine { public override void Update(float dt) { emptyComponentReadResult = this.ReadComponents(); } } [Test] public void ReadComponentsOfTypeWhereNoneExist() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); var world = worldBuilder.Build(); world.Update(0.01f); Assert.That(emptyComponentReadResult, Is.Empty); } struct DestroyerComponent : IComponent { } class DestroyerEngine : Engine { public override void Update(float dt) { var componentPairs = ReadComponents(); foreach (var componentPair in componentPairs) { var componentID = componentPair.Key; var entityID = GetEntityIDByComponentID(componentID); Destroy(entityID); } } } static IEnumerable> results; class ReaderEngine : Engine { public override void Update(float dt) { results = ReadComponents(); } } [Test] public void DestroyEntity() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); worldBuilder.AddEngine(); var entity = worldBuilder.CreateEntity(); var entityB = worldBuilder.CreateEntity(); DestroyerComponent destroyerComponent; MockComponent mockComponent; mockComponent.myInt = 2; mockComponent.myString = "blah"; entity.AddComponent(destroyerComponent); var componentID = entity.AddComponent(mockComponent); entityB.AddComponent(destroyerComponent); var componentBID = entityB.AddComponent(mockComponent); var world = worldBuilder.Build(); world.Update(0.01f); Assert.That(results, Does.Not.Contain(new KeyValuePair(componentID, mockComponent))); Assert.That(results, Does.Not.Contain(new KeyValuePair(componentBID, mockComponent))); } static Entity entityFromComponentIDResult; class GetEntityFromComponentIDEngine : Engine { public override void Update(float dt) { var componentID = ReadComponent().Key; entityFromComponentIDResult = GetEntityByComponentID(componentID); } } [Test] public void GetEntityFromComponentID() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); MockComponent component; component.myInt = 2; component.myString = "howdy"; var entity = worldBuilder.CreateEntity(); entity.AddComponent(component); var world = worldBuilder.Build(); world.Update(0.01f); Assert.That(entity, Is.EqualTo(entityFromComponentIDResult)); } static MockComponent mockComponentByIDResult; class GetComponentByIDEngine : Engine { public override void Update(float dt) { var componentID = ReadComponent().Key; mockComponentByIDResult = GetComponentByID(componentID); } } [Test] public void GetComponentByID() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); MockComponent component; component.myInt = 2; component.myString = "howdy"; var entity = worldBuilder.CreateEntity(); entity.AddComponent(component); var world = worldBuilder.Build(); world.Update(0.01f); Assert.That(component, Is.EqualTo(mockComponentByIDResult)); } struct OtherComponent : IComponent { } class GetComponentByIDWithTypeMismatchEngine : Engine { public override void Update(float dt) { var componentID = ReadComponent().Key; GetComponentByID(componentID); } } [Test] public void GetComponentByIDWithTypeMismatch() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(); MockComponent component; component.myInt = 2; component.myString = "howdy"; var entity = worldBuilder.CreateEntity(); entity.AddComponent(component); var world = worldBuilder.Build(); Assert.Throws(() => world.Update(0.01f)); } } }