using NUnit.Framework; using Encompass; using System.Collections.Generic; using Encompass.Exceptions; using System.Linq; using FluentAssertions; namespace Tests { public class WorldBuilderTest { public class EngineCycleSimple { struct AMessage : IMessage { } struct BMessage : IMessage { } [Receives(typeof(AMessage))] [Sends(typeof(BMessage))] class AEngine : Engine { public override void Update(double dt) { BMessage message; this.SendMessage(message); } } [Receives(typeof(BMessage))] [Sends(typeof(AMessage))] class BEngine : Engine { public override void Update(double dt) { AMessage message; this.SendMessage(message); } } [Test] public void EngineCycle() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new AEngine()); worldBuilder.AddEngine(new BEngine()); Assert.Throws(() => worldBuilder.Build()); } } public class EngineCycleComplex { struct AMessage : IMessage { } struct BMessage : IMessage { } struct CMessage : IMessage { } struct DMessage : IMessage { } [Receives(typeof(AMessage))] [Sends(typeof(BMessage))] class AEngine : Engine { public override void Update(double dt) { BMessage message; this.SendMessage(message); } } [Receives(typeof(BMessage))] [Sends(typeof(CMessage))] class BEngine : Engine { public override void Update(double dt) { CMessage message; this.SendMessage(message); } } [Receives(typeof(CMessage))] [Sends(typeof(DMessage))] class CEngine : Engine { public override void Update(double dt) { DMessage message; this.SendMessage(message); } } [Receives(typeof(DMessage))] [Sends(typeof(AMessage))] class DEngine : Engine { public override void Update(double dt) { AMessage message; this.SendMessage(message); } } [Test] public void EngineCycle() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new AEngine()); worldBuilder.AddEngine(new BEngine()); worldBuilder.AddEngine(new CEngine()); worldBuilder.AddEngine(new DEngine()); Assert.Throws(() => worldBuilder.Build()); } } public class MutationConflict { struct AComponent : IComponent { } [Updates(typeof(AComponent))] class AEngine : Engine { public override void Update(double dt) { } } [Updates(typeof(AComponent))] class BEngine : Engine { public override void Update(double dt) { } } [Test] public void MutationConflictException() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new AEngine()); worldBuilder.AddEngine(new BEngine()); Assert.Throws(() => worldBuilder.Build()); } } public class EngineMessageSelfCycle { struct AMessage : IMessage { } [Receives(typeof(AMessage))] [Sends(typeof(AMessage))] class AEngine : Engine { public override void Update(double dt) { } } [Test] public void ThrowsError() { var worldBuilder = new WorldBuilder(); Assert.Throws(() => worldBuilder.AddEngine(new AEngine()), "Engine both sends and receives Message AMessage"); } } public class IllegalReadType { struct ANonMessage { } [Reads(typeof(ANonMessage))] class MyEngine : Engine { public override void Update(double dt) { } } [Test] public void ThrowsError() { var worldBuilder = new WorldBuilder(); Assert.Throws(() => worldBuilder.AddEngine(new MyEngine()), "ANonMessage must be a Message or Component"); } } public class IllegalWriteType { struct ANonMessage { } [Sends(typeof(ANonMessage))] class MyEngine : Engine { public override void Update(double dt) { } } [Test] public void ThrowsError() { var worldBuilder = new WorldBuilder(); Assert.Throws(() => worldBuilder.AddEngine(new MyEngine()), "ANonMessage must be a Message or Component"); } } public class LegalEngines { static List order = new List(); struct AComponent : IComponent { } struct BComponent : IComponent { } struct AMessage : IMessage { } struct BMessage : IMessage { } struct CMessage : IMessage { } struct DMessage : IMessage { } [Sends(typeof(AMessage))] class AEngine : Engine { public override void Update(double dt) { order.Add(this); } } [Sends(typeof(BMessage))] class BEngine : Engine { public override void Update(double dt) { order.Add(this); } } [Receives(typeof(AMessage), typeof(BMessage))] [Sends(typeof(DMessage))] class CEngine : Engine { public override void Update(double dt) { order.Add(this); } } [Receives(typeof(DMessage))] class DEngine : Engine { public override void Update(double dt) { order.Add(this); } } [Test] public void EngineOrder() { var worldBuilder = new WorldBuilder(); var engineA = worldBuilder.AddEngine(new AEngine()); var engineB = worldBuilder.AddEngine(new BEngine()); var engineC = worldBuilder.AddEngine(new CEngine()); var engineD = worldBuilder.AddEngine(new DEngine()); Assert.DoesNotThrow(() => worldBuilder.Build()); var world = worldBuilder.Build(); world.Update(0.01f); Assert.That(order.IndexOf(engineA), Is.LessThan(order.IndexOf(engineC))); Assert.That(order.IndexOf(engineB), Is.LessThan(order.IndexOf(engineC))); Assert.That(order.IndexOf(engineC), Is.LessThan(order.IndexOf(engineD))); } static List resultMessages = new List(); [Receives(typeof(AMessage))] class ReadMessageEngine : Engine { public override void Update(double dt) { resultMessages = ReadMessages().ToList(); } } [Test] public void SendMessageDelayed() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new ReadMessageEngine()); worldBuilder.SendMessageDelayed(new AMessage {}, 0.5); var world = worldBuilder.Build(); resultMessages.Should().BeEmpty(); world.Update(0.25); resultMessages.Should().BeEmpty(); world.Update(0.25); resultMessages.Should().NotBeEmpty(); resultMessages.First().Should().BeOfType(); } } } }