Show More
Commit Description:
Tidy code.
Commit Description:
Tidy code.
References:
File last commit:
Show/Diff file:
Action:
encompass-cs/test/WorldBuilderTest.cs
614 lines | 18.0 KiB | text/x-csharp | CSharpLexer
614 lines | 18.0 KiB | text/x-csharp | CSharpLexer
r169 | using NUnit.Framework; | |||
using Encompass; | ||||
using System.Collections.Generic; | ||||
using Encompass.Exceptions; | ||||
using System.Linq; | ||||
using FluentAssertions; | ||||
using System; | ||||
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<EngineCycleException>(() => 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<EngineCycleException>(() => worldBuilder.Build()); | ||||
} | ||||
} | ||||
public class MultipleEngineWriteConflict | ||||
{ | ||||
struct AComponent { } | ||||
[Writes(typeof(AComponent))] | ||||
class AEngine : Engine | ||||
{ | ||||
public override void Update(double dt) { } | ||||
} | ||||
[Writes(typeof(AComponent))] | ||||
class BEngine : Engine | ||||
{ | ||||
public override void Update(double dt) { } | ||||
} | ||||
[Test] | ||||
public void EngineWriteConflictException() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
worldBuilder.AddEngine(new AEngine()); | ||||
worldBuilder.AddEngine(new BEngine()); | ||||
Assert.Throws<EngineWriteConflictException>(() => worldBuilder.Build()); | ||||
} | ||||
} | ||||
public class MultipleEngineWriteWithPriority | ||||
{ | ||||
struct SetMessage : IMessage | ||||
{ | ||||
public Entity entity; | ||||
} | ||||
struct AComponent : IComponent | ||||
{ | ||||
public int myInt; | ||||
} | ||||
[Receives(typeof(SetMessage))] | ||||
[Writes(typeof(AComponent), 0)] | ||||
[WritesImmediate(typeof(AComponent))] | ||||
class AEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
foreach (ref readonly var setMessage in ReadMessages<SetMessage>()) | ||||
{ | ||||
SetComponent(setMessage.entity, new AComponent { myInt = 0 }); | ||||
} | ||||
} | ||||
} | ||||
[Receives(typeof(SetMessage))] | ||||
[Writes(typeof(AComponent), 1)] | ||||
[WritesImmediate(typeof(AComponent))] | ||||
class BEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
foreach (ref readonly var setMessage in ReadMessages<SetMessage>()) | ||||
{ | ||||
SetComponent(setMessage.entity, new AComponent { myInt = 1 }); | ||||
} | ||||
} | ||||
} | ||||
static AComponent resultComponent; | ||||
[ReadsImmediate(typeof(AComponent))] | ||||
class ReadComponentEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
resultComponent = ReadComponent<AComponent>(); | ||||
} | ||||
} | ||||
[Test] | ||||
public void LowerPriorityWrites() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
worldBuilder.AddEngine(new AEngine()); | ||||
worldBuilder.AddEngine(new BEngine()); | ||||
var entity = worldBuilder.CreateEntity(); | ||||
worldBuilder.SendMessage(new SetMessage { entity = entity }); | ||||
var world = worldBuilder.Build(); | ||||
world.Update(0.01); | ||||
Assert.That(resultComponent.myInt, Is.EqualTo(0)); | ||||
} | ||||
} | ||||
public class DefaultWritePriority | ||||
{ | ||||
struct SetMessage : IMessage | ||||
{ | ||||
public Entity entity; | ||||
} | ||||
struct AComponent : IComponent | ||||
{ | ||||
public int myInt; | ||||
} | ||||
[Receives(typeof(SetMessage))] | ||||
[Writes(typeof(AComponent))] | ||||
[WritesImmediate(typeof(AComponent))] | ||||
[Encompass.DefaultWritePriority(4)] | ||||
class AEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
foreach (ref readonly var setMessage in ReadMessages<SetMessage>()) | ||||
{ | ||||
SetComponent(setMessage.entity, new AComponent { myInt = 5 }); | ||||
} | ||||
} | ||||
} | ||||
[Receives(typeof(SetMessage))] | ||||
[Writes(typeof(AComponent), 3)] | ||||
[WritesImmediate(typeof(AComponent))] | ||||
class BEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
foreach (ref readonly var setMessage in ReadMessages<SetMessage>()) | ||||
{ | ||||
SetComponent(setMessage.entity, new AComponent { myInt = 1 }); | ||||
} | ||||
} | ||||
} | ||||
[Receives(typeof(SetMessage))] | ||||
[Writes(typeof(AComponent), 2)] | ||||
[WritesImmediate(typeof(AComponent))] | ||||
class CEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
foreach (ref readonly var setMessage in ReadMessages<SetMessage>()) | ||||
{ | ||||
SetComponent(setMessage.entity, new AComponent { myInt = 3 }); | ||||
} | ||||
} | ||||
} | ||||
static AComponent resultComponent; | ||||
[ReadsImmediate(typeof(AComponent))] | ||||
class ReadComponentEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
resultComponent = ReadComponent<AComponent>(); | ||||
} | ||||
} | ||||
[Test] | ||||
public void LowerPriorityWrites() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
worldBuilder.AddEngine(new AEngine()); | ||||
worldBuilder.AddEngine(new BEngine()); | ||||
worldBuilder.AddEngine(new CEngine()); | ||||
worldBuilder.AddEngine(new ReadComponentEngine()); | ||||
var entity = worldBuilder.CreateEntity(); | ||||
worldBuilder.SendMessage(new SetMessage { entity = entity }); | ||||
var world = worldBuilder.Build(); | ||||
world.Update(0.01); | ||||
Assert.That(resultComponent.myInt, Is.EqualTo(3)); | ||||
} | ||||
} | ||||
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<EngineSelfCycleException>(() => worldBuilder.AddEngine(new AEngine()), "Engine both sends and receives Message AMessage"); | ||||
} | ||||
} | ||||
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<IllegalSendTypeException>(() => worldBuilder.AddEngine(new MyEngine()), "ANonMessage must be a Message or Component"); | ||||
} | ||||
} | ||||
public class PriorityConflict | ||||
{ | ||||
[Writes(typeof(MockComponent), 2)] | ||||
class AEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
} | ||||
} | ||||
[Writes(typeof(MockComponent), 2)] | ||||
class BEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
} | ||||
} | ||||
[Test] | ||||
public void PriorityConflictTest() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
worldBuilder.AddEngine(new AEngine()); | ||||
worldBuilder.AddEngine(new BEngine()); | ||||
Assert.Throws<EngineWriteConflictException>(() => worldBuilder.Build()); | ||||
} | ||||
} | ||||
public class EngineWriteConflict | ||||
{ | ||||
[Writes(typeof(MockComponent))] | ||||
class AEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
} | ||||
} | ||||
[Writes(typeof(MockComponent), 2)] | ||||
class BEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
} | ||||
} | ||||
[Test] | ||||
public void EngineWriteConflictPriorityAndNoPriorityTest() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
worldBuilder.AddEngine(new AEngine()); | ||||
worldBuilder.AddEngine(new BEngine()); | ||||
Assert.Throws<EngineWriteConflictException>(() => worldBuilder.Build()); | ||||
} | ||||
} | ||||
public class LegalEngines | ||||
{ | ||||
static List<Engine> order = new List<Engine>(); | ||||
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(); | ||||
worldBuilder.AddEngine(new AEngine()); | ||||
worldBuilder.AddEngine(new BEngine()); | ||||
worldBuilder.AddEngine(new CEngine()); | ||||
worldBuilder.AddEngine(new DEngine()); | ||||
Assert.DoesNotThrow(() => worldBuilder.Build()); | ||||
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()); | ||||
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 AMessage[] resultMessages; | ||||
[Receives(typeof(AMessage))] | ||||
class ReadMessageEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
resultMessages = ReadMessages<AMessage>().ToArray(); | ||||
} | ||||
} | ||||
[Test] | ||||
public void SendMessageDelayed() | ||||
{ | ||||
resultMessages = Array.Empty<AMessage>(); | ||||
var worldBuilder = new WorldBuilder(); | ||||
worldBuilder.AddEngine(new ReadMessageEngine()); | ||||
worldBuilder.SendMessage(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<AMessage>(); | ||||
} | ||||
} | ||||
public class MultipleMessagesBetweenEngines | ||||
{ | ||||
static List<Engine> order = new List<Engine>(); | ||||
struct AMessage : IMessage { } | ||||
struct BMessage : IMessage { } | ||||
[Sends(typeof(AMessage), typeof(BMessage))] | ||||
class AEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
order.Add(this); | ||||
} | ||||
} | ||||
[Receives(typeof(AMessage), typeof(BMessage))] | ||||
class BEngine : Engine | ||||
{ | ||||
public override void Update(double dt) | ||||
{ | ||||
order.Add(this); | ||||
} | ||||
} | ||||
[Test] | ||||
public void WorldBuilderDoesNotThrowError() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
var engineA = worldBuilder.AddEngine(new AEngine()); | ||||
var engineB = worldBuilder.AddEngine(new BEngine()); | ||||
Assert.DoesNotThrow(() => worldBuilder.Build()); | ||||
var world = worldBuilder.Build(); | ||||
world.Update(0.01f); | ||||
Assert.That(order.IndexOf(engineA), Is.LessThan(order.IndexOf(engineB))); | ||||
} | ||||
} | ||||
public class DrawLayerRegister | ||||
{ | ||||
struct AComponent : IComponent, IDrawableComponent | ||||
{ | ||||
public int Layer { get; } | ||||
} | ||||
struct BComponent : IComponent, IDrawableComponent | ||||
{ | ||||
public int Layer { get => 3; } | ||||
} | ||||
class ARenderer : OrderedRenderer<AComponent> | ||||
{ | ||||
public override void Render(Entity entity, in AComponent drawComponent) { } | ||||
} | ||||
class BRenderer : OrderedRenderer<BComponent> | ||||
{ | ||||
public override void Render(Entity entity, in BComponent drawComponent) { } | ||||
} | ||||
[Test] | ||||
public void DrawLayerRegisterAfterOrderedRendererRegisterThrows() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
var rendererA = worldBuilder.AddOrderedRenderer(new ARenderer()); | ||||
Assert.Throws<IllegalDrawLayerException>(() => worldBuilder.RegisterDrawLayer(1)); | ||||
} | ||||
[Test] | ||||
public void DrawLayerRegisterBeforeOrderedRendererDoesNotThrow() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
Assert.DoesNotThrow(() => worldBuilder.RegisterDrawLayer(1)); | ||||
Assert.DoesNotThrow(() => worldBuilder.AddOrderedRenderer(new ARenderer())); | ||||
} | ||||
[Test] | ||||
public void DrawLayerWithProperty() | ||||
{ | ||||
var worldBuilder = new WorldBuilder(); | ||||
var rendererB = worldBuilder.AddOrderedRenderer(new BRenderer()); | ||||
Assert.DoesNotThrow(() => worldBuilder.Build()); | ||||
} | ||||
} | ||||
} | ||||
} | ||||