Show More
Commit Description:
Add timers for Simulation and various engines...
Commit Description:
Add timers for Simulation and various engines Starting to add additional timers for different stages of the process of updating in order to get more insight into what is slowing it down. The update takes 9ms, which is much longer than it used to. Engine-specific timers are coming later.
Show/Diff file:
Action:
encompass-cs/test/WorldBuilderTest.cs
614 lines | 18.0 KiB | text/x-csharp | CSharpLexer
Initial version of encompass addition (not fully working)....
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());
}
}
}
}