155 lines
4.2 KiB
C#
155 lines
4.2 KiB
C#
namespace HSchool.Simulation.Tests;
|
|
|
|
public class GameClockTests
|
|
{
|
|
private static readonly DateTime Start = new(2012, 4, 3, 6, 0, 0, DateTimeKind.Utc);
|
|
|
|
private const double OneTwentiethOfASecond = 1d / 20d;
|
|
private const double GameMinutesPerRealSecond = 1d;
|
|
|
|
[Fact]
|
|
public void NewClock_StartsRunningAtTheStartDate()
|
|
{
|
|
var clock = new GameClock(Start);
|
|
|
|
Assert.Equal(Start, clock.Time);
|
|
Assert.True(clock.IsRunning);
|
|
Assert.Equal(ClockSpeed.DefaultIndex, clock.SpeedIndex);
|
|
Assert.Equal(1d, clock.Multiplier);
|
|
}
|
|
|
|
[Fact]
|
|
public void PausedClock_DoesNotMove()
|
|
{
|
|
var clock = new GameClock(Start) { IsRunning = false };
|
|
|
|
for (var i = 0; i < 100; i++)
|
|
{
|
|
clock.Advance(OneTwentiethOfASecond, GameMinutesPerRealSecond);
|
|
}
|
|
|
|
Assert.Equal(Start, clock.Time);
|
|
}
|
|
|
|
[Fact]
|
|
public void OneRealSecond_AdvancesOneGameMinute()
|
|
{
|
|
var clock = new GameClock(Start);
|
|
|
|
// One real second at 20 Hz.
|
|
for (var i = 0; i < 20; i++)
|
|
{
|
|
clock.Advance(OneTwentiethOfASecond, GameMinutesPerRealSecond);
|
|
}
|
|
|
|
Assert.Equal(Start.AddMinutes(1), clock.Time);
|
|
}
|
|
|
|
[Fact]
|
|
public void TwentyStepsAtX1_AdvanceOneGameMinuteNotFive()
|
|
{
|
|
var clock = new GameClock(Start) { SpeedIndex = 1 };
|
|
|
|
for (var i = 0; i < 20; i++)
|
|
{
|
|
clock.Advance(OneTwentiethOfASecond, GameMinutesPerRealSecond);
|
|
}
|
|
|
|
Assert.Equal(Start.AddMinutes(1), clock.Time);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0, 0.5)]
|
|
[InlineData(1, 1)]
|
|
[InlineData(2, 2)]
|
|
[InlineData(3, 5)]
|
|
[InlineData(4, 10)]
|
|
public void SpeedIndex_ScalesTheGameMinutesPerSecond(int speedIndex, double expectedMinutes)
|
|
{
|
|
var clock = new GameClock(Start) { SpeedIndex = speedIndex };
|
|
|
|
for (var i = 0; i < 20; i++)
|
|
{
|
|
clock.Advance(OneTwentiethOfASecond, GameMinutesPerRealSecond);
|
|
}
|
|
|
|
Assert.Equal(Start.AddMinutes(expectedMinutes), clock.Time);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(-1)]
|
|
[InlineData(5)]
|
|
[InlineData(200)]
|
|
public void InvalidSpeedIndex_IsIgnored(int speedIndex)
|
|
{
|
|
var clock = new GameClock(Start) { SpeedIndex = 2 };
|
|
|
|
clock.SpeedIndex = speedIndex;
|
|
|
|
Assert.Equal(2, clock.SpeedIndex);
|
|
}
|
|
|
|
[Fact]
|
|
public void Pausing_FreezesTimeWhereItStopped()
|
|
{
|
|
var clock = new GameClock(Start);
|
|
for (var i = 0; i < 20; i++)
|
|
{
|
|
clock.Advance(OneTwentiethOfASecond, GameMinutesPerRealSecond);
|
|
}
|
|
|
|
var paused = clock.Time;
|
|
clock.IsRunning = false;
|
|
for (var i = 0; i < 100; i++)
|
|
{
|
|
clock.Advance(OneTwentiethOfASecond, GameMinutesPerRealSecond);
|
|
}
|
|
|
|
Assert.Equal(paused, clock.Time);
|
|
}
|
|
|
|
[Fact]
|
|
public void SameTickCount_AlwaysProducesTheSameDate()
|
|
{
|
|
Assert.Equal(RunOneHourOfTicks(), RunOneHourOfTicks());
|
|
|
|
static DateTime RunOneHourOfTicks()
|
|
{
|
|
var clock = new GameClock(Start) { SpeedIndex = 0 };
|
|
for (var i = 0; i < 20 * 60 * 60; i++)
|
|
{
|
|
clock.Advance(OneTwentiethOfASecond, GameMinutesPerRealSecond);
|
|
}
|
|
|
|
return clock.Time;
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Time_IsUtcSoSerializationIsUnambiguous()
|
|
{
|
|
var clock = new GameClock(new DateTime(2012, 4, 3, 6, 0, 0, DateTimeKind.Unspecified));
|
|
|
|
Assert.Equal(DateTimeKind.Utc, clock.Time.Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void JumpTo_MovesTheCalendarWithoutTicking()
|
|
{
|
|
var clock = new GameClock(Start) { IsRunning = false };
|
|
var target = new DateTime(2012, 4, 9, 6, 0, 0, DateTimeKind.Utc);
|
|
|
|
clock.JumpTo(target);
|
|
|
|
Assert.Equal(target, clock.Time);
|
|
Assert.Equal(DateTimeKind.Utc, clock.Time.Kind);
|
|
Assert.False(clock.IsRunning);
|
|
}
|
|
|
|
[Fact]
|
|
public void StartDateOutsideTheSupportedRange_Throws()
|
|
{
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => new GameClock(new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
|
|
}
|
|
}
|