177 lines
6.3 KiB
C#
177 lines
6.3 KiB
C#
namespace ReactorMaintenance.Simulation.Tests;
|
|
|
|
public sealed class SimulationEngineTests
|
|
{
|
|
[Fact]
|
|
public void FuelLeakNearPoweredGeneratorCreatesIgnitionForecast()
|
|
{
|
|
var level = LevelState.Create("Fuel leak", 6, 6)
|
|
.SetCell(new(2, 2), new() {
|
|
Kind = ECellKind.Generator,
|
|
Pipe = EPipeMedium.Fuel,
|
|
LeakRate = 4,
|
|
Pressure = 8,
|
|
Integrity = 8,
|
|
Powered = true
|
|
});
|
|
|
|
var forecasts = m_Engine.Forecast(level);
|
|
|
|
Assert.Contains(forecasts, forecast => forecast.Kind == EFailureKind.Ignition && forecast.Position == new GridPosition(2, 2) && forecast.Turns == 1);
|
|
}
|
|
|
|
[Fact]
|
|
public void CoolantLeakOnPoweredCellRaisesElectricalCharge()
|
|
{
|
|
var level = LevelState.Create("Wet cable", 6, 6)
|
|
.SetCell(new(3, 3), new() {
|
|
Pipe = EPipeMedium.Coolant,
|
|
LeakRate = 3,
|
|
Powered = true
|
|
});
|
|
|
|
var next = m_Engine.AdvanceTurn(level);
|
|
|
|
Assert.True(next.GetCell(new(3, 3)).Hazards.ElectricalCharge >= 2);
|
|
}
|
|
|
|
[Fact]
|
|
public void ActiveFireSpreadsSmokeToOpenNeighbors()
|
|
{
|
|
var level = LevelState.Create("Smoke", 6, 6)
|
|
.SetCell(new(2, 2), new() {
|
|
Hazards = new() {
|
|
Fire = true,
|
|
Smoke = 6
|
|
}
|
|
});
|
|
|
|
var next = m_Engine.AdvanceTurn(level);
|
|
|
|
Assert.True(next.GetCell(new(2, 3)).Hazards.Smoke > 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void OverpressurePredictsPipeBurst()
|
|
{
|
|
var level = LevelState.Create("Pressure", 6, 6)
|
|
.SetCell(new(1, 2), new() {
|
|
Pipe = EPipeMedium.Pressure,
|
|
Pressure = 10,
|
|
Integrity = 6
|
|
});
|
|
|
|
var forecasts = m_Engine.Forecast(level);
|
|
|
|
Assert.Contains(forecasts, forecast => forecast.Kind == EFailureKind.PipeBurst && forecast.Turns == 2);
|
|
}
|
|
|
|
[Fact]
|
|
public void ForecastCapsFutureSimulationWhenNoTerminalConditionOccurs()
|
|
{
|
|
var engine = new SimulationEngine([], [], [new StepCountingHazard()]);
|
|
var level = LevelState.Create("Stable", 6, 6);
|
|
|
|
var forecasts = engine.Forecast(level);
|
|
|
|
Assert.Equal(12, forecasts.Count);
|
|
Assert.Equal(12, forecasts.Max(forecast => forecast.Turns));
|
|
}
|
|
|
|
[Fact]
|
|
public void ForecastPredictsMeltdownFromFutureSimulation()
|
|
{
|
|
var level = LevelState.Create("Meltdown", 6, 6)
|
|
.SetCell(new(2, 2), new() {
|
|
Kind = ECellKind.Reactor,
|
|
Hazards = new() { Heat = 9 }
|
|
});
|
|
|
|
var forecasts = m_Engine.Forecast(level);
|
|
|
|
Assert.Contains(forecasts, forecast => forecast.Kind == EFailureKind.Meltdown && forecast.Turns == 1);
|
|
}
|
|
|
|
[Fact]
|
|
public void ForecastReportsAlreadyLostLevelAtCurrentTurn()
|
|
{
|
|
var level = LevelState.Create("Lost", 6, 6) with {
|
|
Global = new() {
|
|
CoreHeat = 10,
|
|
Lost = true,
|
|
Status = "CORE MELTDOWN"
|
|
}
|
|
};
|
|
|
|
var forecasts = m_Engine.Forecast(level);
|
|
|
|
Assert.Contains(forecasts, forecast => forecast.Kind == EFailureKind.Meltdown && forecast.Turns == 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void ForecastPredictsStabilityCollapseFromFutureSimulation()
|
|
{
|
|
var level = LevelState.Create("Collapse", 6, 6)
|
|
.SetCell(new(2, 2), new() {
|
|
Kind = ECellKind.Generator,
|
|
Hazards = new() { Stability = 3 }
|
|
}) with {
|
|
Global = new() { FacilityStability = 1 }
|
|
};
|
|
|
|
var forecasts = m_Engine.Forecast(level);
|
|
|
|
Assert.Contains(forecasts, forecast => forecast.Kind == EFailureKind.StabilityCollapse && forecast.Turns == 1);
|
|
}
|
|
|
|
[Fact]
|
|
public void StableReactorWithPowerAndCoolingCanActivate()
|
|
{
|
|
var level = LevelState.Create("Ready", 8, 6)
|
|
.SetCell(new(2, 2), new() {
|
|
Kind = ECellKind.Reactor,
|
|
Hazards = new() { Heat = 3 }
|
|
})
|
|
.SetCell(new(3, 2), new() {
|
|
Kind = ECellKind.Generator,
|
|
Powered = true
|
|
})
|
|
.SetCell(new(4, 2), new() {
|
|
Kind = ECellKind.CoolingPump,
|
|
Powered = true
|
|
});
|
|
|
|
var next = m_Engine.AdvanceTurn(level);
|
|
var activated = m_Engine.ActivateReactor(next);
|
|
|
|
Assert.Equal("REACTOR ONLINE", activated.Global.Status);
|
|
Assert.True(activated.Global.ReactorActivated);
|
|
}
|
|
|
|
[Fact]
|
|
public void LevelSerializationRoundTripsEditableState()
|
|
{
|
|
var level = LevelState.Create("Round trip", 5, 5);
|
|
level = LevelEditor.Apply(level, new(2, 2), EEditorTool.Reactor);
|
|
level = LevelEditor.Apply(level, new(1, 2), EEditorTool.CoolantPipe);
|
|
level = LevelEditor.Apply(level, new(1, 2), EEditorTool.Leak);
|
|
|
|
var json = LevelSerializer.Serialize(level);
|
|
var loaded = LevelSerializer.Deserialize(json);
|
|
|
|
Assert.Equal(level.Name, loaded.Name);
|
|
Assert.Equal(ECellKind.Reactor, loaded.GetCell(new(2, 2)).Kind);
|
|
Assert.Equal(EPipeMedium.Coolant, loaded.GetCell(new(1, 2)).Pipe);
|
|
Assert.Equal(1, loaded.GetCell(new(1, 2)).LeakRate);
|
|
}
|
|
|
|
private readonly SimulationEngine m_Engine = new();
|
|
|
|
private sealed class StepCountingHazard : Hazard
|
|
{
|
|
public override IEnumerable<Forecast> Predict(LevelState level, int turns)
|
|
{
|
|
yield return new(EFailureKind.PipeBurst, new(turns, 0), turns, $"STEP {turns}");
|
|
}
|
|
}
|
|
} |