Merge phase 29 country.
ci / server (push) Failing after 3m53s
ci / client (push) Successful in 19s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-20 02:59:46 +03:00
co-authored by Cursor
59 changed files with 903 additions and 478 deletions
+88 -13
View File
@@ -278,13 +278,14 @@ public class SchoolApiTests(AppHostFixture fixture)
Assert.Equal("Кабинет директора", Assert.Single(ru.Rooms, room => room.DefName == "PrincipalsOffice").Label);
Assert.Equal("Principal's office", Assert.Single(en.Rooms, room => room.DefName == "PrincipalsOffice").Label);
Assert.Equal("yard", ru.DefaultMap.Territory?.Id);
Assert.Equal("Славянский", Assert.Single(ru.NameSets, set => set.DefName == "Slavic").Label);
Assert.Equal("Slavic", Assert.Single(en.NameSets, set => set.DefName == "Slavic").Label);
var slavic = Assert.Single(ru.NameSets, set => set.DefName == "Slavic");
Assert.Equal("Россия", Assert.Single(ru.Countries, country => country.DefName == "Russia").Label);
Assert.Equal("Russia", Assert.Single(en.Countries, country => country.DefName == "Russia").Label);
var russia = Assert.Single(ru.Countries, country => country.DefName == "Russia");
Assert.Equal(
["RussianLanguage", "BelarusianLanguage", "UkrainianLanguage"],
slavic.NativeLanguages.Select(language => language.DefName).ToArray());
Assert.Equal("Белорусский", Assert.Single(slavic.NativeLanguages, language => language.DefName == "BelarusianLanguage").Label);
russia.NativeLanguages.Select(language => language.DefName).ToArray());
Assert.Equal("Белорусский", Assert.Single(russia.NativeLanguages, language => language.DefName == "BelarusianLanguage").Label);
Assert.Equal(["TemperateContinental", "ContinentalCold"], russia.ClimatePresets);
Assert.Equal("Начальные классы", Assert.Single(ru.Subjects, subject => subject.DefName == "PrimarySchool").Label);
Assert.Equal("Primary", Assert.Single(en.Subjects, subject => subject.DefName == "PrimarySchool").Label);
var classroom = Assert.Single(ru.Rooms, room => room.DefName == "Classroom");
@@ -396,7 +397,7 @@ public class SchoolApiTests(AppHostFixture fixture)
}
[Fact]
public async Task CreateSchool_WithAnUnknownNameSet_IsRejected()
public async Task CreateSchool_WithAnUnknownCountry_IsRejected()
{
using var client = fixture.App.CreateHttpClient("server");
await ResetAsync(client);
@@ -405,14 +406,47 @@ public class SchoolApiTests(AppHostFixture fixture)
"/api/schools",
new
{
name = "Чужие имена",
name = "Чужая страна",
startDate = ExpectedDefaultStart,
nameSetId = "NoSuchNames",
countryId = "NoSuchCountry",
},
TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
Assert.Equal("unknown-name-set", await ProblemCodeAsync(response));
Assert.Equal("unknown-country", await ProblemCodeAsync(response));
}
[Fact]
public async Task CreateSchool_WithRussiaAndNoLanguage_PicksTheSameNativeAsTheSeed()
{
using var client = fixture.App.CreateHttpClient("server");
await ResetAsync(client);
const int seed = 42;
var first = await CreateWithCountryAsync(client, "Страна А", ExpectedDefaultStart, "Russia", seed);
var second = await CreateWithCountryAsync(client, "Страна Б", ExpectedDefaultStart, "Russia", seed);
var firstSave = await ReadSchoolSaveAsync(client, first.Id);
var secondSave = await ReadSchoolSaveAsync(client, second.Id);
Assert.Equal("Russia", firstSave.CountryId);
Assert.Equal(firstSave.NativeLanguage, secondSave.NativeLanguage);
Assert.Contains(firstSave.NativeLanguage, new[] { "RussianLanguage", "BelarusianLanguage", "UkrainianLanguage" });
}
[Fact]
public async Task CreateSchool_WithTheSameSeed_GetsTheSameClimatePreset()
{
using var client = fixture.App.CreateHttpClient("server");
await ResetAsync(client);
const int seed = 20260818;
var first = await CreateWithCountryAsync(client, "Климат А", ExpectedDefaultStart, "Russia", seed);
var second = await CreateWithCountryAsync(client, "Климат Б", ExpectedDefaultStart, "Russia", seed);
var firstSave = await ReadSchoolSaveAsync(client, first.Id);
var secondSave = await ReadSchoolSaveAsync(client, second.Id);
Assert.Equal(firstSave.ClimatePresetId, secondSave.ClimatePresetId);
Assert.Contains(firstSave.ClimatePresetId, new[] { "TemperateContinental", "ContinentalCold" });
}
[Fact]
@@ -427,7 +461,7 @@ public class SchoolApiTests(AppHostFixture fixture)
{
name = "Чужой язык",
startDate = ExpectedDefaultStart,
nameSetId = "Slavic",
countryId = "Russia",
nativeLanguage = "Klingon",
},
TestContext.Current.CancellationToken);
@@ -521,6 +555,46 @@ public class SchoolApiTests(AppHostFixture fixture)
return created;
}
private static async Task<SchoolResponse> CreateWithCountryAsync(
HttpClient client,
string name,
DateTime startDate,
string countryId,
int seed)
{
using var response = await client.PostAsJsonAsync(
"/api/schools",
new { name, startDate, countryId, seed },
TestContext.Current.CancellationToken);
response.EnsureSuccessStatusCode();
var created = await response.Content.ReadFromJsonAsync<SchoolResponse>(TestContext.Current.CancellationToken);
Assert.NotNull(created);
return created;
}
private static async Task<SchoolSaveFile> ReadSchoolSaveAsync(HttpClient client, int id)
{
var directory = await SavesDirectoryAsync(client);
var json = await File.ReadAllTextAsync(Path.Combine(directory, $"{id}.json"), TestContext.Current.CancellationToken);
var save = System.Text.Json.JsonSerializer.Deserialize<SchoolSaveFile>(
json,
new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(save);
return save;
}
private static async Task<string> SavesDirectoryAsync(HttpClient client)
{
var payload = await client.GetFromJsonAsync<PathResponse>(
"/api/dev/saves-directory",
TestContext.Current.CancellationToken);
Assert.NotNull(payload);
Assert.False(string.IsNullOrWhiteSpace(payload.Path));
return payload.Path;
}
private sealed record SchoolSaveFile(string? CountryId, string? ClimatePresetId, string? NativeLanguage);
internal static readonly object SimpleCustomMap = new
{
territory = new { id = "yard", def = "SchoolYard" },
@@ -626,7 +700,7 @@ public class SchoolApiTests(AppHostFixture fixture)
IReadOnlyList<DefInfoResponse> Floors,
IReadOnlyList<RoomInfoResponse> Rooms,
IReadOnlyList<DefInfoResponse> Things,
IReadOnlyList<NameSetInfoResponse> NameSets,
IReadOnlyList<CountryInfoResponse> Countries,
IReadOnlyList<SubjectInfoResponse> Subjects,
DayFrameResponse? DayFrame,
IReadOnlyList<HolidayInfoResponse> Holidays,
@@ -634,10 +708,11 @@ public class SchoolApiTests(AppHostFixture fixture)
private sealed record DefInfoResponse(string DefName, string Label);
private sealed record NameSetInfoResponse(
private sealed record CountryInfoResponse(
string DefName,
string Label,
IReadOnlyList<DefInfoResponse> NativeLanguages);
IReadOnlyList<DefInfoResponse> NativeLanguages,
IReadOnlyList<string> ClimatePresets);
private sealed record RoomInfoResponse(
string DefName,