102 lines
3.9 KiB
C#
102 lines
3.9 KiB
C#
using TheLivingWorld.Core.Simulation;
|
|
|
|
namespace TheLivingWorld.Tests;
|
|
|
|
public sealed class ClimateTests
|
|
{
|
|
[Theory]
|
|
[InlineData(1.35, ClimateKind.Equatorial)] // Singapore
|
|
[InlineData(13.75, ClimateKind.Savanna)] // Bangkok
|
|
[InlineData(30.05, ClimateKind.HotDesert)] // Cairo
|
|
[InlineData(37.98, ClimateKind.Mediterranean)] // Athens
|
|
[InlineData(51.51, ClimateKind.Oceanic)] // London
|
|
[InlineData(55.75, ClimateKind.CentralEuropean)] // Moscow
|
|
[InlineData(62.03, ClimateKind.Siberian)] // Yakutsk
|
|
[InlineData(78.22, ClimateKind.Tundra)] // Svalbard
|
|
public void FromLatitude_lands_on_the_expected_band(double latitude, ClimateKind expected)
|
|
{
|
|
Assert.Equal(expected, ClimateCatalog.FromLatitude(latitude));
|
|
}
|
|
|
|
[Fact]
|
|
public void FromLatitude_ignores_the_hemisphere()
|
|
{
|
|
for (var degrees = 0.0; degrees <= 90.0; degrees += 0.5)
|
|
Assert.Equal(ClimateCatalog.FromLatitude(degrees), ClimateCatalog.FromLatitude(-degrees));
|
|
}
|
|
|
|
[Fact]
|
|
public void FromLatitude_is_monotonic_from_the_equator_to_the_pole()
|
|
{
|
|
// The bands must not interleave: walking north should never hand back a warmer preset than the last.
|
|
var previous = -1;
|
|
|
|
for (var degrees = 0.0; degrees <= 90.0; degrees += 0.25)
|
|
{
|
|
var index = ClimateCatalog.All
|
|
.Select(static (preset, i) => (preset.Kind, Index: i))
|
|
.First(entry => entry.Kind == ClimateCatalog.FromLatitude(degrees))
|
|
.Index;
|
|
|
|
Assert.True(index >= previous, $"Latitude {degrees} stepped backwards in the catalogue order.");
|
|
previous = index;
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Every_preset_is_reachable_and_self_consistent()
|
|
{
|
|
Assert.Equal(12, ClimateCatalog.All.Count);
|
|
|
|
foreach (var kind in Enum.GetValues<ClimateKind>())
|
|
{
|
|
var preset = ClimateCatalog.Get(kind);
|
|
Assert.Equal(kind, preset.Kind);
|
|
Assert.False(string.IsNullOrWhiteSpace(preset.Label));
|
|
Assert.False(string.IsNullOrWhiteSpace(preset.KoppenCode));
|
|
Assert.False(string.IsNullOrWhiteSpace(preset.Example));
|
|
Assert.InRange(preset.Humidity, 0f, 1f);
|
|
Assert.InRange(preset.Wetness, 0f, 1f);
|
|
Assert.InRange(preset.Storminess, 1, WeatherSystem.MaxSystems);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Presets_the_latitude_rule_cannot_reach_are_reported_as_such()
|
|
{
|
|
var reachable = Enumerable.Range(0, 91)
|
|
.Select(static degrees => ClimateCatalog.FromLatitude(degrees))
|
|
.ToHashSet();
|
|
|
|
foreach (var preset in ClimateCatalog.All)
|
|
Assert.Equal(reachable.Contains(preset.Kind), ClimateCatalog.IsInferable(preset.Kind));
|
|
}
|
|
|
|
[Fact]
|
|
public void Band_limits_are_ordered_and_reproduce_the_latitude_rule()
|
|
{
|
|
// The create form re-derives FromLatitude on the client from exactly these limits, walking the list
|
|
// in order, so they have to be ascending and they have to agree at every latitude.
|
|
var banded = ClimateCatalog.All
|
|
.Select(static preset => (preset.Kind, Limit: ClimateCatalog.BandLimit(preset.Kind)))
|
|
.Where(static entry => entry.Limit is not null)
|
|
.Select(static entry => (entry.Kind, Limit: entry.Limit!.Value))
|
|
.ToArray();
|
|
|
|
Assert.NotEmpty(banded);
|
|
Assert.Equal(banded.OrderBy(static entry => entry.Limit).ToArray(), banded);
|
|
|
|
for (var degrees = 0.0; degrees <= 90.0; degrees += 0.25)
|
|
{
|
|
var expected = banded.FirstOrDefault(entry => degrees < entry.Limit, banded[^1]).Kind;
|
|
Assert.Equal(expected, ClimateCatalog.FromLatitude(degrees));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Get_rejects_an_undefined_climate()
|
|
{
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => ClimateCatalog.Get((ClimateKind)99));
|
|
}
|
|
}
|