namespace HSchool.Content.Tests; public class MapValidationTests { private readonly CatalogLoader _loader = new(); [Fact] public void ConnectedMap_WithAnEmptyRoom_IsValid() { var (catalog, map) = MiniSchool(fillOffice: false); MapValidator.Validate(map, catalog); Assert.Empty(map.Rooms.Single(room => room.Id == "office").Slots); Assert.Equal(["Principal"], catalog.PositionsFor(DefKind.Room, "Office")); } [Fact] public void AbstractDef_CannotBePlacedOnTheMap() { var catalog = _loader.Load( [CatalogLoader.CorePackId], MiniDefs(abstractYard: true)); var map = MiniMap(); var ex = Assert.Throws(() => MapValidator.Validate(map, catalog)); Assert.Contains("Abstract", ex.Message); } [Fact] public void UnknownDef_IsRejected() { var catalog = _loader.Load([CatalogLoader.CorePackId], MiniDefs()); var map = MiniMap(officeDef: "MissingOffice"); var ex = Assert.Throws(() => MapValidator.Validate(map, catalog)); Assert.Contains("Unknown", ex.Message); } [Fact] public void EdgeToNowhere_IsRejected() { var (catalog, map) = MiniSchool(extraLink: new MapLink { A = "office", B = "ghost" }); var ex = Assert.Throws(() => MapValidator.Validate(map, catalog)); Assert.Contains("unknown node", ex.Message); } [Fact] public void IsolatedNode_IsRejected() { var catalog = _loader.Load([CatalogLoader.CorePackId], MiniDefs()); var map = MiniMap(includeOfficeLink: false); var ex = Assert.Throws(() => MapValidator.Validate(map, catalog)); Assert.Contains("isolated", ex.Message, StringComparison.OrdinalIgnoreCase); } [Fact] public void DisconnectedGraph_IsRejected() { var catalog = _loader.Load([CatalogLoader.CorePackId], MiniDefs()); var map = new MapLayout { Territory = new TerritoryNode { Id = "yard", Def = "Yard" }, Buildings = [new BuildingNode { Id = "main", Def = "Main" }], Floors = [new FloorNode { Id = "floor-1", Def = "Floor", Building = "main" }], Rooms = [ new RoomNode { Id = "office", Def = "Office", Building = "main", Floor = "floor-1" }, new RoomNode { Id = "a", Def = "Office", Building = "main", Floor = "floor-1" }, new RoomNode { Id = "b", Def = "Office", Building = "main", Floor = "floor-1" }, ], Links = [ new MapLink { A = "yard", B = "office" }, new MapLink { A = "a", B = "b" }, ], }; var ex = Assert.Throws(() => MapValidator.Validate(map, catalog)); Assert.Contains("not connected", ex.Message); } [Fact] public void OneRoomWithoutAYard_IsRejected() { var catalog = _loader.Load([CatalogLoader.CorePackId], MiniDefs()); var map = new MapLayout { Buildings = [new BuildingNode { Id = "main", Def = "Main" }], Floors = [new FloorNode { Id = "floor-1", Def = "Floor", Building = "main" }], Rooms = [new RoomNode { Id = "office", Def = "Office", Building = "main", Floor = "floor-1" }], Links = [new MapLink { A = "office", B = "office" }], }; var ex = Assert.Throws(() => MapValidator.Validate(map, catalog)); Assert.Contains("no territory", ex.Message); } [Fact] public void MapWithNoRooms_IsRejected() { var catalog = _loader.Load([CatalogLoader.CorePackId], MiniDefs()); var map = new MapLayout { Territory = new TerritoryNode { Id = "yard", Def = "Yard" }, }; var ex = Assert.Throws(() => MapValidator.Validate(map, catalog)); Assert.Contains("at least one room", ex.Message); } private (DefCatalog Catalog, MapLayout Map) MiniSchool(bool fillOffice = true, MapLink? extraLink = null) { var catalog = _loader.Load([CatalogLoader.CorePackId], MiniDefs()); var map = MiniMap(fillOffice: fillOffice, extraLink: extraLink); return (catalog, map); } private static List MiniDefs(bool abstractYard = false) => [ PackDocuments.Def(CatalogLoader.CorePackId, "actions", "sit", """{ "defName": "Sit" }"""), PackDocuments.Def(CatalogLoader.CorePackId, "things", "chair", """{ "defName": "Chair", "actions": ["Sit"] }"""), PackDocuments.Def(CatalogLoader.CorePackId, "positions", "principal", """{ "defName": "Principal" }"""), PackDocuments.Def( CatalogLoader.CorePackId, "territories", "yard", abstractYard ? """{ "defName": "Yard", "abstract": true }""" : """{ "defName": "Yard" }"""), PackDocuments.Def(CatalogLoader.CorePackId, "buildings", "main", """{ "defName": "Main" }"""), PackDocuments.Def(CatalogLoader.CorePackId, "floors", "floor", """{ "defName": "Floor" }"""), PackDocuments.Def( CatalogLoader.CorePackId, "rooms", "office", """{ "defName": "Office", "slots": [{ "key": "seat", "thing": "Chair" }], "positions": ["Principal"] }"""), ]; private static MapLayout MiniMap( bool fillOffice = false, bool includeOfficeLink = true, string officeDef = "Office", MapLink? extraLink = null) { var links = new List(); if (includeOfficeLink) { links.Add(new MapLink { A = "yard", B = "office" }); } if (extraLink is not null) { links.Add(extraLink); } return new MapLayout { Territory = new TerritoryNode { Id = "yard", Def = "Yard" }, Buildings = [new BuildingNode { Id = "main", Def = "Main" }], Floors = [new FloorNode { Id = "floor-1", Def = "Floor", Building = "main" }], Rooms = [ new RoomNode { Id = "office", Def = officeDef, Building = "main", Floor = "floor-1", Slots = fillOffice ? [new SlotFill { Key = "seat", Thing = "Chair" }] : [], }, ], Links = links, }; } }