using System.Collections.Generic; using Bogatyri.Settlement.Placement; using NUnit.Framework; // Тесты размещения зданий в 3D-поселении (ТЗ «Система строительства поселения» от 04.11.2026, раздел 11). // Запуск: Window -> General -> Test Runner -> EditMode -> Run All. public class PlacementTests { // Карта 20 x 20: всё открыто с Ратуши 1, кроме правой полосы (x >= 15 -- Ратуша 2); // река по x = 10, скала в (2, 18), дерево "tree_1" в (5, 5), холм справа вверху static SettlementMap Map() { var map = new SettlementMap(20, 20); for (int y = 0; y < 20; y++) for (int x = 0; x < 20; x++) { CellKind k = x == 10 ? CellKind.Water : x == 2 && y == 18 ? CellKind.Mountain : CellKind.Ground; int height = x >= 16 && y >= 16 ? (x - 16) * 500 : 0; // склон: 0,5 м на клетку map.SetCell(x, y, k, height, x >= 15 ? 2 : 1); } map.AddObstacle("tree_1", new[] { (5, 5) }); return map; } [Test] public void Placement_FlatGround_Ok_AndForbiddenPlaces() { var map = Map(); Assert.AreEqual(PlaceError.None, map.Place("hall", "Ратуша", 1, 1, 3, 3, 0, 1), "01: ровная земля"); Assert.AreEqual(PlaceError.Water, map.Validate(9, 2, 2, 2, 0, 1, null, out _), "02: река"); Assert.AreEqual(PlaceError.Mountain, map.Validate(1, 17, 2, 2, 0, 1, null, out _), "02: скала"); Assert.AreEqual(PlaceError.Obstacle, map.Validate(4, 4, 2, 2, 0, 1, null, out _), "дерево мешает"); Assert.AreEqual(PlaceError.OutOfMap, map.Validate(19, 19, 2, 2, 0, 1, null, out _), "за краем"); Assert.AreEqual(PlaceError.ZoneLocked, map.Validate(15, 2, 2, 2, 0, 1, null, out _), "зона Ратуши 2"); Assert.AreEqual(PlaceError.None, map.Validate(15, 2, 2, 2, 0, 2, null, out _), "11: Ратуша 2 открыла зону"); } [Test] public void Placement_GapBetweenBuildings() { var map = Map(); map.Place("a", "Дом", 1, 1, 2, 2, 0, 1); Assert.AreEqual(PlaceError.Occupied, map.Validate(2, 2, 2, 2, 0, 1, null, out _)); Assert.AreEqual(PlaceError.TooClose, map.Validate(3, 1, 2, 2, 0, 1, null, out _), "03: вплотную -- нарушен отступ"); Assert.AreEqual(PlaceError.None, map.Validate(4, 1, 2, 2, 0, 1, null, out _), "через клетку -- можно"); } [Test] public void Placement_Rotation_SwapsFootprint() { var map = Map(); // 4 x 1 у реки: повёрнутое на 90 -- 1 x 4 -- помещается вдоль реки, без поворота -- упирается в неё Assert.AreEqual(PlaceError.Water, map.Validate(7, 12, 4, 1, 0, 1, null, out _)); foreach (int rot in new[] { 90, 270 }) Assert.AreEqual(PlaceError.None, map.Validate(9, 12, 4, 1, rot, 1, null, out _), "04: поворот " + rot); Assert.AreEqual(PlaceError.Water, map.Validate(7, 12, 4, 1, 180, 1, null, out _), "04: 180 -- как 0"); map.Place("long", "Склад", 9, 12, 4, 1, 90, 1); Assert.IsTrue(map.TryGetBuilding("long", out var b)); Assert.AreEqual(1, b.W); Assert.AreEqual(4, b.H); Assert.AreEqual("long", map.BuildingAt(9, 15)); Assert.IsNull(map.BuildingAt(10, 12)); } [Test] public void Placement_Slope_FoundationOrTooSteep() { var map = Map(); Assert.AreEqual(PlaceError.None, map.Validate(16, 16, 2, 2, 0, 2, null, out int f), "небольшой перепад"); Assert.AreEqual(500, f, "фундамент 0,5 м"); Assert.AreEqual(PlaceError.TooSteep, map.Validate(16, 16, 3, 2, 0, 2, null, out _), "1 м -- слишком круто"); } [Test] public void Placement_Move_IsAtomic_KeepsId() { var map = Map(); map.Place("farm", "Ферма", 1, 1, 3, 3, 0, 1); map.Place("mine", "Шахта", 12, 1, 2, 2, 0, 1); Assert.AreEqual(PlaceError.None, map.Move("farm", 2, 1, 0, 1), "свой прежний след не мешает"); Assert.IsTrue(map.TryGetBuilding("farm", out var moved)); Assert.AreEqual(2, moved.X); Assert.AreEqual(PlaceError.Water, map.Move("farm", 8, 1, 0, 1), "09: ошибка -- здание на месте"); map.TryGetBuilding("farm", out var same); Assert.AreEqual(2, same.X); Assert.AreEqual(2, map.Buildings.Count, "без дублей"); Assert.AreEqual(PlaceError.None, map.Move("mine", 12, 6, 90, 1), "05: шахту можно переносить и поворачивать"); Assert.AreEqual(PlaceError.OutOfMap, map.Move("nope", 1, 1, 0, 1)); } [Test] public void Placement_ClearObstacle_OnceOnly_SurvivesReload() { var map = Map(); Assert.IsTrue(map.ClearObstacle("tree_1"), "10: расчищено -- одна награда"); Assert.IsFalse(map.ClearObstacle("tree_1"), "второй раз -- без награды"); Assert.IsNull(map.ObstacleAt(5, 5)); Assert.AreEqual(PlaceError.None, map.Validate(4, 4, 2, 2, 0, 1, null, out _)); // Загрузка: расчищенное не возвращается, даже если отмечено раньше, чем объект добавлен на карту var copy = new SettlementMap(20, 20); for (int y = 0; y < 20; y++) for (int x = 0; x < 20; x++) copy.SetCell(x, y, CellKind.Ground, 0, 1); copy.RestoreCleared(new List(map.Cleared)); copy.AddObstacle("tree_1", new[] { (5, 5) }); Assert.IsNull(copy.ObstacleAt(5, 5)); Assert.IsFalse(copy.ClearObstacle("tree_1")); } [Test] public void Placement_Restore_NoOverlaps() { var map = Map(); Assert.IsTrue(map.Restore(new PlacedRect { Id = "a", Type = "Дом", X = 1, Y = 1, SizeW = 2, SizeH = 2, Rotation = 0 })); Assert.IsFalse(map.Restore(new PlacedRect { Id = "b", Type = "Дом", X = 2, Y = 2, SizeW = 2, SizeH = 2, Rotation = 0 }), "12: наложение не восстанавливается"); Assert.IsFalse(map.Restore(new PlacedRect { Id = "a", Type = "Дом", X = 6, Y = 6, SizeW = 2, SizeH = 2, Rotation = 0 }), "тот же id -- не дубль"); Assert.AreEqual(270, SettlementMap.NormalizeRotation(-90)); } }