namespace HSchool.Simulation.Tests; public class SchoolRegistryTests { private static readonly DateTime Start = new(2012, 4, 3, 6, 0, 0, DateTimeKind.Utc); private static SchoolRegistry NewRegistry(int maxSchools = 6) => new(new SimulationOptions { MaxSchools = maxSchools, TickRate = 20, GameMinutesPerRealSecond = 5 }); [Fact] public void NewRegistry_IsEmpty() { using var registry = NewRegistry(); Assert.Equal(0, registry.Count); Assert.Equal(6, registry.MaxSchools); Assert.False(registry.IsFull); } [Fact] public void Create_AddsASchoolAtTheGivenStartDate() { using var registry = NewRegistry(); var result = registry.Create("Гимназия №1", Start); Assert.True(result.Succeeded); Assert.Equal("Гимназия №1", result.School!.Name); Assert.Equal(Start, result.School.Clock.Time); // A new school starts living straight away; only the pause button stops it. Assert.True(result.School.Clock.IsRunning); Assert.Equal(1, registry.Count); } [Fact] public void Create_BeyondTheLimit_Fails() { using var registry = NewRegistry(maxSchools: 2); registry.Create("Первая", Start); registry.Create("Вторая", Start); var result = registry.Create("Третья", Start); Assert.False(result.Succeeded); Assert.Equal(SchoolCreationError.LimitReached, result.Error); Assert.True(registry.IsFull); Assert.Equal(2, registry.Count); } [Fact] public void Delete_FreesASlot() { using var registry = NewRegistry(maxSchools: 1); var first = registry.Create("Первая", Start).School!; Assert.False(registry.Create("Вторая", Start).Succeeded); Assert.True(registry.Delete(first.Id)); Assert.True(registry.Create("Вторая", Start).Succeeded); } [Fact] public void Delete_UnknownId_ReportsFailure() { using var registry = NewRegistry(); Assert.False(registry.Delete(42)); } [Fact] public void Ids_AreNotReusedAfterDeletion() { using var registry = NewRegistry(); var first = registry.Create("Первая", Start).School!; registry.Delete(first.Id); var second = registry.Create("Вторая", Start).School!; Assert.NotEqual(first.Id, second.Id); Assert.Null(registry.Find(first.Id)); } [Theory] [InlineData("")] [InlineData(" ")] [InlineData("\t\n")] public void Create_RejectsBlankNames(string name) { using var registry = NewRegistry(); Assert.Equal(SchoolCreationError.InvalidName, registry.Create(name, Start).Error); } [Fact] public void Create_RejectsOverlongNames() { using var registry = NewRegistry(); var result = registry.Create(new string('ш', School.MaxNameLength + 1), Start); Assert.Equal(SchoolCreationError.InvalidName, result.Error); } [Fact] public void Create_TrimsAndStripsControlCharacters() { using var registry = NewRegistry(); var result = registry.Create(" Лицей ", Start); Assert.Equal("Лицей", result.School!.Name); } [Fact] public void Create_RejectsStartDatesOutsideTheSupportedRange() { using var registry = NewRegistry(); var result = registry.Create("Школа", new DateTime(1500, 1, 1, 0, 0, 0, DateTimeKind.Utc)); Assert.Equal(SchoolCreationError.InvalidStartDate, result.Error); } [Fact] public void Tick_AdvancesOnlyRunningSchools() { using var registry = NewRegistry(); var running = registry.Create("Идёт", Start).School!; var paused = registry.Create("Стоит", Start).School!; paused.Clock.IsRunning = false; for (var i = 0; i < 20; i++) { registry.Tick(); } Assert.Equal(Start.AddMinutes(5), running.Clock.Time); Assert.Equal(Start, paused.Clock.Time); } [Fact] public void SuggestName_NeverRepeatsAnExistingName() { using var registry = NewRegistry(maxSchools: 20); for (var i = 0; i < 20; i++) { var suggestion = registry.SuggestName(); Assert.True(registry.Create(suggestion, Start).Succeeded, $"\"{suggestion}\" was rejected."); } var names = registry.Schools.Select(school => school.Name).ToArray(); Assert.Equal(names.Length, names.Distinct(StringComparer.OrdinalIgnoreCase).Count()); } [Fact] public void SuggestedNames_FitTheNameLimit() { var generator = new SchoolNameGenerator(new Random(1234)); foreach (var language in new[] { SchoolNameLanguage.Russian, SchoolNameLanguage.English }) { for (var i = 0; i < 200; i++) { var name = generator.Next([], language); Assert.InRange(name.Length, 1, School.MaxNameLength); } } } [Fact] public void SuggestedEnglishNames_AreAscii() { var generator = new SchoolNameGenerator(new Random(1234)); for (var i = 0; i < 50; i++) { var name = generator.Next([], SchoolNameLanguage.English); Assert.Matches("^[A-Za-z0-9 .]+$", name); } } [Fact] public void Dispose_DropsEverySchool() { var registry = NewRegistry(); registry.Create("Школа", Start); registry.Dispose(); Assert.Equal(0, registry.Count); } }