using System.IO; using System.Linq; using UnitTestSharp; using Vellum; namespace Annulus.Vellum.UnitTests { public class HexGridConverterTests : TestFixture { public const int Sentinel = -99; public static SaveSession Session() { return SaveConverters.For(typeof(HexGridConverterTests).Assembly).CreateSession(); } /// /// Builds a grid whose every cell holds its place in the order of the grid plus one. /// public static HexGrid Numbered(HexOrientation orientation, int rows, int columns) { var returnMe = new HexGrid(orientation, rows, columns, Sentinel); for (int i = 0; i < returnMe.Count; ++i) { returnMe[returnMe.IndexAt(i)] = i + 1; } return returnMe; } public static HexGrid Loaded(SaveNode node) { return (HexGrid)Session().FromNode(node, typeof(HexGrid)); } public static bool SameGrid(HexGrid expected, HexGrid actual) { if (expected.Orientation != actual.Orientation || expected.Rows != actual.Rows || expected.Columns != actual.Columns || expected.OutOfBounds != actual.OutOfBounds) { return false; } for (int i = 0; i < expected.Count; ++i) { HexIndex index = expected.IndexAt(i); if (expected[index] != actual[index]) { return false; } } return true; } public class WriteTests : TestFixture { public void SavesTheShapeAndWhatLiesOutside() { SaveNode node = Session().ToNode(Numbered(HexOrientation.FlatTop, 2, 3), typeof(HexGrid)); CheckEqual(SaveNode.Kinds.Table, node.Kind); CheckEqual("2", node.RequireEntry(HexGridConverter.RowsKey).Text); CheckEqual("3", node.RequireEntry(HexGridConverter.ColumnsKey).Text); CheckEqual("-99", node.RequireEntry(HexGridConverter.OutOfBoundsKey).Text); CheckEqual("FlatTop", node.RequireEntry(HexGridConverter.OrientationKey).Text); } public void SavesTheCellsInTheOrderOfTheGrid() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 2, 3), typeof(HexGrid)); CheckEqual(new[] { "1", "2", "3", "4", "5", "6" }, node.RequireEntry(HexGridConverter.CellsKey).Items.Select(item => item.Text).ToArray()); } public void AnEmptyGrid_SavesNoCells() { var grid = new HexGrid(HexOrientation.PointyTop, 0, 5, Sentinel); SaveNode node = Session().ToNode(grid, typeof(HexGrid)); CheckEqual(0, node.RequireEntry(HexGridConverter.CellsKey).Items.Count); } } public class ReadTests : TestFixture { public void EitherOrientation_RoundTrips() { foreach (HexOrientation orientation in new[] { HexOrientation.PointyTop, HexOrientation.FlatTop }) { HexGrid grid = Numbered(orientation, 3, 4); CheckTrue(SameGrid(grid, Loaded(Session().ToNode(grid, typeof(HexGrid))))); } } public void EachCellKeepsItsHex() { HexGrid grid = Numbered(HexOrientation.PointyTop, 3, 4); HexGrid loaded = Loaded(Session().ToNode(grid, typeof(HexGrid))); CheckEqual(grid[new HexIndex(2, 1)], loaded[new HexIndex(2, 1)]); CheckEqual(Sentinel, loaded[new HexIndex(-20, 0)]); } public void ThroughLuaText_RoundTrips() { HexGrid grid = Numbered(HexOrientation.FlatTop, 3, 2); SaveNode save = SaveNode.NewTable(); save.Entries["grid"] = Session().ToNode(grid, typeof(HexGrid)); SaveNode read = LuaSaveFormat.Parse(LuaSaveFormat.Format(save)); CheckTrue(SameGrid(grid, Loaded(read.RequireEntry("grid")))); } public void AnEmptyGrid_RoundTrips() { var grid = new HexGrid(HexOrientation.PointyTop, 4, 0, Sentinel); CheckTrue(SameGrid(grid, Loaded(Session().ToNode(grid, typeof(HexGrid))))); } public void ReferenceCells_RoundTripIncludingNull() { var grid = new HexGrid(HexOrientation.PointyTop, 1, 3, "outside"); grid[new HexIndex(0, 0)] = "a"; grid[new HexIndex(2, 0)] = "c"; SaveSession session = Session(); var loaded = (HexGrid)session.FromNode( session.ToNode(grid, typeof(HexGrid)), typeof(HexGrid)); CheckEqual("a", loaded[new HexIndex(0, 0)]); CheckNull(loaded[new HexIndex(1, 0)]); CheckEqual("c", loaded[new HexIndex(2, 0)]); CheckEqual("outside", loaded.OutOfBounds); } public void TooFewCells_Throws() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 2, 3), typeof(HexGrid)); node.RequireEntry(HexGridConverter.CellsKey).Items.RemoveAt(0); CheckThrow(typeof(InvalidDataException)); Loaded(node); } public void TooManyCells_Throws() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 2, 3), typeof(HexGrid)); node.RequireEntry(HexGridConverter.CellsKey).Items.Add(SaveNode.OfText("7")); CheckThrow(typeof(InvalidDataException)); Loaded(node); } public void NegativeRows_Throws() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 2, 3), typeof(HexGrid)); node.Entries[HexGridConverter.RowsKey] = SaveNode.OfText("-2"); node.Entries[HexGridConverter.ColumnsKey] = SaveNode.OfText("-3"); CheckThrow(typeof(InvalidDataException)); Loaded(node); } public void ADamagedHugeShape_Throws() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 2, 3), typeof(HexGrid)); node.Entries[HexGridConverter.RowsKey] = SaveNode.OfText("100000"); node.Entries[HexGridConverter.ColumnsKey] = SaveNode.OfText("100000"); CheckThrow(typeof(InvalidDataException)); Loaded(node); } public void MissingCells_Throws() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 2, 3), typeof(HexGrid)); node.Entries.Remove(HexGridConverter.CellsKey); CheckThrow(typeof(InvalidDataException)); Loaded(node); } public void ABadCell_LoadsAsDefaultAndIsRecordedAsAnIssue() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 2, 2), typeof(HexGrid)); node.RequireEntry(HexGridConverter.CellsKey).Items[1] = SaveNode.OfText("not a number"); SaveSession session = Session(); var loaded = (HexGrid)session.FromNode(node, typeof(HexGrid)); CheckEqual(1, loaded[loaded.IndexAt(0)]); CheckEqual(0, loaded[loaded.IndexAt(1)]); CheckEqual(3, loaded[loaded.IndexAt(2)]); CheckEqual(1, session.Sandbox.Issues.Count); } public void NodeThatIsNotATable_Throws() { CheckThrow(typeof(InvalidDataException)); Loaded(SaveNode.OfText("1")); } public void NullForAGrid_IsNull() { CheckNull(Session().FromNode(SaveNode.Null, typeof(HexGrid))); } } public class TryListChildrenTests : TestFixture { public void ListsTheOutOfBoundsValueThenEachCellAsTheCellType() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 1, 2), typeof(HexGrid)); var children = new ChildList(); CheckTrue(new HexGridConverter().TryListChildren(node, children)); CheckEqual(3, children.Count); CheckTrue(ReferenceEquals(node.RequireEntry(HexGridConverter.OutOfBoundsKey), children.NodeAt(0))); CheckTrue(ReferenceEquals(node.RequireEntry(HexGridConverter.CellsKey).Items[1], children.NodeAt(2))); CheckEqual(typeof(int), children.TypeAt(0)); CheckEqual(typeof(int), children.TypeAt(2)); } public void NodeWithoutCells_ReturnsFalse() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 1, 2), typeof(HexGrid)); node.Entries.Remove(HexGridConverter.CellsKey); CheckFalse(new HexGridConverter().TryListChildren(node, new ChildList())); } public void NodeWithoutOutOfBounds_ReturnsFalse() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 1, 2), typeof(HexGrid)); node.Entries.Remove(HexGridConverter.OutOfBoundsKey); CheckFalse(new HexGridConverter().TryListChildren(node, new ChildList())); } public void CellsThatAreNotAList_ReturnFalse() { SaveNode node = Session().ToNode(Numbered(HexOrientation.PointyTop, 1, 2), typeof(HexGrid)); node.Entries[HexGridConverter.CellsKey] = SaveNode.OfText("3"); CheckFalse(new HexGridConverter().TryListChildren(node, new ChildList())); } public void NodeThatIsNotATable_ReturnsFalse() { CheckFalse(new HexGridConverter().TryListChildren(SaveNode.OfText("3"), new ChildList())); } } } }